mirror of
https://github.com/ihhub/fheroes2.git
synced 2026-10-12 02:16:11 +00:00
Improve video processing logic (#10059)
This commit is contained in:
@@ -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
@@ -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, ¤tFrame, nullptr, nullptr );
|
||||
|
||||
if ( const signed char returnValue = smk_info_all( _videoFile.get(), ¤tFrame, 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
@@ -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 };
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user