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
gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
GstBuffer * buffer, gint * have_data)
gst_ffmpegaudenc_send_frame (GstFFMpegAudEnc * ffmpegaudenc, GstBuffer * buffer)
{
GstAudioEncoder *enc;
AVCodecContext *ctx;
gint res;
GstFlowReturn ret;
gint res;
GstAudioInfo *info;
AVPacket *pkt;
AVFrame *frame = ffmpegaudenc->frame;
gboolean planar;
gint nsamples = -1;
@ -419,8 +417,6 @@ gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
ctx = ffmpegaudenc->context;
pkt = g_slice_new0 (AVPacket);
if (buffer != NULL) {
BufferInfo *buffer_info = g_slice_new0 (BufferInfo);
guint8 *audio_in;
@ -529,28 +525,47 @@ gst_ffmpegaudenc_encode_audio (GstFFMpegAudEnc * ffmpegaudenc,
}
/* 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);
} else {
GST_LOG_OBJECT (ffmpegaudenc, "draining");
/* flushing the encoder */
res = avcodec_encode_audio2 (ctx, pkt, NULL, have_data);
res = avcodec_send_frame (ctx, NULL);
}
if (res < 0) {
char error_str[128] = { 0, };
g_slice_free (AVPacket, pkt);
av_strerror (res, error_str, sizeof (error_str));
GST_ERROR_OBJECT (enc, "Failed to encode buffer: %d - %s", res, error_str);
return GST_FLOW_OK;
if (res == 0) {
ret = GST_FLOW_OK;
} else if (res == AVERROR_EOF) {
ret = GST_FLOW_EOS;
} else { /* Any other return value is an error in our context */
ret = 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;
const AVCodec *codec;
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,
pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket);
codec = ffmpegaudenc->context->codec;
if ((codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) || !buffer) {
/* FIXME: Not really correct, as -1 means "all the samples we got
given so far", which may not be true depending on the codec,
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);
}
ret =
gst_audio_encoder_finish_frame (enc, outbuf,
pkt->duration > 0 ? pkt->duration : -1);
*got_packet = TRUE;
} else {
GST_LOG_OBJECT (ffmpegaudenc, "no output produced");
g_slice_free (AVPacket, pkt);
ret = GST_FLOW_OK;
*got_packet = FALSE;
}
return ret;
}
static void
static GstFlowReturn
gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc)
{
GstFFMpegAudEncClass *oclass;
GstFlowReturn ret = GST_FLOW_OK;
gboolean got_packet;
oclass = (GstFFMpegAudEncClass *) (G_OBJECT_GET_CLASS (ffmpegaudenc));
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");
ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL);
if (ret == GST_FLOW_OK) {
do {
GstFlowReturn ret;
ret = gst_ffmpegaudenc_encode_audio (ffmpegaudenc, NULL, &have_data);
if (ret != GST_FLOW_OK || have_data == 0)
ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
if (ret != GST_FLOW_OK)
break;
} while (try++ < 10);
} while (got_packet);
}
avcodec_flush_buffers (ffmpegaudenc->context);
return ret;
}
static GstFlowReturn
@ -604,17 +613,15 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
{
GstFFMpegAudEnc *ffmpegaudenc;
GstFlowReturn ret;
gint have_data;
gboolean got_packet;
ffmpegaudenc = (GstFFMpegAudEnc *) encoder;
if (G_UNLIKELY (!ffmpegaudenc->opened))
goto not_negotiated;
if (!inbuf) {
gst_ffmpegaudenc_drain (ffmpegaudenc);
return GST_FLOW_OK;
}
if (!inbuf)
return gst_ffmpegaudenc_drain (ffmpegaudenc);
inbuf = gst_buffer_ref (inbuf);
@ -632,10 +639,14 @@ gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf)
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)
goto push_failed;
goto send_frame_failed;
do {
ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet);
} while (got_packet);
return GST_FLOW_OK;
@ -647,9 +658,9 @@ not_negotiated:
gst_buffer_unref (inbuf);
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));
return ret;
}