Hi,

libavformat currently doesn't provide any mechanism for detecting when a
substream is no longer present but the stream as a whole is otherwise OK. Your
best guess is to check when you last got any frames on it, which tends to work
for video and audio but not for substreams that sometimes spend a long amount of
time without presenting anything, like subtitles.

I've attached my first attempt at a detection mechanism, implemented as an
AVSTREAM_EVENT_FLAG. Depending on the demultiplexer it's either raised when the
substream carrier has died (e.g. if you have one pipe per substream and that one
in particular broke), or if its presence wasn't detected during the last call to
av_read_frame. I've added it to the MPEG-TS demultiplexer as that's where it
itches, but I could see it being somewhat relevant for other formats as well.

Does this sound useful to anyone but me? If yes, can you think of a better way
of exposing this functionality?

Regards,
John Högberg
From 0f4183bf6f942df7fe7813e002b2697928acf937 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <[email protected]>
Date: Thu, 7 May 2015 14:24:27 +0200
Subject: [RFC] Add a stream event for detecting carrier loss.

AVSTREAM_EVENT_FLAG_NO_CARRIER: depending on the carrier type of the stream, it
either indicates that no carrier was detected for the stream during the latest
call, or that the carrier was lost. The former case is distinct from there being
no data, and is intended to be used for the detection of a common error in
in MPEG-TS; the lack of presence of a stream defined in the headers.
---
 libavformat/avformat.h | 21 +++++++++++++++++++++
 libavformat/mpegts.c   |  6 ++++++
 libavformat/utils.c    | 12 +++++++++++-
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index aa11cff..78cbe83 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -814,6 +814,27 @@ typedef struct AVStream {
      */
     int event_flags;
 #define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in 
updated metadata.
+#define AVSTREAM_EVENT_FLAG_NO_CARRIER       0x0002 ///< For constant carrier 
types, the carrier was lost during the
+                                                    ///  call. For 
intermittent carrier types, no carrier for this
+                                                    ///  stream was present 
during the call.
+
+    /**
+     * The kind of carrier this stream has. Used to determine how the 
NO_CARRIER
+     * event should be raised and cleared.
+     *
+     * Constant means that the stream is presumed to be present, and the event
+     * will be raised whenever the underlying demultiplexer has determined that
+     * this specific stream has lost its carrier. This is the default behavior.
+     *
+     * Intermittent means that the stream is presumed to be missing, and the
+     * event will be cleared when a carrier is present on this specific stream.
+     *
+     * demuxing/muxing: set by libavformat, must not be modified by the caller.
+     */
+    enum AVStreamCarrierType {
+        AVSTREAM_CARRIER_TYPE_CONSTANT = 0,
+        AVSTREAM_CARRIER_TYPE_INTERMITTENT,
+    } carrier_type;
 
     /*****************************************************************
      * All fields below this line are not part of the public API. They
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 8f61f17..6217e5e 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -652,6 +652,7 @@ static int mpegts_set_stream_info(AVStream *st, PESContext 
*pes,
     st->codec->codec_type = AVMEDIA_TYPE_DATA;
     st->codec->codec_id   = AV_CODEC_ID_NONE;
     st->need_parsing      = AVSTREAM_PARSE_FULL;
+    st->carrier_type      = AVSTREAM_CARRIER_TYPE_INTERMITTENT;
     pes->st          = st;
     pes->stream_type = stream_type;
 
@@ -840,6 +841,10 @@ static int mpegts_push_data(MpegTSFilter *filter,
                     av_log(pes->stream, AV_LOG_TRACE, "pid=%x pes_code=%#x\n", 
pes->pid,
                             code);
 
+                    if(pes->st) {
+                        pes->st->event_flags &= 
~AVSTREAM_EVENT_FLAG_NO_CARRIER;
+                    }
+
                     if ((pes->st && pes->st->discard == AVDISCARD_ALL &&
                          (!pes->sub_st ||
                           pes->sub_st->discard == AVDISCARD_ALL)) ||
@@ -1507,6 +1512,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, 
AVStream *st, int stream_type
     default:
         break;
     }
+
     *pp = desc_end;
     return 0;
 }
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 18cd0d7..72a4ad9 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -971,7 +971,7 @@ static int read_frame_internal(AVFormatContext *s, AVPacket 
*pkt)
 int av_read_frame(AVFormatContext *s, AVPacket *pkt)
 {
     const int genpts = s->flags & AVFMT_FLAG_GENPTS;
-    int eof = 0;
+    int eof = 0, i;
 
     if (!genpts)
         return s->internal->packet_buffer
@@ -979,6 +979,14 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
                                          &s->internal->packet_buffer_end, pkt)
                : read_frame_internal(s, pkt);
 
+    for (i = 0; i < s->nb_streams; i++) {
+        AVStream *st = s->streams[i];
+
+        if(st->carrier_type == AVSTREAM_CARRIER_TYPE_INTERMITTENT) {
+            st->event_flags |= AVSTREAM_EVENT_FLAG_NO_CARRIER;
+        }
+    }
+
     for (;;) {
         int ret;
         AVPacketList *pktl = s->internal->packet_buffer;
@@ -2559,6 +2567,8 @@ AVStream *avformat_new_stream(AVFormatContext *s, const 
AVCodec *c)
     st->info->fps_first_dts = AV_NOPTS_VALUE;
     st->info->fps_last_dts  = AV_NOPTS_VALUE;
 
+    st->carrier_type = AVSTREAM_CARRIER_TYPE_CONSTANT;
+
     s->streams[s->nb_streams++] = st;
     return st;
 }
-- 
2.1.0

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

Reply via email to