Improve video processing logic (#10059)

This commit is contained in:
Ihar Hubchyk
2025-08-03 10:54:16 +08:00
committed by GitHub
parent 38bc09a78a
commit 6aab11ff18
5 changed files with 121 additions and 88 deletions
+15
View File
@@ -11,3 +11,18 @@ rules:
actions:
review_status: false_positive
reason: "cetintrin.h:62:10: 1st function call argument is an uninitialized value"
- filters:
report_hash: d071c5bf5e4d9f23cb32232823dc5f20
actions:
review_status: false_positive
reason: "https://github.com/llvm/llvm-project/issues/47814 https://godbolt.org/z/onxhTsqWa"
- filters:
report_hash: f699c93e80136a0ef2a7837c8b01aee6
actions:
review_status: false_positive
reason: "https://github.com/llvm/llvm-project/issues/47814 https://godbolt.org/z/onxhTsqWa"
- filters:
report_hash: 8f5f809c6c4c2746197c7d9434f936a0
actions:
review_status: false_positive
reason: "https://github.com/llvm/llvm-project/issues/47814 https://godbolt.org/z/onxhTsqWa"
+64 -69
View File
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2020 - 2024 *
* Copyright (C) 2020 - 2025 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -26,12 +26,12 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <memory>
#include <ostream>
#include "exception.h"
#include "image.h"
#include "logging.h"
#include "serialize.h"
#include "smacker.h"
namespace
{
@@ -62,21 +62,13 @@ namespace
}
SMKVideoSequence::SMKVideoSequence( const std::string & filePath )
: _width( 0 )
, _height( 0 )
, _heightScaleFactor( 1 )
, _fps( 0 )
, _frameCount( 0 )
, _currentFrameId( 0 )
, _videoFile( nullptr )
{
verifyVideoFile( filePath );
_videoFile = smk_open_file( filePath.c_str(), SMK_MODE_MEMORY );
if ( _videoFile == nullptr )
_videoFile.reset( smk_open_file( filePath.c_str(), SMK_MODE_MEMORY ) );
if ( !_videoFile ) {
return;
double usf = 0;
}
const uint8_t audioChannelCount = 7;
@@ -90,8 +82,13 @@ SMKVideoSequence::SMKVideoSequence( const std::string & filePath )
unsigned long height = 0;
unsigned char scaledYMode = 1;
smk_info_all( _videoFile, nullptr, &_frameCount, &usf );
smk_info_video( _videoFile, &width, &height, &scaledYMode );
if ( const signed char returnValue = smk_info_all( _videoFile.get(), nullptr, &_frameCount, &_microsecondsPerFrame ); returnValue < 0 ) {
ERROR_LOG( "smk_info_all() failed with error code: " << static_cast<int>( returnValue ) )
}
if ( const signed char returnValue = smk_info_video( _videoFile.get(), &width, &height, &scaledYMode ); returnValue < 0 ) {
ERROR_LOG( "smk_info_video() failed with error code: " << static_cast<int>( returnValue ) )
}
_heightScaleFactor = scaledYMode;
@@ -107,27 +104,41 @@ SMKVideoSequence::SMKVideoSequence( const std::string & filePath )
_width = static_cast<int32_t>( width );
_height = static_cast<int32_t>( height ) * _heightScaleFactor;
smk_info_audio( _videoFile, &trackMask, channelsPerTrack, audioBitDepth, audioRate );
if ( const signed char returnValue = smk_info_audio( _videoFile.get(), &trackMask, channelsPerTrack, audioBitDepth, audioRate ); returnValue < 0 ) {
ERROR_LOG( "smk_info_audio() failed with error code: " << static_cast<int>( returnValue ) )
}
if ( usf > 0 )
_fps = 1000000.0 / usf;
else
_fps = 15; // let's use as a default
if ( _microsecondsPerFrame < 1 ) {
// Since the value is not set let's set a default value for 15 FPS.
_microsecondsPerFrame = 1000000.0 / 15.0;
}
for ( uint8_t i = 0; i < audioChannelCount; ++i ) {
if ( trackMask & ( 1 << i ) ) {
smk_enable_audio( _videoFile, i, 1 );
if ( const signed char returnValue = smk_enable_audio( _videoFile.get(), i, 1 ); returnValue < 0 ) {
ERROR_LOG( "smk_enable_audio() failed with error code: " << static_cast<int>( returnValue ) )
}
}
}
smk_enable_video( _videoFile, 0 ); // disable video reading
smk_first( _videoFile );
// Disable video reading.
if ( const signed char returnValue = smk_enable_video( _videoFile.get(), 0 ); returnValue < 0 ) {
ERROR_LOG( "smk_enable_video() failed with error code: " << static_cast<int>( returnValue ) )
}
if ( const signed char returnValue = smk_first( _videoFile.get() ); returnValue < 0 ) {
ERROR_LOG( "smk_first() failed with error code: " << static_cast<int>( returnValue ) )
}
unsigned long currentFrame = 0;
smk_info_all( _videoFile, &currentFrame, nullptr, nullptr );
if ( const signed char returnValue = smk_info_all( _videoFile.get(), &currentFrame, nullptr, nullptr ); returnValue < 0 ) {
ERROR_LOG( "smk_info_all() failed with error code: " << static_cast<int>( returnValue ) )
}
for ( uint8_t i = 0; i < audioChannelCount; ++i ) {
if ( trackMask & ( 1 << i ) ) {
const unsigned long length = smk_get_audio_size( _videoFile, i );
const unsigned long length = smk_get_audio_size( _videoFile.get(), i );
if ( length == 0 ) {
continue;
}
@@ -136,17 +147,19 @@ SMKVideoSequence::SMKVideoSequence( const std::string & filePath )
soundBuffer[i].resize( audioHeaderSize );
}
const uint8_t * data = smk_get_audio( _videoFile, i );
const uint8_t * data = smk_get_audio( _videoFile.get(), i );
soundBuffer[i].insert( soundBuffer[i].end(), data, data + length );
}
}
for ( currentFrame = 1; currentFrame < _frameCount; ++currentFrame ) {
smk_next( _videoFile );
if ( const signed char returnValue = smk_next( _videoFile.get() ); returnValue < 0 ) {
ERROR_LOG( "smk_next() failed with error code: " << static_cast<int>( returnValue ) )
}
for ( uint8_t i = 0; i < audioChannelCount; ++i ) {
if ( trackMask & ( 1 << i ) ) {
const unsigned long length = smk_get_audio_size( _videoFile, i );
const unsigned long length = smk_get_audio_size( _videoFile.get(), i );
if ( length == 0 ) {
continue;
}
@@ -155,7 +168,7 @@ SMKVideoSequence::SMKVideoSequence( const std::string & filePath )
soundBuffer[i].resize( audioHeaderSize );
}
const uint8_t * data = smk_get_audio( _videoFile, i );
const uint8_t * data = smk_get_audio( _videoFile.get(), i );
soundBuffer[i].insert( soundBuffer[i].end(), data, data + length );
}
}
@@ -200,56 +213,39 @@ SMKVideoSequence::SMKVideoSequence( const std::string & filePath )
}
}
smk_enable_video( _videoFile, 1 ); // enable video reading
smk_first( _videoFile );
}
SMKVideoSequence::~SMKVideoSequence()
{
if ( _videoFile != nullptr ) {
smk_close( _videoFile );
// Enable video reading.
if ( const signed char returnValue = smk_enable_video( _videoFile.get(), 1 ); returnValue < 0 ) {
ERROR_LOG( "smk_enable_video() failed with error code: " << static_cast<int>( returnValue ) )
}
}
int32_t SMKVideoSequence::width() const
{
return _width;
}
int32_t SMKVideoSequence::height() const
{
return _height;
}
double SMKVideoSequence::fps() const
{
return _fps;
}
unsigned long SMKVideoSequence::frameCount() const
{
return _frameCount;
if ( const signed char returnValue = smk_first( _videoFile.get() ); returnValue < 0 ) {
ERROR_LOG( "smk_first() failed with error code: " << static_cast<int>( returnValue ) )
}
}
void SMKVideoSequence::resetFrame()
{
if ( _videoFile == nullptr )
if ( !_videoFile ) {
return;
}
if ( const signed char returnValue = smk_first( _videoFile.get() ); returnValue < 0 ) {
ERROR_LOG( "smk_first() failed with error code: " << static_cast<int>( returnValue ) )
}
smk_first( _videoFile );
_currentFrameId = 0;
}
void SMKVideoSequence::getNextFrame( fheroes2::Image & image, const int32_t x, const int32_t y, int32_t & width, int32_t & height, std::vector<uint8_t> & palette )
{
if ( _videoFile == nullptr || image.empty() || x < 0 || y < 0 || x >= image.width() || y >= image.height() || !image.singleLayer() ) {
if ( !_videoFile || image.empty() || x < 0 || y < 0 || x >= image.width() || y >= image.height() || !image.singleLayer() ) {
width = 0;
height = 0;
return;
}
const uint8_t * data = smk_get_video( _videoFile );
const uint8_t * paletteData = smk_get_palette( _videoFile );
const uint8_t * data = smk_get_video( _videoFile.get() );
const uint8_t * paletteData = smk_get_palette( _videoFile.get() );
width = _width;
height = _height;
@@ -308,19 +304,18 @@ void SMKVideoSequence::getNextFrame( fheroes2::Image & image, const int32_t x, c
++_currentFrameId;
if ( _currentFrameId < _frameCount ) {
smk_next( _videoFile );
if ( const signed char returnValue = smk_next( _videoFile.get() ); returnValue < 0 ) {
ERROR_LOG( "smk_next() failed with error code: " << static_cast<int>( returnValue ) )
}
}
}
std::vector<uint8_t> SMKVideoSequence::getCurrentPalette() const
{
const uint8_t * paletteData = smk_get_palette( _videoFile );
assert( _videoFile );
const uint8_t * paletteData = smk_get_palette( _videoFile.get() );
assert( paletteData != nullptr );
return std::vector<uint8_t>( paletteData, paletteData + 256 * 3 );
}
const std::vector<std::vector<uint8_t>> & SMKVideoSequence::getAudioChannels() const
{
return _audioChannel;
}
+36 -15
View File
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2020 - 2023 *
* Copyright (C) 2020 - 2025 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -21,19 +21,22 @@
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "smacker.h"
namespace fheroes2
{
class Image;
}
class SMKVideoSequence
class SMKVideoSequence final
{
public:
explicit SMKVideoSequence( const std::string & filePath );
~SMKVideoSequence();
~SMKVideoSequence() = default;
SMKVideoSequence( const SMKVideoSequence & ) = delete;
SMKVideoSequence & operator=( const SMKVideoSequence & ) = delete;
@@ -46,12 +49,30 @@ public:
std::vector<uint8_t> getCurrentPalette() const;
const std::vector<std::vector<uint8_t>> & getAudioChannels() const;
const std::vector<std::vector<uint8_t>> & getAudioChannels() const
{
return _audioChannel;
}
int32_t width() const;
int32_t height() const;
double fps() const;
unsigned long frameCount() const;
int32_t width() const
{
return _width;
}
int32_t height() const
{
return _height;
}
double microsecondsPerFrame() const
{
return _microsecondsPerFrame;
}
unsigned long frameCount() const
{
return _frameCount;
}
unsigned long getCurrentFrame() const
{
@@ -60,12 +81,12 @@ public:
private:
std::vector<std::vector<uint8_t>> _audioChannel;
int32_t _width;
int32_t _height;
int32_t _heightScaleFactor;
double _fps;
unsigned long _frameCount;
unsigned long _currentFrameId;
int32_t _width{ 0 };
int32_t _height{ 0 };
int32_t _heightScaleFactor{ 1 };
double _microsecondsPerFrame{ 0 };
unsigned long _frameCount{ 0 };
unsigned long _currentFrameId{ 0 };
struct smk_t * _videoFile;
std::unique_ptr<struct smk_t, void ( * )( struct smk_t * )> _videoFile{ nullptr, smk_close };
};
+2 -2
View File
@@ -208,7 +208,7 @@ fheroes2::GameMode Game::NewSuccessionWarsCampaign()
const std::array<fheroes2::Rect, 2> campaignRoi{ fheroes2::Rect( 382 + roiOffset.x, 58 + roiOffset.y, 222, 298 ),
fheroes2::Rect( 30 + roiOffset.x, 59 + roiOffset.y, 224, 297 ) };
const uint64_t customDelay = static_cast<uint64_t>( std::lround( 1000.0 / video->fps() ) );
const uint64_t customDelay = static_cast<uint64_t>( std::lround( video->microsecondsPerFrame() / 1000 ) );
outputNewSuccessionWarsCampaignInTextSupportMode();
@@ -368,7 +368,7 @@ fheroes2::GameMode Game::NewPriceOfLoyaltyCampaign()
for ( size_t i = 0; i < activeCampaignArea.size(); ++i ) {
if ( le.isMouseCursorPosInArea( activeCampaignArea[i] ) && videos[i] ) {
highlightCampaignId = i;
customDelay = static_cast<uint64_t>( std::lround( 1000.0 / videos[highlightCampaignId]->fps() ) );
customDelay = static_cast<uint64_t>( std::lround( videos[highlightCampaignId]->microsecondsPerFrame() / 1000 ) );
break;
}
}
+4 -2
View File
@@ -1,6 +1,6 @@
/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2020 - 2024 *
* Copyright (C) 2020 - 2025 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -23,6 +23,7 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <ostream>
@@ -131,7 +132,8 @@ namespace Video
uint32_t currentFrame = 0;
fheroes2::Rect frameRoi( ( display.width() - video.width() ) / 2, ( display.height() - video.height() ) / 2, 0, 0 );
const uint32_t delay = static_cast<uint32_t>( 1000.0 / video.fps() + 0.5 ); // This might be not very accurate but it's the best we can have now
// This might be not very accurate but it's the best we can have now.
const uint32_t delay = static_cast<uint32_t>( std::lround( video.microsecondsPerFrame() / 1000 ) );
std::vector<uint8_t> palette;
std::vector<uint8_t> prevPalette;