avaudenc: port to send_frame / receive_packet

https://bugzilla.gnome.org/show_bug.cgi?id=792900
This commit is contained in:
Mathieu Duponchelle 2018-07-01 17:09:05 +02:00
parent 3e8709d21a
commit 8562f10969

View file

@ -402,15 +402,13 @@ buffer_info_free (void *opaque, guint8 * data)
} }
static GstFlowReturn static GstFlowReturn
gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc, gst_ffmpegaudenc_send_frame (GstFFMpegAudEnc * ffmpegaudenc, GstBuffer * buffer)
GstBuffer * buffer, gint * have_data)
{ {
GstAudioEncoder *enc; GstAudioEncoder *enc;
AVCodecContext *ctx; AVCodecContext *ctx;
gint res;
GstFlowReturn ret; GstFlowReturn ret;
gint res;
GstAudioInfo *info; GstAudioInfo *info;
AVPacket *pkt;
AVFrame *frame = ffmpegaudenc->frame; AVFrame *frame = ffmpegaudenc->frame;
gboolean planar; gboolean planar;
gint nsamples = -1; gint nsamples = -1;
@ -419,8 +417,6 @@ gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
ctx = ffmpegaudenc->context; ctx = ffmpegaudenc->context;
pkt = g_slice_new0 (AVPacket);
if (buffer != NULL) { if (buffer != NULL) {
BufferInfo *buffer_info = g_slice_new0 (BufferInfo); BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
guint8 *audio_in; guint8 *audio_in;
@ -529,28 +525,47 @@ gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
} }
/* we have a frame to feed the encoder */ /* we have a frame to feed the encoder */
res = avcodec_encode_audio2 (ctx, pkt, frame, have_data); res = avcodec_send_frame (ctx, frame);
av_frame_unref (frame); av_frame_unref (frame);
} else { } else {
GST_LOG_OBJECT (ffmpegaudenc, "draining"); GST_LOG_OBJECT (ffmpegaudenc, "draining");
/* flushing the encoder */ /* flushing the encoder */
res = avcodec_encode_audio2 (ctx, pkt, NULL, have_data); res = avcodec_send_frame (ctx, NULL);
} }
if (res < 0) { if (res == 0) {
char error_str[128] = { 0, }; ret = GST_FLOW_OK;
} else if (res == AVERROR_EOF) {
g_slice_free (AVPacket, pkt); ret = GST_FLOW_EOS;
av_strerror (res, error_str, sizeof (error_str)); } else { /* Any other return value is an error in our context */
GST_ERROR_OBJECT (enc, "Failed to encode buffer: %d - %s", res, error_str); ret = GST_FLOW_OK;
return GST_FLOW_OK; GST_WARNING_OBJECT (ffmpegaudenc, "Failed to encode buffer");
} }
GST_LOG_OBJECT (ffmpegaudenc, "got output size %d", res);
if (*have_data) { return ret;
}
static GstFlowReturn
gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc,
gboolean * got_packet)
{
GstAudioEncoder *enc;
AVCodecContext *ctx;
gint res;
GstFlowReturn ret;
AVPacket *pkt;
enc = GST_AUDIO_ENCODER (ffmpegaudenc);
ctx = ffmpegaudenc->context;
pkt = g_slice_new0 (AVPacket);
res = avcodec_receive_packet (ctx, pkt);
if (res == 0) {
GstBuffer *outbuf; GstBuffer *outbuf;
const AVCodec *codec;
GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size); GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size);
@ -558,45 +573,39 @@ gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data, gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data,
pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket); pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket);
codec = ffmpegaudenc->context->codec; ret =
if ((codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) || !buffer) { gst_audio_encoder_finish_frame (enc, outbuf,
/* FIXME: Not really correct, as -1 means "all the samples we got pkt->duration > 0 ? pkt->duration : -1);
given so far", which may not be true depending on the codec, *got_packet = TRUE;
but we have no way to know AFAICT */
ret = gst_audio_encoder_finish_frame (enc, outbuf, -1);
} else {
ret = gst_audio_encoder_finish_frame (enc, outbuf, nsamples);
}
} else { } else {
GST_LOG_OBJECT (ffmpegaudenc, "no output produced"); GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
g_slice_free (AVPacket, pkt); g_slice_free (AVPacket, pkt);
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
*got_packet = FALSE;
} }
return ret; return ret;
} }
static void static GstFlowReturn
gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc) gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc)
{ {
GstFFMpegAudEncClass *oclass; GstFlowReturn ret = GST_FLOW_OK;
gboolean got_packet;
oclass = (GstFFMpegAudEncClass *) (G_OBJECT_GET_CLASS (ffmpegaudenc)); ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL);
if (oclass->in_plugin->capabilities & AV_CODEC_CAP_DELAY) {
gint have_data, try = 0;
GST_LOG_OBJECT (ffmpegaudenc,
"codec has delay capabilities, calling until libav has drained everything");
if (ret == GST_FLOW_OK) {
do { do {
GstFlowReturn ret; ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
if (ret != GST_FLOW_OK)
ret = gst_ffmpegaudenc_encode_audio (ffmpegaudenc, NULL, &have_data);
if (ret != GST_FLOW_OK || have_data == 0)
break; break;
} while (try++ < 10); } while (got_packet);
} }
avcodec_flush_buffers (ffmpegaudenc->context);
return ret;
} }
static GstFlowReturn static GstFlowReturn
@ -604,17 +613,15 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
{ {
GstFFMpegAudEnc *ffmpegaudenc; GstFFMpegAudEnc *ffmpegaudenc;
GstFlowReturn ret; GstFlowReturn ret;
gint have_data; gboolean got_packet;
ffmpegaudenc = (GstFFMpegAudEnc *) encoder; ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
if (G_UNLIKELY (!ffmpegaudenc->opened)) if (G_UNLIKELY (!ffmpegaudenc->opened))
goto not_negotiated; goto not_negotiated;
if (!inbuf) { if (!inbuf)
gst_ffmpegaudenc_drain (ffmpegaudenc); return gst_ffmpegaudenc_drain (ffmpegaudenc);
return GST_FLOW_OK;
}
inbuf = gst_buffer_ref (inbuf); inbuf = gst_buffer_ref (inbuf);
@ -632,10 +639,14 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
info->channels, info->position, ffmpegaudenc->ffmpeg_layout); info->channels, info->position, ffmpegaudenc->ffmpeg_layout);
} }
ret = gst_ffmpegaudenc_encode_audio (ffmpegaudenc, inbuf, &have_data); ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, inbuf);
if (ret != GST_FLOW_OK) if (ret != GST_FLOW_OK)
goto push_failed; goto send_frame_failed;
do {
ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
} while (got_packet);
return GST_FLOW_OK; return GST_FLOW_OK;
@ -647,9 +658,9 @@ not_negotiated:
gst_buffer_unref (inbuf); gst_buffer_unref (inbuf);
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
push_failed: send_frame_failed:
{ {
GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to push buffer %d (%s)", ret, GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to send frame %d (%s)", ret,
gst_flow_get_name (ret)); gst_flow_get_name (ret));
return ret; return ret;
} }