History

Merge commit 'c94e2e85cb6af8a570d8542a830556243bd32873'

* commit 'c94e2e85cb6af8a570d8542a830556243bd32873': nut: Support experimental NUT 4 features Conflicts: doc/nut.texi libavformat/nut.h libavformat/nutdec.c libavformat/nutenc.c

Michael Niedermayer committed 12 years ago

Commit a8499cb2 parents d858ee7 c94e2e85 files · +111 −9Browse files

Unified · Split

5 files
  1. doc/muxers.texi +17 −0
  2. doc/nut.texi +21 −0
  3. libavformat/nut.h +8 −2
  4. libavformat/nutdec.c +23 −4
  5. libavformat/nutenc.c +42 −3
doc/muxers.texi+17−0
@@ -706,6 +706,23 @@ Alternatively you can write the command as: · 705 unmodified lines
706ffmpeg -benchmark -i INPUT -f null -706ffmpeg -benchmark -i INPUT -f null -
707@end example707@end example
708 708
709@section nut
710
711@table @option
712@item -syncpoints @var{flags}
713Change the syncpoint usage in nut:
714@table @option
715@item @var{default} use the normal low-overhead seeking aids.
716@item @var{none} do not use the syncpoints at all, reducing the overhead but making the stream non-seekable;
717@item @var{timestamped} extend the syncpoint with a wallclock field.
718@end table
719The @var{none} and @var{timestamped} flags are experimental.
720@end table
721
722@example
723ffmpeg -i INPUT -f_strict experimental -syncpoints none - | processor
724@end example
725
709@section ogg726@section ogg
710 727
711Ogg container muxer.728Ogg container muxer.
doc/nut.texi+21−0
@@ -21,6 +21,27 @@ The official nut specification is at svn://svn.mplayerhq.hu/nut · 20 unmodified lines
21In case of any differences between this text and the official specification,21In case of any differences between this text and the official specification,
22the official specification shall prevail.22the official specification shall prevail.
23 23
24@chapter Modes
25NUT has some variants signaled by using the flags field in its main header.
26
27@multitable @columnfractions .4 .4
28@item BROADCAST @tab Extend the syncpoint to report the sender wallclock
29@item PIPE @tab Omit completely the syncpoint
30@end multitable
31
32@section BROADCAST
33
34The BROADCAST variant provides a secondary time reference to facilitate
35detecting endpoint latency and network delays.
36It assumes all the endpoint clocks are syncronized.
37To be used in real-time scenarios.
38
39@section PIPE
40
41The PIPE variant assumes NUT is used as non-seekable intermediate container,
42by not using syncpoint removes unneeded overhead and reduces the overall
43memory usage.
44
24@chapter Container-specific codec tags45@chapter Container-specific codec tags
25 46
26@section Generic raw YUVA formats47@section Generic raw YUVA formats
libavformat/nut.h+8−2
@@ -36,7 +36,9 @@ · 35 unmodified lines
36 36
37#define MAX_DISTANCE (1024*32-1)37#define MAX_DISTANCE (1024*32-1)
38 38
39#define NUT_VERSION 339#define NUT_MAX_VERSION 4
40#define NUT_STABLE_VERSION 3
41#define NUT_MIN_VERSION 2
40 42
41typedef enum{43typedef enum{
42 FLAG_KEY = 1, ///<if set, frame is keyframe44 FLAG_KEY = 1, ///<if set, frame is keyframe
@@ -87,6 +89,7 @@ typedef struct ChapterContext { · 44 unmodified lines
87} ChapterContext;89} ChapterContext;
88 90
89typedef struct NUTContext {91typedef struct NUTContext {
92 const AVClass *av_class;
90 AVFormatContext *avf;93 AVFormatContext *avf;
91// int written_packet_size;94// int written_packet_size;
92// int64_t packet_start;95// int64_t packet_start;
@@ -105,7 +108,10 @@ typedef struct NUTContext { · 12 unmodified lines
105 int sp_count;108 int sp_count;
106 int64_t max_pts;109 int64_t max_pts;
107 AVRational *max_pts_tb;110 AVRational *max_pts_tb;
108 int version;111#define NUT_BROADCAST 1 // use extended syncpoints
112#define NUT_PIPE 2 // do not write syncpoints
113 int flags;
114 int version; // version currently in use
109 int minor_version;115 int minor_version;
110} NUTContext;116} NUTContext;
111 117
libavformat/nutdec.c+23−4
@@ -229,7 +229,7 @@ static int decode_main_header(NUTContext *nut) · 228 unmodified lines
229 end += avio_tell(bc);229 end += avio_tell(bc);
230 230
231 tmp = ffio_read_varlen(bc);231 tmp = ffio_read_varlen(bc);
232 if (tmp < 2 && tmp > 4) {232 if (tmp < NUT_MIN_VERSION && tmp > NUT_MAX_VERSION) {
233 av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n",233 av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n",
234 tmp);234 tmp);
235 return AVERROR(ENOSYS);235 return AVERROR(ENOSYS);
@@ -340,6 +340,11 @@ static int decode_main_header(NUTContext *nut) · 104 unmodified lines
340 av_assert0(nut->header_len[0] == 0);340 av_assert0(nut->header_len[0] == 0);
341 }341 }
342 342
343 // flags had been effectively introduced in version 4
344 if (nut->version > NUT_STABLE_VERSION) {
345 nut->flags = ffio_read_varlen(bc);
346 }
347
343 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {348 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
344 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");349 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");
345 return AVERROR_INVALIDDATA;350 return AVERROR_INVALIDDATA;
@@ -578,6 +583,14 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) · 232 unmodified lines
578 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],583 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],
579 tmp / nut->time_base_count);584 tmp / nut->time_base_count);
580 585
586 if (nut->flags & NUT_BROADCAST) {
587 tmp = ffio_read_varlen(bc);
588 av_log(s, AV_LOG_VERBOSE, "Syncpoint wallclock %"PRId64"\n",
589 av_rescale_q(tmp / nut->time_base_count,
590 nut->time_base[tmp % nut->time_base_count],
591 AV_TIME_BASE_Q));
592 }
593
581 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {594 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
582 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");595 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
583 return AVERROR_INVALIDDATA;596 return AVERROR_INVALIDDATA;
@@ -898,7 +911,8 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, · 314 unmodified lines
898 int size, flags, size_mul, pts_delta, i, reserved_count;911 int size, flags, size_mul, pts_delta, i, reserved_count;
899 uint64_t tmp;912 uint64_t tmp;
900 913
901 if (avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) {914 if (!(nut->flags & NUT_PIPE) &&
915 avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) {
902 av_log(s, AV_LOG_ERROR,916 av_log(s, AV_LOG_ERROR,
903 "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n",917 "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n",
904 avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance);918 avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance);
@@ -951,8 +965,9 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, · 46 unmodified lines
951 965
952 if (flags & FLAG_CHECKSUM) {966 if (flags & FLAG_CHECKSUM) {
953 avio_rb32(bc); // FIXME check this967 avio_rb32(bc); // FIXME check this
954 } else if (size > 2 * nut->max_distance || FFABS(stc->last_pts - *pts) >968 } else if (!(nut->flags & NUT_PIPE) &&
955 stc->max_pts_distance) {969 size > 2 * nut->max_distance ||
970 FFABS(stc->last_pts - *pts) > stc->max_pts_distance) {
956 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");971 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");
957 return AVERROR_INVALIDDATA;972 return AVERROR_INVALIDDATA;
958 }973 }
@@ -1118,6 +1133,10 @@ static int read_seek(AVFormatContext *s, int stream_index, · 159 unmodified lines
1118 int64_t pos, pos2, ts;1133 int64_t pos, pos2, ts;
1119 int i;1134 int i;
1120 1135
1136 if (nut->flags & NUT_PIPE) {
1137 return AVERROR(ENOSYS);
1138 }
1139
1121 if (st->index_entries) {1140 if (st->index_entries) {
1122 int index = av_index_search_timestamp(st, pts, flags);1141 int index = av_index_search_timestamp(st, pts, flags);
1123 if (index < 0)1142 if (index < 0)
libavformat/nutenc.c+42−3
@@ -26,6 +26,8 @@ · 25 unmodified lines
26#include "libavutil/tree.h"26#include "libavutil/tree.h"
27#include "libavutil/dict.h"27#include "libavutil/dict.h"
28#include "libavutil/avassert.h"28#include "libavutil/avassert.h"
29#include "libavutil/time.h"
30#include "libavutil/opt.h"
29#include "libavcodec/bytestream.h"31#include "libavcodec/bytestream.h"
30#include "libavcodec/mpegaudiodata.h"32#include "libavcodec/mpegaudiodata.h"
31#include "nut.h"33#include "nut.h"
@@ -338,7 +340,7 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) · 306 unmodified lines
338 tmp_head_idx;340 tmp_head_idx;
339 int64_t tmp_match;341 int64_t tmp_match;
340 342
341 ff_put_v(bc, nut->version = NUT_VERSION);343 ff_put_v(bc, nut->version);
342 if (nut->version > 3)344 if (nut->version > 3)
343 ff_put_v(bc, nut->minor_version);345 ff_put_v(bc, nut->minor_version);
344 ff_put_v(bc, nut->avf->nb_streams);346 ff_put_v(bc, nut->avf->nb_streams);
@@ -407,6 +409,9 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) · 62 unmodified lines
407 ff_put_v(bc, nut->header_len[i]);409 ff_put_v(bc, nut->header_len[i]);
408 avio_write(bc, nut->header[i], nut->header_len[i]);410 avio_write(bc, nut->header[i], nut->header_len[i]);
409 }411 }
412 // flags had been effectively introduced in version 4
413 if (nut->version > NUT_STABLE_VERSION)
414 ff_put_v(bc, nut->flags);
410}415}
411 416
412static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,417static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
@@ -692,6 +697,16 @@ static int nut_write_header(AVFormatContext *s) · 279 unmodified lines
692 697
693 nut->avf = s;698 nut->avf = s;
694 699
700 nut->version = NUT_STABLE_VERSION + !!nut->flags;
701 if (nut->flags && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
702 av_log(s, AV_LOG_ERROR,
703 "The additional syncpoint modes require version %d, "
704 "that is currently not finalized, "
705 "please set -f_strict experimental in order to enable it.\n",
706 nut->version);
707 return AVERROR_EXPERIMENTAL;
708 }
709
695 nut->stream = av_calloc(s->nb_streams, sizeof(*nut->stream ));710 nut->stream = av_calloc(s->nb_streams, sizeof(*nut->stream ));
696 nut->chapter = av_calloc(s->nb_chapters, sizeof(*nut->chapter));711 nut->chapter = av_calloc(s->nb_chapters, sizeof(*nut->chapter));
697 nut->time_base= av_calloc(s->nb_streams +712 nut->time_base= av_calloc(s->nb_streams +
@@ -974,7 +989,8 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) · 276 unmodified lines
974 989
975//FIXME: Ensure store_sp is 1 in the first place.990//FIXME: Ensure store_sp is 1 in the first place.
976 991
977 if (store_sp) {992 if (store_sp &&
993 (!(nut->flags & NUT_PIPE) || nut->last_syncpoint_pos == INT_MIN)) {
978 Syncpoint *sp, dummy = { .pos = INT64_MAX };994 Syncpoint *sp, dummy = { .pos = INT64_MAX };
979 995
980 ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);996 ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);
@@ -1000,6 +1016,11 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) · 19 unmodified lines
1000 return ret;1016 return ret;
1001 put_tt(nut, nus->time_base, dyn_bc, pkt->dts);1017 put_tt(nut, nus->time_base, dyn_bc, pkt->dts);
1002 ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);1018 ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);
1019
1020 if (nut->flags & NUT_BROADCAST) {
1021 put_tt(nut, nus->time_base, dyn_bc,
1022 av_rescale_q(av_gettime(), AV_TIME_BASE_Q, *nus->time_base));
1023 }
1003 put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);1024 put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
1004 1025
1005 if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)1026 if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
@@ -1110,7 +1131,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) · 104 unmodified lines
1110 nus->last_pts = pkt->pts;1131 nus->last_pts = pkt->pts;
1111 1132
1112 //FIXME just store one per syncpoint1133 //FIXME just store one per syncpoint
1113 if (flags & FLAG_KEY) {1134 if (flags & FLAG_KEY && !(nut->flags & NUT_PIPE)) {
1114 av_add_index_entry(1135 av_add_index_entry(
1115 s->streams[pkt->stream_index],1136 s->streams[pkt->stream_index],
1116 nut->last_syncpoint_pos,1137 nut->last_syncpoint_pos,
@@ -1156,6 +1177,23 @@ static int nut_write_trailer(AVFormatContext *s) · 39 unmodified lines
1156 return 0;1177 return 0;
1157}1178}
1158 1179
1180#define OFFSET(x) offsetof(NUTContext, x)
1181#define E AV_OPT_FLAG_ENCODING_PARAM
1182static const AVOption options[] = {
1183 { "syncpoints", "NUT syncpoint behaviour", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, E, "syncpoints" },
1184 { "default", "", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, E, "syncpoints" },
1185 { "none", "Disable syncpoints, low overhead and unseekable", 0, AV_OPT_TYPE_CONST, {.i64 = NUT_PIPE}, INT_MIN, INT_MAX, E, "syncpoints" },
1186 { "timestamped", "Extend syncpoints with a wallclock timestamp", 0, AV_OPT_TYPE_CONST, {.i64 = NUT_BROADCAST}, INT_MIN, INT_MAX, E, "syncpoints" },
1187 { NULL },
1188};
1189
1190static const AVClass class = {
1191 .class_name = "nutenc",
1192 .item_name = av_default_item_name,
1193 .option = options,
1194 .version = LIBAVUTIL_VERSION_INT,
1195};
1196
1159AVOutputFormat ff_nut_muxer = {1197AVOutputFormat ff_nut_muxer = {
1160 .name = "nut",1198 .name = "nut",
1161 .long_name = NULL_IF_CONFIG_SMALL("NUT"),1199 .long_name = NULL_IF_CONFIG_SMALL("NUT"),
@@ -1170,4 +1208,5 @@ AVOutputFormat ff_nut_muxer = { · 8 unmodified lines
1170 .write_trailer = nut_write_trailer,1208 .write_trailer = nut_write_trailer,
1171 .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,1209 .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
1172 .codec_tag = ff_nut_codec_tags,1210 .codec_tag = ff_nut_codec_tags,
1211 .priv_class = &class,
1173};1212};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t