@@ -84,13 +84,14 @@ namespace core {
8484
8585 close ();
8686
87- if (!loadVideoFile (path)) return false ;
88- if (!configureHardwareAcceleration ()) return false ;
89- if (!selectVideoStream (options.video_stream_index )) return false ;
90- if (!negotiateOutputFormat (options)) return false ;
91- if (!extractVideoProperties ()) return false ;
92- if (!createResources ()) return false ;
93- if (!loadFirstFrame ()) return false ;
87+ SmartReference<IData> file_data;
88+ if (!FileSystemManager::readFile (path, file_data.put ())) {
89+ Logger::error (" [core] [VideoDecoder] Failed to read video file: {}" , path);
90+ return false ;
91+ }
92+
93+ if (!createStreamFromMemory (file_data->data (), file_data->size ())) return false ;
94+ if (!openFromStream (options)) return false ;
9495
9596 m_last_open_path.assign (path.data (), path.size ());
9697 m_last_open_options = options;
@@ -105,74 +106,105 @@ namespace core {
105106
106107 return true ;
107108 }
109+
110+ bool VideoDecoder::openFromMemory (void const * data, size_t size, VideoOpenOptions const & options, StringView source_name) {
111+ if (!m_initialized) {
112+ Logger::error (" [core] [VideoDecoder] Not initialized" );
113+ return false ;
114+ }
115+
116+ close ();
117+
118+ if (!createStreamFromMemory (data, size)) return false ;
119+ if (!openFromStream (options)) return false ;
120+
121+ m_last_open_path.assign (source_name.data (), source_name.size ());
122+ m_last_open_options = options;
123+
124+ setLooping (options.looping );
125+ if (options.loop_duration > 0.0 ) {
126+ setLoopRange (options.loop_end , options.loop_duration );
127+ }
128+
129+ Logger::info (" [core] [VideoDecoder] Opened video from memory: {}x{}, duration: {:.2f}s" ,
130+ m_target_size.x , m_target_size.y , m_duration);
131+
132+ return true ;
133+ }
108134
109135 void VideoDecoder::getVideoStreams (void (*callback)(VideoStreamInfo const &, void *), void* userdata) const {
110- if (!m_source_reader || ! callback) return ;
136+ if (!callback) return ;
111137
112- wil::unique_prop_variant var;
113- double duration_sec = 0.0 ;
114- if (SUCCEEDED (m_source_reader->GetPresentationAttribute ((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var))) {
115- duration_sec = var.hVal .QuadPart / 10000000.0 ;
116- }
117-
118- for (DWORD si = 0 ; si < Config::kMaxStreams ; ++si) {
119- win32::com_ptr<IMFMediaType> mt;
120- if (FAILED (m_source_reader->GetNativeMediaType (si, 0 , mt.put ()))) continue ;
121-
122- GUID major = GUID_NULL;
123- if (FAILED (mt->GetGUID (MF_MT_MAJOR_TYPE, &major)) || major != MFMediaType_Video) continue ;
124-
125- VideoStreamInfo info{};
126- info.index = si;
127- info.duration_seconds = duration_sec;
128-
129- UINT32 w = 0 , h = 0 ;
130- if (SUCCEEDED (MFGetAttributeSize (mt.get (), MF_MT_FRAME_SIZE, &w, &h))) {
131- info.width = w;
132- info.height = h;
133- }
134-
135- UINT32 num = 0 , den = 0 ;
136- if (SUCCEEDED (MFGetAttributeRatio (mt.get (), MF_MT_FRAME_RATE, &num, &den)) && den > 0 ) {
137- info.fps = static_cast <double >(num) / static_cast <double >(den);
138- }
139-
138+ for (auto const & info : m_cached_video_streams) {
140139 callback (info, userdata);
141140 }
142141 }
143142
144143 void VideoDecoder::getAudioStreams (void (*callback)(AudioStreamInfo const &, void *), void* userdata) const {
145- if (!m_source_reader || ! callback) return ;
144+ if (!callback) return ;
146145
147- wil::unique_prop_variant var;
148- double duration_sec = 0.0 ;
149- if (SUCCEEDED (m_source_reader->GetPresentationAttribute ((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var))) {
150- duration_sec = var.hVal .QuadPart / 10000000.0 ;
151- }
152-
153- for (DWORD si = 0 ; si < Config::kMaxStreams ; ++si) {
154- win32::com_ptr<IMFMediaType> mt;
155- if (FAILED (m_source_reader->GetNativeMediaType (si, 0 , mt.put ()))) continue ;
156-
157- GUID major = GUID_NULL;
158- if (FAILED (mt->GetGUID (MF_MT_MAJOR_TYPE, &major)) || major != MFMediaType_Audio) continue ;
159-
160- AudioStreamInfo info{};
161- info.index = si;
162- info.duration_seconds = duration_sec;
163- info.channels = (UINT32)MFGetAttributeUINT32 (mt.get (), MF_MT_AUDIO_NUM_CHANNELS, 0 );
164- info.sample_rate = MFGetAttributeUINT32 (mt.get (), MF_MT_AUDIO_SAMPLES_PER_SECOND, 0 );
165-
146+ for (auto const & info : m_cached_audio_streams) {
166147 callback (info, userdata);
167148 }
168149 }
169150
170151 bool VideoDecoder::reopen (VideoOpenOptions const & options) {
171- if (m_last_open_path.empty ()) {
172- Logger::error (" [core] [VideoDecoder] reopen: no previous path (open was never successful)" );
152+ if (!m_byte_stream) {
153+ Logger::error (" [core] [VideoDecoder] reopen: no byte stream available" );
154+ return false ;
155+ }
156+
157+ auto saved_stream = m_byte_stream;
158+
159+ m_source_reader.reset ();
160+ m_media_type.reset ();
161+ m_texture.reset ();
162+ m_shader_resource_view.reset ();
163+ m_device_context.reset ();
164+ m_video_processor.reset ();
165+ m_video_processor_enum.reset ();
166+ m_video_context.reset ();
167+ m_video_device.reset ();
168+
169+ m_output_format = OutputFormat::ARGB32;
170+ m_video_size = Vector2U{};
171+ m_target_size = Vector2U{};
172+ m_duration = 0.0 ;
173+ m_current_time = 0.0 ;
174+ m_last_requested_time = -1.0 ;
175+ m_frame_interval = 1.0 / Config::kDefaultFrameRateNum ;
176+ m_frame_rate_num = Config::kDefaultFrameRateNum ;
177+ m_frame_rate_den = Config::kDefaultFrameRateDen ;
178+ m_frame_pitch = 0 ;
179+ m_video_stream_index = 0 ;
180+ m_loop_state = LoopState{};
181+ m_first_texture_update_logged = false ;
182+ m_cached_video_streams.clear ();
183+ m_cached_audio_streams.clear ();
184+
185+ m_byte_stream = saved_stream;
186+
187+ if (FAILED (m_byte_stream->SetCurrentPosition (0 ))) {
188+ Logger::error (" [core] [VideoDecoder] reopen: failed to reset stream position" );
173189 return false ;
174190 }
175- return open (StringView (m_last_open_path), options);
191+
192+ if (!openFromStream (options)) {
193+ Logger::error (" [core] [VideoDecoder] reopen: failed to reopen" );
194+ return false ;
195+ }
196+
197+ m_last_open_options = options;
198+
199+ setLooping (options.looping );
200+ if (options.loop_duration > 0.0 ) {
201+ setLoopRange (options.loop_end , options.loop_duration );
202+ }
203+
204+ Logger::info (" [core] [VideoDecoder] Reopened video: {}x{}" ,
205+ m_target_size.x , m_target_size.y );
206+
207+ return true ;
176208 }
177209
178210 void VideoDecoder::close () {
@@ -200,6 +232,9 @@ namespace core {
200232 m_video_stream_index = 0 ;
201233 m_loop_state = LoopState{};
202234 m_first_texture_update_logged = false ;
235+
236+ m_cached_video_streams.clear ();
237+ m_cached_audio_streams.clear ();
203238 }
204239
205240 void VideoDecoder::setLoopRange (double end_sec, double duration_sec) {
0 commit comments