Skip to content

Commit a8409f5

Browse files
committed
Pre-allocates HW frames context to prevent ffmpeg to re-allocate it on every seek (flush codecs)
Fixes a critical audio sync issue caused by 3.4.2
1 parent 16dbfb7 commit a8409f5

3 files changed

Lines changed: 109 additions & 8 deletions

File tree

FlyleafLib/MediaFramework/MediaContext/DecoderContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,14 +947,14 @@ public long GetVideoFrame(long timestamp = -1)
947947
switch (VideoDemuxer.FormatContext->streams[packet->stream_index]->codecpar->codec_type)
948948
{
949949
case AVMEDIA_TYPE_AUDIO:
950-
if (timestamp == -1 || (long)(frame->pts * AudioStream.Timebase) - VideoDemuxer.StartTime > timestamp)
950+
if (!VideoDecoder.keyFrameRequired && (timestamp == -1 || (long)(frame->pts * AudioStream.Timebase) - VideoDemuxer.StartTime > timestamp))
951951
VideoDemuxer.AudioPackets.Enqueue((IntPtr)packet);
952952
packet = av_packet_alloc();
953953

954954
continue;
955955

956956
case AVMEDIA_TYPE_SUBTITLE:
957-
if (timestamp == -1 || (long)(frame->pts * SubtitlesStream.Timebase) - VideoDemuxer.StartTime > timestamp)
957+
if (!VideoDecoder.keyFrameRequired && (timestamp == -1 || (long)(frame->pts * SubtitlesStream.Timebase) - VideoDemuxer.StartTime > timestamp))
958958
VideoDemuxer.SubtitlesPackets.Enqueue((IntPtr)packet);
959959
packet = av_packet_alloc();
960960

FlyleafLib/MediaFramework/MediaDecoder/VideoDecoder.cs

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public ConcurrentQueue<VideoFrame>
3535

3636
// Hardware & Software_Handled (Y_UV | Y_U_V)
3737
Texture2DDescription textDesc, textDescUV;
38+
ID3D11Texture2D textureFFmpeg;
39+
AVCodecContext_get_format getHWformat;
3840

3941
// Software_Sws (RGBA)
4042
const AVPixelFormat VOutPixelFormat = AVPixelFormat.AV_PIX_FMT_RGBA;
@@ -107,9 +109,15 @@ public void DisposeVA()
107109
{
108110
if (Renderer == null) return;
109111

110-
fixed(AVBufferRef** ptr = &hw_device_ctx) av_buffer_unref(ptr);
111-
hw_device_ctx = null;
112+
if (hw_device_ctx != null)
113+
fixed(AVBufferRef** ptr = &hw_device_ctx) av_buffer_unref(ptr);
114+
115+
if (hwframes != null)
116+
fixed(AVBufferRef** ptr = &hwframes) av_buffer_unref(ptr);
112117

118+
hw_device_ctx = null;
119+
hwframes = null;
120+
113121
Renderer.Dispose();
114122
}
115123
public void Swap(VideoDecoder videoDecoder)
@@ -170,10 +178,96 @@ public void Swap(VideoDecoder videoDecoder)
170178

171179
public VideoDecoder(Config config, Control control = null, int uniqueId = -1, bool initVA = true) : base(config, uniqueId)
172180
{
181+
getHWformat = new AVCodecContext_get_format(get_format);
182+
173183
if (initVA)
174184
InitVA(control);
175185
}
176186

187+
AVBufferRef* hwframes;
188+
private unsafe AVPixelFormat get_format(AVCodecContext* avctx, AVPixelFormat* pix_fmts)
189+
{
190+
Log("get_format");
191+
192+
//if (codecCtx->hw_frames_ctx == null)
193+
// return AVPixelFormat.AV_PIX_FMT_NONE;
194+
195+
if (AllocateHWFrames() != 0)
196+
Log("Hmmm...");
197+
198+
return AVPixelFormat.AV_PIX_FMT_D3D11;
199+
}
200+
201+
private bool ShouldAllocateNew()
202+
{
203+
if (hwframes == null)
204+
return true;
205+
206+
var t2 = (AVHWFramesContext*) hwframes->data;
207+
208+
if (codecCtx->width != t2->width)
209+
return true;
210+
211+
if (codecCtx->height != t2->height)
212+
return true;
213+
214+
var fmt = codecCtx->sw_pix_fmt == AVPixelFormat.AV_PIX_FMT_YUV420P10LE ? AVPixelFormat.AV_PIX_FMT_P010LE : AVPixelFormat.AV_PIX_FMT_NV12;
215+
if (fmt != t2->sw_format)
216+
return true;
217+
218+
return false;
219+
}
220+
private int AllocateHWFrames()
221+
{
222+
if (!ShouldAllocateNew())
223+
{
224+
if (hwframes != null && codecCtx->hw_frames_ctx == null)
225+
{
226+
codecCtx->hw_frames_ctx = av_buffer_ref(hwframes);
227+
Log("Already allocated 1");
228+
}
229+
else
230+
Log("Already allocated 2");
231+
232+
textDesc.Format = textureFFmpeg.Description.Format;
233+
return 0;
234+
}
235+
236+
Log("Allocating ...");
237+
238+
if (hwframes != null)
239+
fixed(AVBufferRef** ptr = &hwframes) av_buffer_unref(ptr);
240+
241+
codecCtx->hw_frames_ctx = av_hwframe_ctx_alloc(codecCtx->hw_device_ctx);
242+
if (codecCtx->hw_frames_ctx == null)
243+
return -1;
244+
245+
codecCtx->hwaccel_context = null;
246+
codecCtx->hwaccel_flags |= 2; //AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX
247+
248+
var t2 = (AVHWFramesContext*)(codecCtx->hw_frames_ctx->data);
249+
t2->format = AVPixelFormat.AV_PIX_FMT_D3D11;
250+
t2->sw_format = codecCtx->sw_pix_fmt == AVPixelFormat.AV_PIX_FMT_YUV420P10LE ? AVPixelFormat.AV_PIX_FMT_P010LE : AVPixelFormat.AV_PIX_FMT_NV12;
251+
t2->width = codecCtx->width;
252+
t2->height = codecCtx->height;
253+
t2->initial_pool_size = 20;
254+
255+
AVD3D11VAFramesContext *t3 = (AVD3D11VAFramesContext *)t2->hwctx;
256+
t3->texture = null;
257+
t3->BindFlags |= (uint)BindFlags.Decoder;
258+
259+
hwframes = av_buffer_ref(codecCtx->hw_frames_ctx);
260+
261+
int ret = av_hwframe_ctx_init(codecCtx->hw_frames_ctx);
262+
if (ret == 0)
263+
{
264+
textureFFmpeg = new ID3D11Texture2D((IntPtr) t3->texture);
265+
textDesc.Format = textureFFmpeg.Description.Format;
266+
}
267+
268+
return ret;
269+
}
270+
177271
protected override int Setup(AVCodec* codec)
178272
{
179273
VideoAccelerated = false;
@@ -200,6 +294,12 @@ protected override int Setup(AVCodec* codec)
200294
codecCtx->thread_count = Math.Min(Config.Decoder.VideoThreads, codecCtx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16);
201295
codecCtx->thread_type = 0;
202296

297+
if (VideoAccelerated)
298+
{
299+
codecCtx->pix_fmt = AVPixelFormat.AV_PIX_FMT_D3D11;
300+
codecCtx->get_format = getHWformat;
301+
}
302+
203303
int bits = VideoStream.PixelFormatDesc->comp.ToArray()[0].depth;
204304

205305
textDesc = new Texture2DDescription()
@@ -647,11 +747,12 @@ internal VideoFrame ProcessVideoFrame(AVFrame* frame)
647747
VideoAccelerated = false;
648748
Renderer?.FrameResized();
649749
CodecChanged?.Invoke(this);
750+
codecCtx->get_format = null;
751+
650752
return ProcessVideoFrame(frame);
651753
}
652-
653-
ID3D11Texture2D textureFFmpeg = new ID3D11Texture2D((IntPtr) frame->data.ToArray()[0]);
654-
textDesc.Format = textureFFmpeg.Description.Format;
754+
755+
//Log($"{(IntPtr) frame->data.ToArray()[0]} | {(int) frame->data.ToArray()[1]} | {(IntPtr) (((AVD3D11VAFramesContext *)((AVHWFramesContext*)(codecCtx->hw_frames_ctx->data))->hwctx)->texture)}");
655756
mFrame.textures = new ID3D11Texture2D[1];
656757
mFrame.textures[0] = Renderer.Device.CreateTexture2D(textDesc);
657758
Renderer.Device.ImmediateContext.CopySubresourceRegion(mFrame.textures[0], 0, 0, 0, 0, textureFFmpeg, (int) frame->data.ToArray()[1], new Vortice.Mathematics.Box(0, 0, 0, mFrame.textures[0].Description.Width, mFrame.textures[0].Description.Height, 1));

FlyleafLib/MediaPlayer/Player.Screamers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ private bool MediaBuffer()
157157
{
158158
for (int i=0; i<Math.Min(20, AudioDecoder.Frames.Count); i++)
159159
{
160-
if (aFrame == null || vFrame.timestamp + 20000 > aFrame.timestamp) { gotAudio = true; break; }
160+
if (aFrame == null || aFrame.timestamp + 20000 > vFrame.timestamp) { gotAudio = true; break; }
161161

162162
Log("Drop AFrame " + TicksToTime(aFrame.timestamp));
163163
AudioDecoder.Frames.TryDequeue(out aFrame);

0 commit comments

Comments
 (0)