X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fnutdec.c;h=69057e933afbfb63d8c168e5132d600d5cdae7b6;hb=167e004e1aca7765686ed95d7cd8ea5064d4f6f6;hp=004a2ea255b66ffeeeba14096bce7d0e8b06d1c1;hpb=679481b3b61dda5e2827f9757bf8c12a8de193c9;p=ffmpeg diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c index 004a2ea255b..69057e933af 100644 --- a/libavformat/nutdec.c +++ b/libavformat/nutdec.c @@ -27,6 +27,7 @@ #include "libavutil/tree.h" #include "avio_internal.h" #include "nut.h" +#include "riff.h" #undef NDEBUG #include @@ -76,8 +77,8 @@ static uint64_t get_fourcc(AVIOContext *bc) } #ifdef TRACE -static inline uint64_t get_v_trace(AVIOContext *bc, char *file, - char *func, int line) +static inline uint64_t get_v_trace(AVIOContext *bc, const char *file, + const char *func, int line) { uint64_t v = ffio_read_varlen(bc); @@ -86,8 +87,8 @@ static inline uint64_t get_v_trace(AVIOContext *bc, char *file, return v; } -static inline int64_t get_s_trace(AVIOContext *bc, char *file, - char *func, int line) +static inline int64_t get_s_trace(AVIOContext *bc, const char *file, + const char *func, int line) { int64_t v = get_s(bc); @@ -96,18 +97,8 @@ static inline int64_t get_s_trace(AVIOContext *bc, char *file, return v; } -static inline uint64_t get_vb_trace(AVIOContext *bc, char *file, - char *func, int line) -{ - uint64_t v = get_vb(bc); - - av_log(NULL, AV_LOG_DEBUG, "get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", - v, v, file, func, line); - return v; -} #define ffio_read_varlen(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) #define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) #endif static int get_packetheader(NUTContext *nut, AVIOContext *bc, @@ -187,20 +178,22 @@ static int nut_probe(AVProbeData *p) return 0; } -#define GET_V(dst, check) \ - tmp = ffio_read_varlen(bc); \ - if (!(check)) { \ - av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp); \ - return -1; \ - } \ - dst = tmp; +#define GET_V(dst, check) \ + do { \ + tmp = ffio_read_varlen(bc); \ + if (!(check)) { \ + av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp); \ + return AVERROR_INVALIDDATA; \ + } \ + dst = tmp; \ + } while (0) static int skip_reserved(AVIOContext *bc, int64_t pos) { pos -= avio_tell(bc); if (pos < 0) { avio_seek(bc, pos, SEEK_CUR); - return -1; + return AVERROR_INVALIDDATA; } else { while (pos--) avio_r8(bc); @@ -220,8 +213,15 @@ static int decode_main_header(NUTContext *nut) end = get_packetheader(nut, bc, 1, MAIN_STARTCODE); end += avio_tell(bc); - GET_V(tmp, tmp >= 2 && tmp <= 3) - GET_V(stream_count, tmp > 0 && tmp <= NUT_MAX_STREAMS) + nut->version = ffio_read_varlen(bc); + if (nut->version < NUT_MIN_VERSION && + nut->version > NUT_MAX_VERSION) { + av_log(s, AV_LOG_ERROR, "Version %d not supported.\n", + nut->version); + return AVERROR(ENOSYS); + } + + GET_V(stream_count, tmp > 0 && tmp <= NUT_MAX_STREAMS); nut->max_distance = ffio_read_varlen(bc); if (nut->max_distance > 65536) { @@ -229,12 +229,12 @@ static int decode_main_header(NUTContext *nut) nut->max_distance = 65536; } - GET_V(nut->time_base_count, tmp > 0 && tmp < INT_MAX / sizeof(AVRational)) + GET_V(nut->time_base_count, tmp > 0 && tmp < INT_MAX / sizeof(AVRational)); nut->time_base = av_malloc(nut->time_base_count * sizeof(AVRational)); for (i = 0; i < nut->time_base_count; i++) { - GET_V(nut->time_base[i].num, tmp > 0 && tmp < (1ULL << 31)) - GET_V(nut->time_base[i].den, tmp > 0 && tmp < (1ULL << 31)) + GET_V(nut->time_base[i].num, tmp > 0 && tmp < (1ULL << 31)); + GET_V(nut->time_base[i].den, tmp > 0 && tmp < (1ULL << 31)); if (av_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1) { av_log(s, AV_LOG_ERROR, "time base invalid\n"); return AVERROR_INVALIDDATA; @@ -302,21 +302,30 @@ static int decode_main_header(NUTContext *nut) if (end > avio_tell(bc) + 4) { int rem = 1024; - GET_V(nut->header_count, tmp < 128U) + GET_V(nut->header_count, tmp < 128U); nut->header_count++; for (i = 1; i < nut->header_count; i++) { + uint8_t *hdr; GET_V(nut->header_len[i], tmp > 0 && tmp < 256); rem -= nut->header_len[i]; if (rem < 0) { av_log(s, AV_LOG_ERROR, "invalid elision header\n"); return AVERROR_INVALIDDATA; } - nut->header[i] = av_malloc(nut->header_len[i]); - avio_read(bc, nut->header[i], nut->header_len[i]); + hdr = av_malloc(nut->header_len[i]); + if (!hdr) + return AVERROR(ENOMEM); + avio_read(bc, hdr, nut->header_len[i]); + nut->header[i] = hdr; } assert(nut->header_len[0] == 0); } + // flags had been effectively introduced in version 4 + if (nut->version > NUT_STABLE_VERSION) { + nut->flags = ffio_read_varlen(bc); + } + if (skip_reserved(bc, end) || ffio_get_checksum(bc)) { av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n"); return AVERROR_INVALIDDATA; @@ -354,15 +363,20 @@ static int decode_stream_header(NUTContext *nut) case 0: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) { - ff_codec_bmp_tags, ff_nut_video_tags, + ff_codec_bmp_tags, 0 }, tmp); break; case 1: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, tmp); + st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) { + ff_nut_audio_tags, + ff_codec_wav_tags, + 0 + }, + tmp); break; case 2: st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; @@ -370,12 +384,13 @@ static int decode_stream_header(NUTContext *nut) break; case 3: st->codec->codec_type = AVMEDIA_TYPE_DATA; + st->codec->codec_id = ff_codec_get_id(ff_nut_data_tags, tmp); break; default: av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class); - return -1; + return AVERROR(ENOSYS); } - if (class < 3 && st->codec->codec_id == CODEC_ID_NONE) + if (class < 3 && st->codec->codec_id == AV_CODEC_ID_NONE) av_log(s, AV_LOG_ERROR, "Unknown codec tag '0x%04x' for stream number %d\n", (unsigned int) tmp, stream_id); @@ -384,7 +399,6 @@ static int decode_stream_header(NUTContext *nut) GET_V(stc->msb_pts_shift, tmp < 16); stc->max_pts_distance = ffio_read_varlen(bc); GET_V(stc->decode_delay, tmp < 1000); // sanity limit, raise this if Moore's law is true - st->codec->has_b_frames = stc->decode_delay; ffio_read_varlen(bc); // stream flags GET_V(st->codec->extradata_size, tmp < (1 << 30)); @@ -395,25 +409,25 @@ static int decode_stream_header(NUTContext *nut) } if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - GET_V(st->codec->width, tmp > 0) - GET_V(st->codec->height, tmp > 0) + GET_V(st->codec->width, tmp > 0); + GET_V(st->codec->height, tmp > 0); st->sample_aspect_ratio.num = ffio_read_varlen(bc); st->sample_aspect_ratio.den = ffio_read_varlen(bc); if ((!st->sample_aspect_ratio.num) != (!st->sample_aspect_ratio.den)) { av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n", st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); - return -1; + return AVERROR_INVALIDDATA; } ffio_read_varlen(bc); /* csp type */ } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - GET_V(st->codec->sample_rate, tmp > 0) + GET_V(st->codec->sample_rate, tmp > 0); ffio_read_varlen(bc); // samplerate_den - GET_V(st->codec->channels, tmp > 0) + GET_V(st->codec->channels, tmp > 0); } if (skip_reserved(bc, end) || ffio_get_checksum(bc)) { av_log(s, AV_LOG_ERROR, "stream header %d checksum mismatch\n", stream_id); - return -1; + return AVERROR_INVALIDDATA; } stc->time_base = &nut->time_base[stc->time_base_id]; avpriv_set_pts_info(s->streams[stream_id], 63, stc->time_base->num, @@ -446,14 +460,16 @@ static int decode_info_header(NUTContext *nut) int64_t value, end; char name[256], str_value[1024], type_str[256]; const char *type; + int *event_flags = NULL; AVChapter *chapter = NULL; AVStream *st = NULL; AVDictionary **metadata = NULL; + int metadata_flag = 0; end = get_packetheader(nut, bc, 1, INFO_STARTCODE); end += avio_tell(bc); - GET_V(stream_id_plus1, tmp <= s->nb_streams) + GET_V(stream_id_plus1, tmp <= s->nb_streams); chapter_id = get_s(bc); chapter_start = ffio_read_varlen(bc); chapter_len = ffio_read_varlen(bc); @@ -469,8 +485,13 @@ static int decode_info_header(NUTContext *nut) } else if (stream_id_plus1) { st = s->streams[stream_id_plus1 - 1]; metadata = &st->metadata; - } else + event_flags = &st->event_flags; + metadata_flag = AVSTREAM_EVENT_FLAG_METADATA_UPDATED; + } else { metadata = &s->metadata; + event_flags = &s->event_flags; + metadata_flag = AVFMT_EVENT_FLAG_METADATA_UPDATED; + } for (i = 0; i < count; i++) { get_str(bc, name, sizeof(name)); @@ -506,14 +527,17 @@ static int decode_info_header(NUTContext *nut) continue; } if (metadata && av_strcasecmp(name, "Uses") && - av_strcasecmp(name, "Depends") && av_strcasecmp(name, "Replaces")) + av_strcasecmp(name, "Depends") && av_strcasecmp(name, "Replaces")) { + if (event_flags) + *event_flags |= metadata_flag; av_dict_set(metadata, name, str_value, 0); + } } } if (skip_reserved(bc, end) || ffio_get_checksum(bc)) { av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n"); - return -1; + return AVERROR_INVALIDDATA; } return 0; } @@ -523,6 +547,7 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) AVFormatContext *s = nut->avf; AVIOContext *bc = s->pb; int64_t end, tmp; + int ret; nut->last_syncpoint_pos = avio_tell(bc) - 8; @@ -537,14 +562,24 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count], tmp / nut->time_base_count); + if (nut->flags & NUT_BROADCAST) { + tmp = ffio_read_varlen(bc); + av_log(s, AV_LOG_VERBOSE, "Syncpoint wallclock %"PRId64"\n", + av_rescale_q(tmp / nut->time_base_count, + nut->time_base[tmp % nut->time_base_count], + AV_TIME_BASE_Q)); + } + if (skip_reserved(bc, end) || ffio_get_checksum(bc)) { av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n"); - return -1; + return AVERROR_INVALIDDATA; } *ts = tmp / s->nb_streams * av_q2d(nut->time_base[tmp % s->nb_streams]) * AV_TIME_BASE; - ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts); + + if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts)) < 0) + return ret; return 0; } @@ -558,20 +593,20 @@ static int find_and_decode_index(NUTContext *nut) int64_t filesize = avio_size(bc); int64_t *syncpoints; int8_t *has_keyframe; - int ret = -1; + int ret = AVERROR_INVALIDDATA; avio_seek(bc, filesize - 12, SEEK_SET); avio_seek(bc, filesize - avio_rb64(bc), SEEK_SET); if (avio_rb64(bc) != INDEX_STARTCODE) { av_log(s, AV_LOG_ERROR, "no index at the end\n"); - return -1; + return ret; } end = get_packetheader(nut, bc, 1, INDEX_STARTCODE); end += avio_tell(bc); ffio_read_varlen(bc); // max_pts - GET_V(syncpoint_count, tmp < INT_MAX / 8 && tmp > 0) + GET_V(syncpoint_count, tmp < INT_MAX / 8 && tmp > 0); syncpoints = av_malloc(sizeof(int64_t) * syncpoint_count); has_keyframe = av_malloc(sizeof(int8_t) * (syncpoint_count + 1)); for (i = 0; i < syncpoint_count; i++) { @@ -716,7 +751,8 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, int size, flags, size_mul, pts_delta, i, reserved_count; uint64_t tmp; - if (avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) { + if (!(nut->flags & NUT_PIPE) && + avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance) { av_log(s, AV_LOG_ERROR, "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n", avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance); @@ -736,7 +772,7 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, if (flags & FLAG_CODED) flags ^= ffio_read_varlen(bc); if (flags & FLAG_STREAM_ID) { - GET_V(*stream_id, tmp < s->nb_streams) + GET_V(*stream_id, tmp < s->nb_streams); } stc = &nut->stream[*stream_id]; if (flags & FLAG_CODED_PTS) { @@ -769,8 +805,9 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, if (flags & FLAG_CHECKSUM) { avio_rb32(bc); // FIXME check this - } else if (size > 2 * nut->max_distance || FFABS(stc->last_pts - *pts) > - stc->max_pts_distance) { + } else if (!(nut->flags & NUT_PIPE) && + size > 2 * nut->max_distance || + FFABS(stc->last_pts - *pts) > stc->max_pts_distance) { av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n"); return AVERROR_INVALIDDATA; } @@ -785,7 +822,7 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code) { AVFormatContext *s = nut->avf; AVIOContext *bc = s->pb; - int size, stream_id, discard; + int size, stream_id, discard, ret; int64_t pts, last_IP_pts; StreamContext *stc; uint8_t header_idx; @@ -810,7 +847,9 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code) return 1; } - av_new_packet(pkt, size + nut->header_len[header_idx]); + ret = av_new_packet(pkt, size + nut->header_len[header_idx]); + if (ret < 0) + return ret; memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]); pkt->pos = avio_tell(bc); // FIXME avio_read(bc, pkt->data + nut->header_len[header_idx], size); @@ -840,7 +879,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) } else { frame_code = avio_r8(bc); if (bc->eof_reached) - return -1; + return AVERROR_EOF; if (frame_code == 'N') { tmp = frame_code; for (i = 1; i < 8; i++) @@ -907,7 +946,7 @@ static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, else if (stream_index == -2) return back_ptr; - assert(0); + return AV_NOPTS_VALUE; } static int read_seek(AVFormatContext *s, int stream_index, @@ -921,6 +960,10 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pos, pos2, ts; int i; + if (nut->flags & NUT_PIPE) { + return AVERROR(ENOSYS); + } + if (st->index_entries) { int index = av_index_search_timestamp(st, pts, flags); if (index < 0) @@ -987,7 +1030,7 @@ static int nut_read_close(AVFormatContext *s) AVInputFormat ff_nut_demuxer = { .name = "nut", - .long_name = NULL_IF_CONFIG_SMALL("NUT format"), + .long_name = NULL_IF_CONFIG_SMALL("NUT"), .priv_data_size = sizeof(NUTContext), .read_probe = nut_probe, .read_header = nut_read_header, @@ -995,8 +1038,5 @@ AVInputFormat ff_nut_demuxer = { .read_close = nut_read_close, .read_seek = read_seek, .extensions = "nut", - .codec_tag = (const AVCodecTag * const []) { - ff_codec_bmp_tags, ff_nut_video_tags, ff_codec_wav_tags, - ff_nut_subtitle_tags, 0 - }, + .codec_tag = ff_nut_codec_tags, };