On Thu, 23 Jun 2016, Anton Khirnov wrote:

Quoting Martin Storsjö (2016-06-23 13:06:41)
While it is less featureful (and slower) than the built-in H264
decoder, one could potentially want to use it to take advantage
of the cisco patent license offer.
---
I got a user explicitly requesting this feature, so apparently there
is (some) demand for it.

The decoder is very simple; it doesn't handle B-frames, so there's
no decoding delay, and the decoder doesn't allow decoding into
user-supplied buffers.
---
+static int init_bsf(AVCodecContext *avctx)
+{
+    SVCContext *s = avctx->priv_data;
+    const AVBitStreamFilter *filter;
+    int ret;
+
+    if (s->bsf)
+        return 0;
+
+    filter = av_bsf_get_by_name("h264_mp4toannexb");
+    if (!filter)
+        return AVERROR_BUG;
+
+    ret = av_bsf_alloc(filter, &s->bsf);
+    if (ret < 0)
+        return ret;
+
+    ret = avcodec_parameters_from_context(s->bsf->par_in, avctx);
+    if (ret < 0)
+        return ret;
+
+    s->bsf->time_base_in = avctx->time_base;
+
+    ret = av_bsf_init(s->bsf);
+    if (ret < 0)
+        return ret;
+
+    return ret;
+}
+
+static int svc_decode_frame(AVCodecContext *avctx, void *data,
+                            int *got_frame, AVPacket *avpkt)
+{
+    SVCContext *s = avctx->priv_data;
+    SBufferInfo info = { 0 };
+    uint8_t* ptrs[3];
+    int linesize[3];
+    AVFrame *avframe = data;
+    int ret;
+    DECODING_STATE state;
+
+    init_bsf(avctx);

The return value should probably be checked.

Sure, will do

+
+    if (avpkt->size) {
+        AVPacket input_ref = { 0 };
+        if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) {
+            ret = av_fifo_realloc2(s->packet_fifo,
+                                   av_fifo_size(s->packet_fifo) + 
sizeof(input_ref));
+            if (ret < 0)
+                return ret;
+        }
+
+        ret = av_packet_ref(&input_ref, avpkt);
+        if (ret < 0)
+            return ret;
+        av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), 
NULL);
+    }
+
+    while (!*got_frame) {
+        /* prepare the input data -- convert to Annex B if needed */
+        if (s->pkt_filtered.size <= 0) {
+            AVPacket input_ref;
+
+            /* no more data */
+            if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket))
+                return avpkt->size ? avpkt->size : 0;
+
+            av_packet_unref(&s->pkt_filtered);
+
+            av_fifo_generic_read(s->packet_fifo, &input_ref, 
sizeof(input_ref), NULL);
+            ret = av_bsf_send_packet(s->bsf, &input_ref);
+            if (ret < 0) {
+                av_packet_unref(&input_ref);
+                return ret;
+            }
+
+            ret = av_bsf_receive_packet(s->bsf, &s->pkt_filtered);
+            if (ret < 0)
+                av_packet_move_ref(&s->pkt_filtered, &input_ref);
+            else
+                av_packet_unref(&input_ref);
+        }
+
+        state = (*s->decoder)->DecodeFrame2(s->decoder, s->pkt_filtered.data, 
s->pkt_filtered.size, ptrs, &info);
+        s->pkt_filtered.size = 0;
+        if (state != dsErrorFree) {
+            av_log(avctx, AV_LOG_ERROR, "DecodeFrame2 failed\n");
+            return AVERROR_UNKNOWN;
+        }
+        if (info.iBufferStatus != 1) {
+            av_log(avctx, AV_LOG_DEBUG, "No frame produced\n");
+            continue;
+        }
+
+        avctx->width = info.UsrData.sSystemBuffer.iWidth;
+        avctx->height = info.UsrData.sSystemBuffer.iHeight;
+        if (ff_get_buffer(avctx, avframe, 0) < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Unable to allocate buffer\n");
+            return AVERROR(ENOMEM);
+        }
+
+        linesize[0] = info.UsrData.sSystemBuffer.iStride[0];
+        linesize[1] = linesize[2] = info.UsrData.sSystemBuffer.iStride[1];
+        av_image_copy(avframe->data, avframe->linesize, (const uint8_t **) ptrs, 
linesize, avctx->pix_fmt, avctx->width, avctx->height);
+
+        avframe->pts     = s->pkt_filtered.pts;
+        avframe->pkt_dts = s->pkt_filtered.dts;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+        avframe->pkt_pts = s->pkt_filtered.pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+        *got_frame = 1;
+    }
+    return avpkt->size;
+}
+
+AVCodec ff_libopenh264_decoder = {
+    .name           = "libopenh264",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_H264,
+    .priv_data_size = sizeof(SVCContext),
+    .init           = svc_decode_init,
+    .decode         = svc_decode_frame,
+    .close          = svc_decode_close,
+    .long_name      = NULL_IF_CONFIG_SMALL("OpenH264"),
+    .capabilities   = AV_CODEC_CAP_DELAY, // The decoder itself doesn't have 
delay, but the BSF might

It does call ff_get_buffer(), so it should be flagged as DR I think.
Even though it's not "proper" DR.

Hmm, good point. If not setting the flags, the avframe would be allocated and filled locally, right?

I guess I could do that as well (pointing to the buffers returned by the decoder); would the refcounting take care of duplicating it in case the caller wants to retain it past the next decode call?

// Martin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to