omx: Use the EOS flag to handle flushing at the end
authorMartin Storsjö <martin@martin.st>
Mon, 6 Feb 2017 22:25:19 +0000 (00:25 +0200)
committerMartin Storsjö <martin@martin.st>
Wed, 8 Feb 2017 09:50:57 +0000 (11:50 +0200)
This avoids having to count the number of frames sent to the codec
and the number of output packets received; instead just wait until
the encoder returns a buffer with the EOS flag set.

Signed-off-by: Martin Storsjö <martin@martin.st>
libavcodec/omx.c

index 05c8743..f43e92a 100644 (file)
@@ -220,7 +220,7 @@ typedef struct OMXCodecContext {
 
     int mutex_cond_inited;
 
-    int num_in_frames, num_out_frames;
+    int eos_sent, got_eos;
 
     uint8_t *output_buf;
     int output_buf_size;
@@ -791,17 +791,35 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
             av_log(avctx, AV_LOG_ERROR, "OMX_EmptyThisBuffer failed: %x\n", err);
             return AVERROR_UNKNOWN;
         }
-        s->num_in_frames++;
+    } else if (!s->eos_sent) {
+        buffer = get_buffer(&s->input_mutex, &s->input_cond,
+                            &s->num_free_in_buffers, s->free_in_buffers, 1);
+
+        buffer->nFilledLen = 0;
+        buffer->nFlags = OMX_BUFFERFLAG_EOS;
+        buffer->pAppPrivate = buffer->pOutputPortPrivate = NULL;
+        err = OMX_EmptyThisBuffer(s->handle, buffer);
+        if (err != OMX_ErrorNone) {
+            append_buffer(&s->input_mutex, &s->input_cond, &s->num_free_in_buffers, s->free_in_buffers, buffer);
+            av_log(avctx, AV_LOG_ERROR, "OMX_EmptyThisBuffer failed: %x\n", err);
+            return AVERROR_UNKNOWN;
+        }
+        s->eos_sent = 1;
     }
 
-    while (!*got_packet && ret == 0) {
-        // Only wait for output if flushing and not all frames have been output
+    while (!*got_packet && ret == 0 && !s->got_eos) {
+        // If not flushing, just poll the queue if there's finished packets.
+        // If flushing, do a blocking wait until we either get a completed
+        // packet, or get EOS.
         buffer = get_buffer(&s->output_mutex, &s->output_cond,
                             &s->num_done_out_buffers, s->done_out_buffers,
-                            !frame && s->num_out_frames < s->num_in_frames);
+                            !frame);
         if (!buffer)
             break;
 
+        if (buffer->nFlags & OMX_BUFFERFLAG_EOS)
+            s->got_eos = 1;
+
         if (buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG && avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
             if ((ret = av_reallocp(&avctx->extradata, avctx->extradata_size + buffer->nFilledLen + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
                 avctx->extradata_size = 0;
@@ -811,8 +829,6 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
             avctx->extradata_size += buffer->nFilledLen;
             memset(avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
         } else {
-            if (buffer->nFlags & OMX_BUFFERFLAG_ENDOFFRAME)
-                s->num_out_frames++;
             if (!(buffer->nFlags & OMX_BUFFERFLAG_ENDOFFRAME) || !pkt->data) {
                 // If the output packet isn't preallocated, just concatenate everything in our
                 // own buffer