[FFmpeg-devel] [PATCH 2/2] avformat/microdvd: export the declared frame rate

wm4 nfxjfg at googlemail.com
Sun Mar 2 22:36:42 CET 2014


MicroDVD files are normally frame-based (i.e. there are no absolute
timestamps), but can have an optional frame rate header. If this
header is missing, the timestamps depend on the frame rate of the
video they were created for.

The demuxer will use a fallback frame rate if it's missing from the
header. Currently, applications using libavformat can't know whether
the time base is based on the fallback value, or if a frame rate
header was present.

This commit introduces a subfps AVOption for MicroDVD, and the
demuxer sets it if and only if a frame rate header was present.
---
 libavformat/microdvddec.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/libavformat/microdvddec.c b/libavformat/microdvddec.c
index 42c6de0..a705442 100644
--- a/libavformat/microdvddec.c
+++ b/libavformat/microdvddec.c
@@ -24,12 +24,15 @@
 #include "internal.h"
 #include "subtitles.h"
 #include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
 
 #define MAX_LINESIZE 2048
 
 
 typedef struct {
+    const AVClass *class;
     FFDemuxSubtitlesQueue q;
+    AVRational frame_rate;
 } MicroDVDContext;
 
 
@@ -80,6 +83,7 @@ static int microdvd_read_header(AVFormatContext *s)
     AVStream *st = avformat_new_stream(s, NULL);
     int i = 0;
     char line_buf[MAX_LINESIZE];
+    int has_real_fps = 0;
 
     if (!st)
         return AVERROR(ENOMEM);
@@ -105,8 +109,10 @@ static int microdvd_read_header(AVFormatContext *s)
 
             if ((sscanf(line, "{%d}{}%6lf",    &frame, &fps) == 2 ||
                  sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2)
-                && frame <= 1 && fps > 3 && fps < 100)
+                && frame <= 1 && fps > 3 && fps < 100) {
                 pts_info = av_d2q(fps, 100000);
+                has_real_fps = 1;
+            }
             if (!st->codec->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) {
                 st->codec->extradata = av_strdup(line + 11);
                 if (!st->codec->extradata)
@@ -135,6 +141,11 @@ static int microdvd_read_header(AVFormatContext *s)
         sub->duration = get_duration(line);
     }
     ff_subtitles_queue_finalize(&microdvd->q);
+    if (has_real_fps) {
+        microdvd->frame_rate = pts_info;
+    } else if (microdvd->frame_rate.num) {
+        pts_info = microdvd->frame_rate;
+    }
     avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num);
     st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
     st->codec->codec_id   = AV_CODEC_ID_MICRODVD;
@@ -162,6 +173,21 @@ static int microdvd_read_close(AVFormatContext *s)
     return 0;
 }
 
+
+#define OFFSET(x) offsetof(MicroDVDContext, x)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM
+static const AVOption microdvd_options[] = {
+    { "subfps", "set the movie frame rate", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, SD },
+    { NULL }
+};
+
+static const AVClass microdvd_class = {
+    .class_name = "microdvddec",
+    .item_name  = av_default_item_name,
+    .option     = microdvd_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 AVInputFormat ff_microdvd_demuxer = {
     .name           = "microdvd",
     .long_name      = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
@@ -171,4 +197,5 @@ AVInputFormat ff_microdvd_demuxer = {
     .read_packet    = microdvd_read_packet,
     .read_seek2     = microdvd_read_seek,
     .read_close     = microdvd_read_close,
+    .priv_class     = &microdvd_class,
 };
-- 
1.9.0



More information about the ffmpeg-devel mailing list