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
444avconv -benchmark -i INPUT -f null -444avconv -benchmark -i INPUT -f null -
445@end example445@end example
446 446
447@section nut
448
449@table @option
450@item -syncpoints @var{flags}
451Change 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
457The @var{none} and @var{timestamped} flags are experimental.
458@end table
459
460@example
461avconv -i INPUT -f_strict experimental -syncpoints none - | processor
462@end example
463
447@section ogg464@section ogg
448 465
449Ogg container muxer.466Ogg 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
17It was created by a group of FFmpeg and MPlayer developers in 200317It was created by a group of FFmpeg and MPlayer developers in 2003
18and was finalized in 2008.18and was finalized in 2008.
19 19
20@chapter Modes
21NUT 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
30The BROADCAST variant provides a secondary time reference to facilitate
31detecting endpoint latency and network delays.
32It assumes all the endpoint clocks are syncronized.
33To be used in real-time scenarios.
34
35@section PIPE
36
37The PIPE variant assumes NUT is used as non-seekable intermediate container,
38by not using syncpoint removes unneeded overhead and reduces the overall
39memory usage.
40
20@chapter Container-specific codec tags41@chapter Container-specific codec tags
21 42
22@section Generic raw YUVA formats43@section Generic raw YUVA formats
libavformat/nut.h+8−1
@@ -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
@@ -85,6 +87,7 @@ typedef struct ChapterContext { · 42 unmodified lines
85} ChapterContext;87} ChapterContext;
86 88
87typedef struct NUTContext {89typedef struct NUTContext {
90 const AVClass *av_class;
88 AVFormatContext *avf;91 AVFormatContext *avf;
89// int written_packet_size;92// int written_packet_size;
90// int64_t packet_start;93// int64_t packet_start;
@@ -100,6 +103,10 @@ typedef struct NUTContext { · 9 unmodified lines
100 int header_count;103 int header_count;
101 AVRational *time_base;104 AVRational *time_base;
102 struct AVTreeNode *syncpoints;105 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
103} NUTContext;110} NUTContext;
104 111
105extern const AVCodecTag ff_nut_subtitle_tags[];112extern 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
213 end = get_packetheader(nut, bc, 1, MAIN_STARTCODE);213 end = get_packetheader(nut, bc, 1, MAIN_STARTCODE);
214 end += avio_tell(bc);214 end += avio_tell(bc);
215 215
216 tmp = ffio_read_varlen(bc);216 nut->version = ffio_read_varlen(bc);
217 if (tmp < 2 && tmp > NUT_VERSION) {217 if (tmp < NUT_MIN_VERSION && tmp > NUT_MAX_VERSION) {
218 av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n",218 av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n",
219 tmp);219 tmp);
220 return AVERROR(ENOSYS);220 return AVERROR(ENOSYS);
@@ -320,6 +320,11 @@ static int decode_main_header(NUTContext *nut) · 99 unmodified lines
320 assert(nut->header_len[0] == 0);320 assert(nut->header_len[0] == 0);
321 }321 }
322 322
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
323 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {328 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
324 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");329 av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");
325 return AVERROR_INVALIDDATA;330 return AVERROR_INVALIDDATA;
@@ -547,6 +552,14 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) · 221 unmodified lines
547 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],552 ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],
548 tmp / nut->time_base_count);553 tmp / nut->time_base_count);
549 554
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
550 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {563 if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
551 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");564 av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
552 return AVERROR_INVALIDDATA;565 return AVERROR_INVALIDDATA;
@@ -728,7 +741,8 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, · 175 unmodified lines
728 int size, flags, size_mul, pts_delta, i, reserved_count;741 int size, flags, size_mul, pts_delta, i, reserved_count;
729 uint64_t tmp;742 uint64_t tmp;
730 743
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) {
732 av_log(s, AV_LOG_ERROR,746 av_log(s, AV_LOG_ERROR,
733 "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n",747 "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n",
734 avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance);748 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
781 795
782 if (flags & FLAG_CHECKSUM) {796 if (flags & FLAG_CHECKSUM) {
783 avio_rb32(bc); // FIXME check this797 avio_rb32(bc); // FIXME check this
784 } else if (size > 2 * nut->max_distance || FFABS(stc->last_pts - *pts) >798 } else if (!(nut->flags & NUT_PIPE) &&
785 stc->max_pts_distance) {799 size > 2 * nut->max_distance ||
800 FFABS(stc->last_pts - *pts) > stc->max_pts_distance) {
786 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");801 av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");
787 return AVERROR_INVALIDDATA;802 return AVERROR_INVALIDDATA;
788 }803 }
@@ -933,6 +948,10 @@ static int read_seek(AVFormatContext *s, int stream_index, · 144 unmodified lines
933 int64_t pos, pos2, ts;948 int64_t pos, pos2, ts;
934 int i;949 int i;
935 950
951 if (nut->flags & NUT_PIPE) {
952 return AVERROR(ENOSYS);
953 }
954
936 if (st->index_entries) {955 if (st->index_entries) {
937 int index = av_index_search_timestamp(st, pts, flags);956 int index = av_index_search_timestamp(st, pts, flags);
938 if (index < 0)957 if (index < 0)
libavformat/nutenc.c+42−3
@@ -25,6 +25,8 @@ · 24 unmodified lines
25#include "libavutil/mathematics.h"25#include "libavutil/mathematics.h"
26#include "libavutil/tree.h"26#include "libavutil/tree.h"
27#include "libavutil/dict.h"27#include "libavutil/dict.h"
28#include "libavutil/time.h"
29#include "libavutil/opt.h"
28#include "libavcodec/mpegaudiodata.h"30#include "libavcodec/mpegaudiodata.h"
29#include "nut.h"31#include "nut.h"
30#include "internal.h"32#include "internal.h"
@@ -325,7 +327,7 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) · 294 unmodified lines
325 tmp_head_idx;327 tmp_head_idx;
326 int64_t tmp_match;328 int64_t tmp_match;
327 329
328 ff_put_v(bc, NUT_VERSION);330 ff_put_v(bc, nut->version);
329 ff_put_v(bc, nut->avf->nb_streams);331 ff_put_v(bc, nut->avf->nb_streams);
330 ff_put_v(bc, nut->max_distance);332 ff_put_v(bc, nut->max_distance);
331 ff_put_v(bc, nut->time_base_count);333 ff_put_v(bc, nut->time_base_count);
@@ -405,6 +407,9 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) · 73 unmodified lines
405 ff_put_v(bc, nut->header_len[i]);407 ff_put_v(bc, nut->header_len[i]);
406 avio_write(bc, nut->header[i], nut->header_len[i]);408 avio_write(bc, nut->header[i], nut->header_len[i]);
407 }409 }
410 // flags had been effectively introduced in version 4
411 if (nut->version > NUT_STABLE_VERSION)
412 ff_put_v(bc, nut->flags);
408}413}
409 414
410static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,415static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
@@ -643,6 +648,16 @@ static int nut_write_header(AVFormatContext *s) · 232 unmodified lines
643 648
644 nut->avf = s;649 nut->avf = s;
645 650
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
646 nut->stream = av_mallocz(sizeof(StreamContext) * s->nb_streams);661 nut->stream = av_mallocz(sizeof(StreamContext) * s->nb_streams);
647 if (s->nb_chapters)662 if (s->nb_chapters)
648 nut->chapter = av_mallocz(sizeof(ChapterContext) * s->nb_chapters);663 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
789 804
790//FIXME: Ensure store_sp is 1 in the first place.805//FIXME: Ensure store_sp is 1 in the first place.
791 806
792 if (store_sp) {807 if (store_sp &&
808 (!(nut->flags & NUT_PIPE) || nut->last_syncpoint_pos == INT_MIN)) {
793 Syncpoint *sp, dummy = { .pos = INT64_MAX };809 Syncpoint *sp, dummy = { .pos = INT64_MAX };
794 810
795 ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);811 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
815 return ret;831 return ret;
816 put_tt(nut, nus->time_base, dyn_bc, pkt->dts);832 put_tt(nut, nus->time_base, dyn_bc, pkt->dts);
817 ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);833 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 }
818 put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);839 put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
819 840
820 if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)841 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
917 nus->last_pts = pkt->pts;938 nus->last_pts = pkt->pts;
918 939
919 //FIXME just store one per syncpoint940 //FIXME just store one per syncpoint
920 if (flags & FLAG_KEY)941 if (flags & FLAG_KEY && !(nut->flags & NUT_PIPE))
921 av_add_index_entry(942 av_add_index_entry(
922 s->streams[pkt->stream_index],943 s->streams[pkt->stream_index],
923 nut->last_syncpoint_pos,944 nut->last_syncpoint_pos,
@@ -945,6 +966,23 @@ static int nut_write_trailer(AVFormatContext *s) · 21 unmodified lines
945 return 0;966 return 0;
946}967}
947 968
969#define OFFSET(x) offsetof(NUTContext, x)
970#define E AV_OPT_FLAG_ENCODING_PARAM
971static 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
979static const AVClass class = {
980 .class_name = "nutenc",
981 .item_name = av_default_item_name,
982 .option = options,
983 .version = LIBAVUTIL_VERSION_INT,
984};
985
948AVOutputFormat ff_nut_muxer = {986AVOutputFormat ff_nut_muxer = {
949 .name = "nut",987 .name = "nut",
950 .long_name = NULL_IF_CONFIG_SMALL("NUT"),988 .long_name = NULL_IF_CONFIG_SMALL("NUT"),
@@ -959,4 +997,5 @@ AVOutputFormat ff_nut_muxer = { · 8 unmodified lines
959 .write_trailer = nut_write_trailer,997 .write_trailer = nut_write_trailer,
960 .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,998 .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS,
961 .codec_tag = ff_nut_codec_tags,999 .codec_tag = ff_nut_codec_tags,
1000 .priv_class = &class,
962};1001};

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