mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
avauddec: fix decoding of APE and Cook audio
.. and other formats where ffmpeg gives us multiple subframes per input frame. Since we now support non-interleaved audio, we can't just concat buffers any more. Also, audio metas won't be combined when buffers are merged, so when we push out the combined buffer we'll look at the meta describing only the first subframe and think it covers the whole frame leading to stutter/gaps in the output. We could fix this by copying the output data into a new buffer when we merge buffers, but that's suboptimal, so let's add some API to GstAudioDecoder to push out subframes and use that instead. https://gitlab.freedesktop.org/gstreamer/gst-libav/issues/49
This commit is contained in:
parent
caf953bd5d
commit
ef8a1bdd90
2 changed files with 15 additions and 20 deletions
|
@ -188,7 +188,6 @@ gst_ffmpegauddec_close (GstFFMpegAudDec * ffmpegdec, gboolean reset)
|
||||||
GST_LOG_OBJECT (ffmpegdec, "closing libav codec");
|
GST_LOG_OBJECT (ffmpegdec, "closing libav codec");
|
||||||
|
|
||||||
gst_caps_replace (&ffmpegdec->last_caps, NULL);
|
gst_caps_replace (&ffmpegdec->last_caps, NULL);
|
||||||
gst_buffer_replace (&ffmpegdec->outbuf, NULL);
|
|
||||||
|
|
||||||
gst_ffmpeg_avcodec_close (ffmpegdec->context);
|
gst_ffmpeg_avcodec_close (ffmpegdec->context);
|
||||||
ffmpegdec->opened = FALSE;
|
ffmpegdec->opened = FALSE;
|
||||||
|
@ -576,12 +575,10 @@ gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec, GstFlowReturn * ret)
|
||||||
gst_ffmpegauddec_audio_frame (ffmpegdec, oclass->in_plugin, &outbuf, ret);
|
gst_ffmpegauddec_audio_frame (ffmpegdec, oclass->in_plugin, &outbuf, ret);
|
||||||
|
|
||||||
if (outbuf) {
|
if (outbuf) {
|
||||||
GST_LOG_OBJECT (ffmpegdec, "Decoded data, now storing buffer %p", outbuf);
|
GST_LOG_OBJECT (ffmpegdec, "Decoded data, buffer %" GST_PTR_FORMAT, outbuf);
|
||||||
|
*ret =
|
||||||
if (ffmpegdec->outbuf)
|
gst_audio_decoder_finish_subframe (GST_AUDIO_DECODER_CAST (ffmpegdec),
|
||||||
ffmpegdec->outbuf = gst_buffer_append (ffmpegdec->outbuf, outbuf);
|
outbuf);
|
||||||
else
|
|
||||||
ffmpegdec->outbuf = outbuf;
|
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (ffmpegdec, "We didn't get a decoded buffer");
|
GST_DEBUG_OBJECT (ffmpegdec, "We didn't get a decoded buffer");
|
||||||
}
|
}
|
||||||
|
@ -601,6 +598,7 @@ static void
|
||||||
gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec)
|
gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec)
|
||||||
{
|
{
|
||||||
GstFFMpegAudDecClass *oclass;
|
GstFFMpegAudDecClass *oclass;
|
||||||
|
gboolean got_any_frames = FALSE;
|
||||||
|
|
||||||
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
||||||
|
|
||||||
|
@ -617,14 +615,14 @@ gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec)
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
got_frame = gst_ffmpegauddec_frame (ffmpegdec, &ret);
|
got_frame = gst_ffmpegauddec_frame (ffmpegdec, &ret);
|
||||||
|
if (got_frame)
|
||||||
|
got_any_frames = TRUE;
|
||||||
} while (got_frame);
|
} while (got_frame);
|
||||||
avcodec_flush_buffers (ffmpegdec->context);
|
avcodec_flush_buffers (ffmpegdec->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ffmpegdec->outbuf)
|
if (got_any_frames)
|
||||||
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec),
|
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), NULL, 1);
|
||||||
ffmpegdec->outbuf, 1);
|
|
||||||
ffmpegdec->outbuf = NULL;
|
|
||||||
|
|
||||||
send_packet_failed:
|
send_packet_failed:
|
||||||
GST_WARNING_OBJECT (ffmpegdec, "send packet failed, could not drain decoder");
|
GST_WARNING_OBJECT (ffmpegdec, "send packet failed, could not drain decoder");
|
||||||
|
@ -648,6 +646,7 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
GstMapInfo map;
|
GstMapInfo map;
|
||||||
gint size;
|
gint size;
|
||||||
|
gboolean got_any_frames = FALSE;
|
||||||
gboolean got_frame;
|
gboolean got_frame;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
gboolean is_header;
|
gboolean is_header;
|
||||||
|
@ -719,6 +718,9 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
|
||||||
/* decode a frame of audio now */
|
/* decode a frame of audio now */
|
||||||
got_frame = gst_ffmpegauddec_frame (ffmpegdec, &ret);
|
got_frame = gst_ffmpegauddec_frame (ffmpegdec, &ret);
|
||||||
|
|
||||||
|
if (got_frame)
|
||||||
|
got_any_frames = TRUE;
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK) {
|
if (ret != GST_FLOW_OK) {
|
||||||
GST_LOG_OBJECT (ffmpegdec, "breaking because of flow ret %s",
|
GST_LOG_OBJECT (ffmpegdec, "breaking because of flow ret %s",
|
||||||
gst_flow_get_name (ret));
|
gst_flow_get_name (ret));
|
||||||
|
@ -730,14 +732,10 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
|
||||||
gst_buffer_unmap (inbuf, &map);
|
gst_buffer_unmap (inbuf, &map);
|
||||||
gst_buffer_unref (inbuf);
|
gst_buffer_unref (inbuf);
|
||||||
|
|
||||||
if (ffmpegdec->outbuf)
|
if (is_header || got_any_frames) {
|
||||||
ret =
|
|
||||||
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec),
|
|
||||||
ffmpegdec->outbuf, 1);
|
|
||||||
else if (is_header)
|
|
||||||
ret =
|
ret =
|
||||||
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), NULL, 1);
|
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec), NULL, 1);
|
||||||
ffmpegdec->outbuf = NULL;
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -44,9 +44,6 @@ struct _GstFFMpegAudDec
|
||||||
/* prevent reopening the decoder on GST_EVENT_CAPS when caps are same as last time. */
|
/* prevent reopening the decoder on GST_EVENT_CAPS when caps are same as last time. */
|
||||||
GstCaps *last_caps;
|
GstCaps *last_caps;
|
||||||
|
|
||||||
/* Stores current buffers to push as GstAudioDecoder wants 1:1 mapping for input/output buffers */
|
|
||||||
GstBuffer *outbuf;
|
|
||||||
|
|
||||||
/* current output format */
|
/* current output format */
|
||||||
GstAudioInfo info;
|
GstAudioInfo info;
|
||||||
GstAudioChannelPosition ffmpeg_layout[64];
|
GstAudioChannelPosition ffmpeg_layout[64];
|
||||||
|
|
Loading…
Reference in a new issue