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

Michael Niedermayer michaelni at gmx.at
Fri Mar 14 23:14:00 CET 2014


On Sat, Mar 15, 2014 at 12:49:22AM +0530, Anshul wrote:
> 
> 
> 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

ill apply it when the author (nicolas) says i should

[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

In fact, the RIAA has been known to suggest that students drop out
of college or go to community college in order to be able to afford
settlements. -- The RIAA
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140314/734fd7d9/attachment.asc>


More information about the ffmpeg-devel mailing list