[FFmpeg-devel] [PATCH 2/2] lavd/lavfi: allow to extract subcc.

Anshul anshul.ffmpeg at gmail.com
Fri Mar 14 20:19:22 CET 2014



Nicolas George <george at nsup.org> wrote:
>Signed-off-by: Nicolas George <george at nsup.org>
>---
> doc/indevs.texi     |  9 ++++++
>libavdevice/lavfi.c | 80
>+++++++++++++++++++++++++++++++++++++++++++++++++----
> 2 files changed, 84 insertions(+), 5 deletions(-)
>
>
>With this patch, it becomes possible to dump the subcc data, just like
>Anshul's program did, using the ffmpeg command-line tool.
>
>With a decoder, hopefully, it would be possible to use them like any
>kind of
>text subtitles.
>
>It requires using "-f lavfi -i movie=file" instead of just "-i file". I
>am
>not sure what the long term solution would be: implementing that really
>at
>the demuxer level, including frame reordering, or acknowledging that
>the
>protocol/demuxer/decoder stack model is too limited for some features
>(including, but not limited to, this one) and move to a more general
>model,
>possibly based on complex graphs.
>
>
>diff --git a/doc/indevs.texi b/doc/indevs.texi
>index 93fbbe8..cf948c6 100644
>--- a/doc/indevs.texi
>+++ b/doc/indevs.texi
>@@ -324,6 +324,9 @@ number starting from 0 corresponding to the mapped
>input stream
> generated by the device.
> The first unlabelled output is automatically assigned to the "out0"
> label, but all the others need to be specified explicitly.
>+The suffix "+subcc" can be appended to the output label to create an
>extra
>+stream with the closed captions packets attached to that output
>+(experimental).
> 
> If not specified defaults to the filename specified for the input
> device.
>@@ -371,6 +374,12 @@ Read an audio stream and a video stream and play
>it back with
> ffplay -f lavfi "movie=test.avi[out0];amovie=test.wav[out1]"
> @end example
> 
>+ at item
>+Dump decoded frames to images and closed captions to a file
>(experimental):
>+ at example
>+ffmpeg -f lavfi -i "movie=test.ts[out0+subcc]" -map v frame%08d.png
>-map s -c copy -f rawvideo subcc.bin
>+ at end example
>+
> @end itemize
> 
> @section libdc1394
>diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c
>index 1ea7ea7..83fe490 100644
>--- a/libavdevice/lavfi.c
>+++ b/libavdevice/lavfi.c
>@@ -51,7 +51,10 @@ typedef struct {
>     int *sink_stream_map;
>     int *sink_eof;
>     int *stream_sink_map;
>+    int *sink_stream_subcc_map;
>     AVFrame *decoded_frame;
>+    int nb_sinks;
>+    AVPacket subcc_packet;
> } LavfiContext;
> 
> static int *create_all_formats(int n)
>@@ -82,6 +85,7 @@ av_cold static int lavfi_read_close(AVFormatContext
>*avctx)
>     av_freep(&lavfi->sink_stream_map);
>     av_freep(&lavfi->sink_eof);
>     av_freep(&lavfi->stream_sink_map);
>+    av_freep(&lavfi->sink_stream_subcc_map);
>     av_freep(&lavfi->sinks);
>     avfilter_graph_free(&lavfi->graph);
>     av_frame_free(&lavfi->decoded_frame);
>@@ -89,6 +93,27 @@ av_cold static int lavfi_read_close(AVFormatContext
>*avctx)
>     return 0;
> }
> 
>+static int create_subcc_streams(AVFormatContext *avctx)
>+{
>+    LavfiContext *lavfi = avctx->priv_data;
>+    AVStream *st;
>+    int stream_idx, sink_idx;
>+
>+    for (stream_idx = 0; stream_idx < lavfi->nb_sinks; stream_idx++) {
>+        sink_idx = lavfi->stream_sink_map[stream_idx];
>+        if (lavfi->sink_stream_subcc_map[sink_idx]) {
>+            lavfi->sink_stream_subcc_map[sink_idx] =
>avctx->nb_streams;
>+            if (!(st = avformat_new_stream(avctx, NULL)))
>+                return AVERROR(ENOMEM);
>+            st->codec->codec_id = AV_CODEC_ID_CEA_708;
>+            st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
>+        } else {
>+            lavfi->sink_stream_subcc_map[sink_idx] = -1;
>+        }
>+    }
>+    return 0;
>+}
>+
> av_cold static int lavfi_read_header(AVFormatContext *avctx)
> {
>     LavfiContext *lavfi = avctx->priv_data;
>@@ -153,6 +178,7 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
> 
>     /* count the outputs */
>    for (n = 0, inout = output_links; inout; n++, inout = inout->next);
>+    lavfi->nb_sinks = n;
> 
>     if (!(lavfi->sink_stream_map = av_malloc(sizeof(int) * n)))
>         FAIL(AVERROR(ENOMEM));
>@@ -160,6 +186,8 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
>         FAIL(AVERROR(ENOMEM));
>     if (!(lavfi->stream_sink_map = av_malloc(sizeof(int) * n)))
>         FAIL(AVERROR(ENOMEM));
>+    if (!(lavfi->sink_stream_subcc_map = av_malloc(sizeof(int) * n)))
>+        FAIL(AVERROR(ENOMEM));
> 
>     for (i = 0; i < n; i++)
>         lavfi->stream_sink_map[i] = -1;
>@@ -167,10 +195,10 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
>/* parse the output link names - they need to be of the form out0,
>out1, ...
>      * create a mapping between them and the streams */
>   for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
>-        int stream_idx;
>+        int stream_idx, use_subcc = 0;
>         if (!strcmp(inout->name, "out"))
>             stream_idx = 0;
>-        else if (sscanf(inout->name, "out%d\n", &stream_idx) != 1) {
>+        else if (sscanf(inout->name, "out%d+subcc%n\n", &stream_idx,
>&use_subcc) != 1) {
>             av_log(avctx,  AV_LOG_ERROR,
>                    "Invalid outpad name '%s'\n", inout->name);
>             FAIL(AVERROR(EINVAL));
>@@ -200,6 +228,7 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
>         }
>         lavfi->sink_stream_map[i] = stream_idx;
>         lavfi->stream_sink_map[stream_idx] = i;
>+        lavfi->sink_stream_subcc_map[i] = !!use_subcc;
>     }
> 
>     /* for each open output create a corresponding stream */
>@@ -211,7 +240,7 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
>     }
> 
>     /* create a sink for each output and connect them to the graph */
>-    lavfi->sinks = av_malloc(sizeof(AVFilterContext *) *
>avctx->nb_streams);
>+    lavfi->sinks = av_malloc(sizeof(AVFilterContext *) *
>lavfi->nb_sinks);
>     if (!lavfi->sinks)
>         FAIL(AVERROR(ENOMEM));
> 
>@@ -271,7 +300,7 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
>     }
> 
>  /* fill each stream with the information in the corresponding sink */
>-    for (i = 0; i < avctx->nb_streams; i++) {
>+    for (i = 0; i < lavfi->nb_sinks; i++) {
>AVFilterLink *link =
>lavfi->sinks[lavfi->stream_sink_map[i]]->inputs[0];
>         AVStream *st = avctx->streams[i];
>         st->codec->codec_type = link->type;
>@@ -302,6 +331,9 @@ av_cold static int
>lavfi_read_header(AVFormatContext *avctx)
>         }
>     }
> 
>+    if ((ret = create_subcc_streams(avctx)) < 0)
>+        FAIL(ret);
>+
>     if (!(lavfi->decoded_frame = av_frame_alloc()))
>         FAIL(AVERROR(ENOMEM));
> 
>@@ -314,6 +346,30 @@ end:
>     return ret;
> }
> 
>+static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame,
>+                               int sink_idx)
>+{
>+    LavfiContext *lavfi = avctx->priv_data;
>+    AVFrameSideData *sd;
>+    int stream_idx, i, ret;
>+
>+    if ((stream_idx = lavfi->sink_stream_subcc_map[sink_idx]) < 0)
>+        return 0;
>+    for (i = 0; i < frame->nb_side_data; i++)
>+        if (frame->side_data[i]->type == AV_FRAME_DATA_A53_CC)
>+            break;
>+    if (i >= frame->nb_side_data)
>+        return 0;
>+    sd = frame->side_data[i];
>+    if ((ret = av_new_packet(&lavfi->subcc_packet, sd->size)) < 0)
>+        return ret;
>+    memcpy(lavfi->subcc_packet.data, sd->data, sd->size);
>+    lavfi->subcc_packet.stream_index = stream_idx;
>+    lavfi->subcc_packet.pts = frame->pts;
>+    lavfi->subcc_packet.pos = av_frame_get_pkt_pos(frame);
>+    return 0;
>+}
>+
> static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
> {
>     LavfiContext *lavfi = avctx->priv_data;
>@@ -325,9 +381,17 @@ static int lavfi_read_packet(AVFormatContext
>*avctx, AVPacket *pkt)
>     int ret, i;
>     int size = 0;
> 
>+    if (lavfi->subcc_packet.size) {
>+        *pkt = lavfi->subcc_packet;
>+        av_init_packet(&lavfi->subcc_packet);
>+        lavfi->subcc_packet.size = 0;
>+        lavfi->subcc_packet.data = NULL;
>+        return pkt->size;
>+    }
>+
>     /* iterate through all the graph sinks. Select the sink with the
>      * minimum PTS */
>-    for (i = 0; i < avctx->nb_streams; i++) {
>+    for (i = 0; i < lavfi->nb_sinks; i++) {
>         AVRational tb = lavfi->sinks[i]->inputs[0]->time_base;
>         double d;
>         int ret;
>@@ -401,6 +465,12 @@ static int lavfi_read_packet(AVFormatContext
>*avctx, AVPacket *pkt)
>         av_bprint_finalize(&meta_buf, NULL);
>     }
> 
>+    if ((ret = create_subcc_packet(avctx, frame, min_pts_sink_idx)) <
>0) {
>+        av_frame_unref(frame);
>+        av_packet_unref(pkt);
>+        return ret;
>+    }
>+
>     pkt->stream_index = stream_idx;
>     pkt->pts = frame->pts;
>     pkt->pos = av_frame_get_pkt_pos(frame);


If no one have problem, please apply

-Anshul


More information about the ffmpeg-devel mailing list