History

nut: Support experimental NUT 4 features

Add the low overhead pipe mode and the extended broadcast mode. Export the options as 'syncponts' since it impacts only that.

Luca Barbato committed 12 years ago

Commit c94e2e81 parent 6d212595 files · +112 −9Browse files

Unified · Split

5 files
  1. doc/muxers.texi +17 −0
  2. doc/nut.texi +21 −0
  3. libavformat/nut.h +8 −1
  4. libavformat/nutdec.c +24 −5
  5. libavformat/nutenc.c +42 −3
doc/muxers.texi+17−0
@@ -444,6 +444,23 @@ Alternatively you can write the command as: · 443 unmodified lines
444444 avconv -benchmark -i INPUT -f null -
445445 @end example
446446
447+@section nut
448+
449+@table @option
450+@item -syncpoints @var{flags}
451+Change the syncpoint usage in nut:
452+@table @option
453+@item @var{default} use the normal low-overhead seeking aids.
454+@item @var{none} do not use the syncpoints at all, reducing the overhead but making the stream non-seekable;
455+@item @var{timestamped} extend the syncpoint with a wallclock field.
456+@end table
457+The @var{none} and @var{timestamped} flags are experimental.
458+@end table
459+
460+@example
461+avconv -i INPUT -f_strict experimental -syncpoints none - | processor
462+@end example
463+
447464 @section ogg
448465
449466 Ogg container muxer.
doc/nut.texi+21−0
@@ -17,6 +17,27 @@ subtitle and user-defined streams in a simple, yet efficient, way. · 16 unmodified lines
1717 It was created by a group of FFmpeg and MPlayer developers in 2003
1818 and was finalized in 2008.
1919
20+@chapter Modes
21+NUT has some variants signaled by using the flags field in its main header.
22+
23+@multitable @columnfractions .4 .4
24+@item BROADCAST @tab Extend the syncpoint to report the sender wallclock
25+@item PIPE @tab Omit completely the syncpoint
26+@end multitable
27+
28+@section BROADCAST
29+
30+The BROADCAST variant provides a secondary time reference to facilitate
31+detecting endpoint latency and network delays.
32+It assumes all the endpoint clocks are syncronized.
33+To be used in real-time scenarios.
34+
35+@section PIPE
36+
37+The PIPE variant assumes NUT is used as non-seekable intermediate container,
38+by not using syncpoint removes unneeded overhead and reduces the overall
39+memory usage.
40+
2041 @chapter Container-specific codec tags
2142
2243 @section Generic raw YUVA formats
libavformat/nut.h+8−1
@@ -36,7 +36,9 @@ · 35 unmodified lines
3636
3737 #define MAX_DISTANCE (1024*32-1)
3838
39−#define NUT_VERSION 3
39+#define NUT_MAX_VERSION 4
40+#define NUT_STABLE_VERSION 3
41+#define NUT_MIN_VERSION 2
4042
4143 typedef enum{
4244 FLAG_KEY = 1, ///<if set, frame is keyframe
@@ -85,6 +87,7 @@ typedef struct ChapterContext { · 42 unmodified lines
8587 } ChapterContext;
8688
8789 typedef struct NUTContext {
90+ const AVClass *av_class;
8891 AVFormatContext *avf;
8992 // int written_packet_size;
9093 // int64_t packet_start;
@@ -100,6 +103,10 @@ typedef struct NUTContext { · 9 unmodified lines
100103 int header_count;
101104 AVRational *time_base;
102105 struct AVTreeNode *syncpoints;
106+#define NUT_BROADCAST 1 // use extended syncpoints
107+#define NUT_PIPE 2 // do not write syncpoints
108+ int flags;
109+ int version; // version currently in use
103110 } NUTContext;
104111
105112 extern const AVCodecTag ff_nut_subtitle_tags[];
libavformat/nutdec.c+24−5
@@ -213,8 +213,8 @@ static int decode_main_header(NUTContext *nut) · 212 unmodified lines
213213 end = get_packetheader(nut, bc, 1, MAIN_STARTCODE);
214214 end += avio_tell(bc);
215215
216− tmp = ffio_read_varlen(bc);
217− if (tmp < 2 && tmp > NUT_VERSION) {
216+ nut->version = ffio_read_varlen(bc);
217+ if (tmp < NUT_MIN_VERSION && tmp > NUT_MAX_VERSION) {
218218 av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n",
219219 tmp);
220220 return AVERROR(ENOSYS);
@@ -320,6 +320,11 @@ static int decode_main_header(NUTContext *nut) · 99 unmodified lines
320320 assert(nut->header_len[0] == 0);
321321 }
322322
323+ // flags had been effectively introduced in version 4
324+ if (nut->version > NUT_STABLE_VERSION) {
325+ nut->flags = ffio_read_varlen(bc);
326+ }
327+
323328 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
324329 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");
325330 return AVERROR_INVALIDDATA;
@@ -547,6 +552,14 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) · 221 unmodified lines
547552 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],
548553 tmp / nut->time_base_count);
549554
555+ if (nut->flags & NUT_BROADCAST) {
556+ tmp = ffio_read_varlen(bc);
557+ av_log(s, AV_LOG_VERBOSE, "Syncpoint wallclock %"PRId64"\n",
558+ av_rescale_q(tmp / nut->time_base_count,
559+ nut->time_base[tmp % nut->time_base_count],
560+ AV_TIME_BASE_Q));
561+ }
562+
550563 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
551564 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
552565 return AVERROR_INVALIDDATA;
@@ -728,7 +741,8 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, · 175 unmodified lines
728741 int size, flags, size_mul, pts_delta, i, reserved_count;
729742 uint64_t tmp;
730743
731− if (avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) {
744+ if (!(nut->flags & NUT_PIPE) &&
745+ avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) {
732746 av_log(s, AV_LOG_ERROR,
733747 "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n",
734748 avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance);
@@ -781,8 +795,9 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, · 46 unmodified lines
781795
782796 if (flags & FLAG_CHECKSUM) {
783797 avio_rb32(bc); // FIXME check this
784− } else if (size > 2 * nut->max_distance || FFABS(stc->last_pts - *pts) >
785− stc->max_pts_distance) {
798+ } else if (!(nut->flags & NUT_PIPE) &&
799+ size > 2 * nut->max_distance ||
800+ FFABS(stc->last_pts - *pts) > stc->max_pts_distance) {
786801 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");
787802 return AVERROR_INVALIDDATA;
788803 }
@@ -933,6 +948,10 @@ static int read_seek(AVFormatContext *s, int stream_index, · 144 unmodified lines
933948 int64_t pos, pos2, ts;
934949 int i;
935950
951+ if (nut->flags & NUT_PIPE) {
952+ return AVERROR(ENOSYS);
953+ }
954+
936955 if (st->index_entries) {
937956 int index = av_index_search_timestamp(st, pts, flags);
938957 if (index < 0)
libavformat/nutenc.c+42−3
@@ -25,6 +25,8 @@ · 24 unmodified lines
2525 #include "libavutil/mathematics.h"
2626 #include "libavutil/tree.h"
2727 #include "libavutil/dict.h"
28+#include "libavutil/time.h"
29+#include "libavutil/opt.h"
2830 #include "libavcodec/mpegaudiodata.h"
2931 #include "nut.h"
3032 #include "internal.h"
@@ -325,7 +327,7 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) · 294 unmodified lines
325327 tmp_head_idx;
326328 int64_t tmp_match;
327329
328− ff_put_v(bc, NUT_VERSION);
330+ ff_put_v(bc, nut->version);
329331 ff_put_v(bc, nut->avf->nb_streams);
330332 ff_put_v(bc, nut->max_distance);
331333 ff_put_v(bc, nut->time_base_count);
@@ -405,6 +407,9 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) · 73 unmodified lines
405407 ff_put_v(bc, nut->header_len[i]);
406408 avio_write(bc, nut->header[i], nut->header_len[i]);
407409 }
410+ // flags had been effectively introduced in version 4
411+ if (nut->version > NUT_STABLE_VERSION)
412+ ff_put_v(bc, nut->flags);
408413 }
409414
410415 static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
@@ -643,6 +648,16 @@ static int nut_write_header(AVFormatContext *s) · 232 unmodified lines
643648
644649 nut->avf = s;
645650
651+ nut->version = NUT_STABLE_VERSION + !!nut->flags;
652+ if (nut->flags && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
653+ av_log(s, AV_LOG_ERROR,
654+ "The additional syncpoint modes require version %d, "
655+ "that is currently not finalized, "
656+ "please set -f_strict experimental in order to enable it.\n",
657+ nut->version);
658+ return AVERROR_EXPERIMENTAL;
659+ }
660+
646661 nut->stream = av_mallocz(sizeof(StreamContext) * s->nb_streams);
647662 if (s->nb_chapters)
648663 nut->chapter = av_mallocz(sizeof(ChapterContext) * s->nb_chapters);
@@ -789,7 +804,8 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) · 140 unmodified lines
789804
790805 //FIXME: Ensure store_sp is 1 in the first place.
791806
792− if (store_sp) {
807+ if (store_sp &&
808+ (!(nut->flags & NUT_PIPE) || nut->last_syncpoint_pos == INT_MIN)) {
793809 Syncpoint *sp, dummy = { .pos = INT64_MAX };
794810
795811 ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);
@@ -815,6 +831,11 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) · 19 unmodified lines
815831 return ret;
816832 put_tt(nut, nus->time_base, dyn_bc, pkt->dts);
817833 ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);
834+
835+ if (nut->flags & NUT_BROADCAST) {
836+ put_tt(nut, nus->time_base, dyn_bc,
837+ av_rescale_q(av_gettime(), AV_TIME_BASE_Q, *nus->time_base));
838+ }
818839 put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
819840
820841 if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
@@ -917,7 +938,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) · 96 unmodified lines
917938 nus->last_pts = pkt->pts;
918939
919940 //FIXME just store one per syncpoint
920− if (flags & FLAG_KEY)
941+ if (flags & FLAG_KEY && !(nut->flags & NUT_PIPE))
921942 av_add_index_entry(
922943 s->streams[pkt->stream_index],
923944 nut->last_syncpoint_pos,
@@ -945,6 +966,23 @@ static int nut_write_trailer(AVFormatContext *s) · 21 unmodified lines
945966 return 0;
946967 }
947968
969+#define OFFSET(x) offsetof(NUTContext, x)
970+#define E AV_OPT_FLAG_ENCODING_PARAM
971+static const AVOption options[] = {
972+ { "syncpoints", "NUT syncpoint behaviour", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, E, "syncpoints" },
973+ { "default", "", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, E, "syncpoints" },
974+ { "none", "Disable syncpoints, low overhead and unseekable", 0, AV_OPT_TYPE_CONST, {.i64 = NUT_PIPE}, INT_MIN, INT_MAX, E, "syncpoints" },
975+ { "timestamped", "Extend syncpoints with a wallclock timestamp", 0, AV_OPT_TYPE_CONST, {.i64 = NUT_BROADCAST}, INT_MIN, INT_MAX, E, "syncpoints" },
976+ { NULL },
977+};
978+
979+static const AVClass class = {
980+ .class_name = "nutenc",
981+ .item_name = av_default_item_name,
982+ .option = options,
983+ .version = LIBAVUTIL_VERSION_INT,
984+};
985+
948986 AVOutputFormat ff_nut_muxer = {
949987 .name = "nut",
950988 .long_name = NULL_IF_CONFIG_SMALL("NUT"),
@@ -959,4 +997,5 @@ AVOutputFormat ff_nut_muxer = { · 8 unmodified lines
959997 .write_trailer = nut_write_trailer,
960998 .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
961999 .codec_tag = ff_nut_codec_tags,
1000+ .priv_class = &class,
9621001 };

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