mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-06 10:42:22 +00:00
avauddec: port to new decoding API
https://bugzilla.gnome.org/show_bug.cgi?id=792900
This commit is contained in:
parent
8f3bc07e09
commit
6243197c82
1 changed files with 69 additions and 118 deletions
|
@ -453,25 +453,19 @@ gst_avpacket_init (AVPacket * packet, guint8 * data, guint size)
|
||||||
packet->size = size;
|
packet->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
/*
|
||||||
|
* Returns: whether a frame was decoded
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
gst_ffmpegauddec_audio_frame (GstFFMpegAudDec * ffmpegdec,
|
gst_ffmpegauddec_audio_frame (GstFFMpegAudDec * ffmpegdec,
|
||||||
AVCodec * in_plugin, guint8 * data, guint size, gint * have_data,
|
AVCodec * in_plugin, GstBuffer ** outbuf, GstFlowReturn * ret)
|
||||||
GstBuffer ** outbuf, GstFlowReturn * ret)
|
|
||||||
{
|
{
|
||||||
gint len = -1;
|
gboolean got_frame = FALSE;
|
||||||
AVPacket packet;
|
gint res;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (ffmpegdec, "size: %d", size);
|
res = avcodec_receive_frame (ffmpegdec->context, ffmpegdec->frame);
|
||||||
|
|
||||||
gst_avpacket_init (&packet, data, size);
|
if (res >= 0) {
|
||||||
len =
|
|
||||||
avcodec_decode_audio4 (ffmpegdec->context, ffmpegdec->frame, have_data,
|
|
||||||
&packet);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (ffmpegdec,
|
|
||||||
"Decode audio: len=%d, have_data=%d", len, *have_data);
|
|
||||||
|
|
||||||
if (len >= 0 && *have_data) {
|
|
||||||
gint nsamples, channels, byte_per_sample;
|
gint nsamples, channels, byte_per_sample;
|
||||||
gsize output_size;
|
gsize output_size;
|
||||||
|
|
||||||
|
@ -479,10 +473,11 @@ gst_ffmpegauddec_audio_frame (GstFFMpegAudDec * ffmpegdec,
|
||||||
ffmpegdec->frame, FALSE)) {
|
ffmpegdec->frame, FALSE)) {
|
||||||
*outbuf = NULL;
|
*outbuf = NULL;
|
||||||
*ret = GST_FLOW_NOT_NEGOTIATED;
|
*ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
len = -1;
|
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
got_frame = TRUE;
|
||||||
|
|
||||||
channels = ffmpegdec->info.channels;
|
channels = ffmpegdec->info.channels;
|
||||||
nsamples = ffmpegdec->frame->nb_samples;
|
nsamples = ffmpegdec->frame->nb_samples;
|
||||||
byte_per_sample = ffmpegdec->info.finfo->width / 8;
|
byte_per_sample = ffmpegdec->info.finfo->width / 8;
|
||||||
|
@ -578,59 +573,45 @@ gst_ffmpegauddec_audio_frame (GstFFMpegAudDec * ffmpegdec,
|
||||||
/* Mark corrupted frames as corrupted */
|
/* Mark corrupted frames as corrupted */
|
||||||
if (ffmpegdec->frame->flags & AV_FRAME_FLAG_CORRUPT)
|
if (ffmpegdec->frame->flags & AV_FRAME_FLAG_CORRUPT)
|
||||||
GST_BUFFER_FLAG_SET (*outbuf, GST_BUFFER_FLAG_CORRUPTED);
|
GST_BUFFER_FLAG_SET (*outbuf, GST_BUFFER_FLAG_CORRUPTED);
|
||||||
} else {
|
} else if (res == AVERROR (EAGAIN)) {
|
||||||
*outbuf = NULL;
|
*outbuf = NULL;
|
||||||
|
} else if (res == AVERROR_EOF) { /* Should not happen */
|
||||||
|
*ret = GST_FLOW_EOS;
|
||||||
|
GST_WARNING_OBJECT (ffmpegdec,
|
||||||
|
"Tried to receive frame on a flushed context");
|
||||||
|
} else if (res < 0) {
|
||||||
|
*ret = GST_FLOW_ERROR;
|
||||||
|
GST_ELEMENT_ERROR (ffmpegdec, STREAM, DECODE, ("Decoding problem"),
|
||||||
|
("Legitimate decoding error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
av_frame_unref (ffmpegdec->frame);
|
av_frame_unref (ffmpegdec->frame);
|
||||||
GST_DEBUG_OBJECT (ffmpegdec, "return flow %d, out %p, len %d",
|
GST_DEBUG_OBJECT (ffmpegdec, "return flow %d, out %p, got_frame %d",
|
||||||
*ret, *outbuf, len);
|
*ret, *outbuf, got_frame);
|
||||||
return len;
|
return got_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gst_ffmpegauddec_frame:
|
/*
|
||||||
* ffmpegdec:
|
* Returns: whether a frame was decoded
|
||||||
* data: pointer to the data to decode
|
|
||||||
* size: size of data in bytes
|
|
||||||
* got_data: 0 if no data was decoded, != 0 otherwise.
|
|
||||||
* in_time: timestamp of data
|
|
||||||
* in_duration: duration of data
|
|
||||||
* ret: GstFlowReturn to return in the chain function
|
|
||||||
*
|
|
||||||
* Decode the given frame and pushes it downstream.
|
|
||||||
*
|
|
||||||
* Returns: Number of bytes used in decoding, -1 on error/failure.
|
|
||||||
*/
|
*/
|
||||||
|
static gboolean
|
||||||
static gint
|
gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec, GstFlowReturn * ret)
|
||||||
gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec,
|
|
||||||
guint8 * data, guint size, gint * have_data, GstFlowReturn * ret)
|
|
||||||
{
|
{
|
||||||
GstFFMpegAudDecClass *oclass;
|
GstFFMpegAudDecClass *oclass;
|
||||||
GstBuffer *outbuf = NULL;
|
GstBuffer *outbuf = NULL;
|
||||||
gint len = 0;
|
gboolean got_frame = FALSE;
|
||||||
|
|
||||||
if (G_UNLIKELY (ffmpegdec->context->codec == NULL))
|
if (G_UNLIKELY (ffmpegdec->context->codec == NULL))
|
||||||
goto no_codec;
|
goto no_codec;
|
||||||
|
|
||||||
GST_LOG_OBJECT (ffmpegdec, "data:%p, size:%d", data, size);
|
|
||||||
|
|
||||||
*ret = GST_FLOW_OK;
|
*ret = GST_FLOW_OK;
|
||||||
ffmpegdec->context->frame_number++;
|
ffmpegdec->context->frame_number++;
|
||||||
|
|
||||||
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
||||||
|
|
||||||
len =
|
got_frame =
|
||||||
gst_ffmpegauddec_audio_frame (ffmpegdec, oclass->in_plugin, data, size,
|
gst_ffmpegauddec_audio_frame (ffmpegdec, oclass->in_plugin, &outbuf, ret);
|
||||||
have_data, &outbuf, ret);
|
|
||||||
|
|
||||||
if (len < 0) {
|
|
||||||
GST_WARNING_OBJECT (ffmpegdec,
|
|
||||||
"avdec_%s: decoding error (len: %d, have_data: %d)",
|
|
||||||
oclass->in_plugin->name, len, *have_data);
|
|
||||||
goto beach;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outbuf) {
|
if (outbuf) {
|
||||||
GST_LOG_OBJECT (ffmpegdec, "Decoded data, now storing buffer %p", outbuf);
|
GST_LOG_OBJECT (ffmpegdec, "Decoded data, now storing buffer %p", outbuf);
|
||||||
|
@ -644,13 +625,13 @@ gst_ffmpegauddec_frame (GstFFMpegAudDec * ffmpegdec,
|
||||||
}
|
}
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
return len;
|
return got_frame;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
no_codec:
|
no_codec:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (ffmpegdec, "no codec context");
|
GST_ERROR_OBJECT (ffmpegdec, "no codec context");
|
||||||
return -1;
|
goto beach;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,7 +643,7 @@ gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec)
|
||||||
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
|
||||||
|
|
||||||
if (oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) {
|
if (oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) {
|
||||||
gint have_data, len;
|
gboolean got_frame;
|
||||||
|
|
||||||
GST_LOG_OBJECT (ffmpegdec,
|
GST_LOG_OBJECT (ffmpegdec,
|
||||||
"codec has delay capabilities, calling until libav has drained everything");
|
"codec has delay capabilities, calling until libav has drained everything");
|
||||||
|
@ -670,9 +651,8 @@ gst_ffmpegauddec_drain (GstFFMpegAudDec * ffmpegdec)
|
||||||
do {
|
do {
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
len = gst_ffmpegauddec_frame (ffmpegdec, NULL, 0, &have_data, &ret);
|
got_frame = gst_ffmpegauddec_frame (ffmpegdec, &ret);
|
||||||
|
} while (got_frame);
|
||||||
} while (len >= 0 && have_data == 1);
|
|
||||||
avcodec_flush_buffers (ffmpegdec->context);
|
avcodec_flush_buffers (ffmpegdec->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,11 +677,13 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
|
||||||
{
|
{
|
||||||
GstFFMpegAudDec *ffmpegdec;
|
GstFFMpegAudDec *ffmpegdec;
|
||||||
GstFFMpegAudDecClass *oclass;
|
GstFFMpegAudDecClass *oclass;
|
||||||
guint8 *data, *bdata;
|
guint8 *data;
|
||||||
GstMapInfo map;
|
GstMapInfo map;
|
||||||
gint size, bsize, len, have_data;
|
gint size;
|
||||||
|
gboolean got_frame;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
gboolean do_padding, is_header;
|
gboolean is_header;
|
||||||
|
AVPacket packet;
|
||||||
|
|
||||||
ffmpegdec = (GstFFMpegAudDec *) decoder;
|
ffmpegdec = (GstFFMpegAudDec *) decoder;
|
||||||
|
|
||||||
|
@ -736,81 +718,46 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
|
||||||
|
|
||||||
gst_buffer_map (inbuf, &map, GST_MAP_READ);
|
gst_buffer_map (inbuf, &map, GST_MAP_READ);
|
||||||
|
|
||||||
bdata = map.data;
|
data = map.data;
|
||||||
bsize = map.size;
|
size = map.size;
|
||||||
|
|
||||||
if (bsize > 0 && (!GST_MEMORY_IS_ZERO_PADDED (map.memory)
|
if (size > 0 && (!GST_MEMORY_IS_ZERO_PADDED (map.memory)
|
||||||
|| (map.maxsize - map.size) < AV_INPUT_BUFFER_PADDING_SIZE)) {
|
|| (map.maxsize - map.size) < AV_INPUT_BUFFER_PADDING_SIZE)) {
|
||||||
/* add padding */
|
/* add padding */
|
||||||
if (ffmpegdec->padded_size < bsize + AV_INPUT_BUFFER_PADDING_SIZE) {
|
if (ffmpegdec->padded_size < size + AV_INPUT_BUFFER_PADDING_SIZE) {
|
||||||
ffmpegdec->padded_size = bsize + AV_INPUT_BUFFER_PADDING_SIZE;
|
ffmpegdec->padded_size = size + AV_INPUT_BUFFER_PADDING_SIZE;
|
||||||
ffmpegdec->padded = g_realloc (ffmpegdec->padded, ffmpegdec->padded_size);
|
ffmpegdec->padded = g_realloc (ffmpegdec->padded, ffmpegdec->padded_size);
|
||||||
GST_LOG_OBJECT (ffmpegdec, "resized padding buffer to %d",
|
GST_LOG_OBJECT (ffmpegdec, "resized padding buffer to %d",
|
||||||
ffmpegdec->padded_size);
|
ffmpegdec->padded_size);
|
||||||
}
|
}
|
||||||
GST_CAT_TRACE_OBJECT (CAT_PERFORMANCE, ffmpegdec,
|
GST_CAT_TRACE_OBJECT (CAT_PERFORMANCE, ffmpegdec,
|
||||||
"Copy input to add padding");
|
"Copy input to add padding");
|
||||||
memcpy (ffmpegdec->padded, bdata, bsize);
|
memcpy (ffmpegdec->padded, data, size);
|
||||||
memset (ffmpegdec->padded + bsize, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
memset (ffmpegdec->padded + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
|
||||||
bdata = ffmpegdec->padded;
|
data = ffmpegdec->padded;
|
||||||
do_padding = TRUE;
|
}
|
||||||
} else {
|
|
||||||
do_padding = FALSE;
|
gst_avpacket_init (&packet, data, size);
|
||||||
|
|
||||||
|
if (!packet.size)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (avcodec_send_packet (ffmpegdec->context, &packet) < 0) {
|
||||||
|
goto send_packet_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
guint8 tmp_padding[AV_INPUT_BUFFER_PADDING_SIZE];
|
|
||||||
|
|
||||||
data = bdata;
|
|
||||||
size = bsize;
|
|
||||||
|
|
||||||
if (do_padding) {
|
|
||||||
/* add temporary padding */
|
|
||||||
GST_CAT_TRACE_OBJECT (CAT_PERFORMANCE, ffmpegdec,
|
|
||||||
"Add temporary input padding");
|
|
||||||
memcpy (tmp_padding, data + size, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
memset (data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decode a frame of audio now */
|
/* decode a frame of audio now */
|
||||||
len = gst_ffmpegauddec_frame (ffmpegdec, data, size, &have_data, &ret);
|
got_frame = gst_ffmpegauddec_frame (ffmpegdec, &ret);
|
||||||
|
|
||||||
if (do_padding) {
|
|
||||||
memcpy (data + size, tmp_padding, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
||||||
/* bad flow return, make sure we discard all data and exit */
|
/* bad flow return, make sure we discard all data and exit */
|
||||||
bsize = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} while (got_frame);
|
||||||
if (len == 0 && have_data == 0) {
|
|
||||||
/* nothing was decoded, this could be because no data was available or
|
|
||||||
* because we were skipping frames.
|
|
||||||
* If we have no context we must exit and wait for more data, we keep the
|
|
||||||
* data we tried. */
|
|
||||||
GST_LOG_OBJECT (ffmpegdec, "Decoding didn't return any data, breaking");
|
|
||||||
break;
|
|
||||||
} else if (len < 0) {
|
|
||||||
/* a decoding error happened, we must break and try again with next data. */
|
|
||||||
GST_LOG_OBJECT (ffmpegdec, "Decoding error, breaking");
|
|
||||||
bsize = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* prepare for the next round, for codecs with a context we did this
|
|
||||||
* already when using the parser. */
|
|
||||||
bsize -= len;
|
|
||||||
bdata += len;
|
|
||||||
|
|
||||||
do_padding = TRUE;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (ffmpegdec, "Before (while bsize>0). bsize:%d , bdata:%p",
|
|
||||||
bsize, bdata);
|
|
||||||
} while (bsize > 0);
|
|
||||||
|
|
||||||
gst_buffer_unmap (inbuf, &map);
|
gst_buffer_unmap (inbuf, &map);
|
||||||
gst_buffer_unref (inbuf);
|
gst_buffer_unref (inbuf);
|
||||||
|
@ -819,15 +766,12 @@ gst_ffmpegauddec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf)
|
||||||
ret =
|
ret =
|
||||||
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec),
|
gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (ffmpegdec),
|
||||||
ffmpegdec->outbuf, 1);
|
ffmpegdec->outbuf, 1);
|
||||||
else if (len < 0 || is_header)
|
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;
|
ffmpegdec->outbuf = NULL;
|
||||||
|
|
||||||
if (bsize > 0) {
|
done:
|
||||||
GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -837,7 +781,14 @@ not_negotiated:
|
||||||
GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
|
GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
|
||||||
("avdec_%s: input format was not set before data start",
|
("avdec_%s: input format was not set before data start",
|
||||||
oclass->in_plugin->name));
|
oclass->in_plugin->name));
|
||||||
return GST_FLOW_NOT_NEGOTIATED;
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_packet_failed:
|
||||||
|
{
|
||||||
|
GST_WARNING_OBJECT (ffmpegdec, "decoding error");
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue