X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fnutdec.c;h=bf72555876eddc7302a736332904e79a0fb201bf;hb=d20d1449e0eea245c483c0b97faf38df5092ff2f;hp=03c684da9b0122a1efd330d4f33ecc54ae8c460d;hpb=d6f142a1f8e77fb73263ba9c204ad2314951b9e3;p=ffmpeg diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c index 03c684da9b0..bf72555876e 100644 --- a/libavformat/nutdec.c +++ b/libavformat/nutdec.c @@ -20,13 +20,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "tree.h" +#include +#include "libavutil/avstring.h" +#include "libavutil/bswap.h" +#include "libavutil/tree.h" #include "nut.h" -#include "avstring.h" #undef NDEBUG #include +#if FF_API_MAX_STREAMS +#define NUT_MAX_STREAMS MAX_STREAMS +#else +#define NUT_MAX_STREAMS 256 /* arbitrary sanity check value */ +#endif + static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ unsigned int len= ff_get_v(bc); @@ -92,8 +100,8 @@ static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_ch int64_t size; // start= url_ftell(bc) - 8; - startcode= be2me_64(startcode); - startcode= ff_crc04C11DB7_update(0, &startcode, 8); + startcode= av_be2ne64(startcode); + startcode= ff_crc04C11DB7_update(0, (uint8_t*)&startcode, 8); init_checksum(bc, ff_crc04C11DB7_update, startcode); size= ff_get_v(bc); @@ -134,7 +142,7 @@ static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ * Find the given startcode. * @param code the startcode * @param pos the start position of the search, or -1 if the current position - * @returns the position of the startcode or -1 if not found + * @return the position of the startcode or -1 if not found */ static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ for(;;){ @@ -191,7 +199,7 @@ static int decode_main_header(NUTContext *nut){ end += url_ftell(bc); GET_V(tmp , tmp >=2 && tmp <= 3) - GET_V(stream_count , tmp > 0 && tmp <=MAX_STREAMS) + GET_V(stream_count , tmp > 0 && tmp <= NUT_MAX_STREAMS) nut->max_distance = ff_get_v(bc); if(nut->max_distance > 65536){ @@ -205,9 +213,9 @@ static int decode_main_header(NUTContext *nut){ for(i=0; itime_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)) - if(ff_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1){ + 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 -1; + return AVERROR_INVALIDDATA; } } tmp_pts=0; @@ -235,11 +243,11 @@ static int decode_main_header(NUTContext *nut){ if(count == 0 || i+count > 256){ av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i); - return -1; + return AVERROR_INVALIDDATA; } if(tmp_stream >= stream_count){ av_log(s, AV_LOG_ERROR, "illegal stream number\n"); - return -1; + return AVERROR_INVALIDDATA; } for(j=0; jheader_len[i]; if(rem < 0){ av_log(s, AV_LOG_ERROR, "invalid elision header\n"); - return -1; + return AVERROR_INVALIDDATA; } nut->header[i]= av_malloc(nut->header_len[i]); get_buffer(bc, nut->header[i], nut->header_len[i]); @@ -278,7 +286,7 @@ static int decode_main_header(NUTContext *nut){ if(skip_reserved(bc, end) || get_checksum(bc)){ av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n"); - return -1; + return AVERROR_INVALIDDATA; } nut->stream = av_mallocz(sizeof(StreamContext)*stream_count); @@ -313,26 +321,29 @@ static int decode_stream_header(NUTContext *nut){ switch(class) { case 0: - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = codec_get_id(codec_bmp_tags, tmp); + 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, 0 }, + tmp); break; case 1: - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = codec_get_id(codec_wav_tags, tmp); + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, tmp); break; case 2: - st->codec->codec_type = CODEC_TYPE_SUBTITLE; - st->codec->codec_id = codec_get_id(ff_nut_subtitle_tags, tmp); + st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codec->codec_id = ff_codec_get_id(ff_nut_subtitle_tags, tmp); break; case 3: - st->codec->codec_type = CODEC_TYPE_DATA; + st->codec->codec_type = AVMEDIA_TYPE_DATA; break; default: av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class); return -1; } if(class<3 && st->codec->codec_id == CODEC_ID_NONE) - av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); + av_log(s, AV_LOG_ERROR, "Unknown codec tag '0x%04x' for stream number %d\n", + (unsigned int)tmp, stream_id); GET_V(stc->time_base_id , tmp < nut->time_base_count); GET_V(stc->msb_pts_shift , tmp < 16); @@ -347,17 +358,17 @@ static int decode_stream_header(NUTContext *nut){ get_buffer(bc, st->codec->extradata, st->codec->extradata_size); } - if (st->codec->codec_type == CODEC_TYPE_VIDEO){ + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ GET_V(st->codec->width , tmp > 0) GET_V(st->codec->height, tmp > 0) - st->codec->sample_aspect_ratio.num= ff_get_v(bc); - st->codec->sample_aspect_ratio.den= ff_get_v(bc); - if((!st->codec->sample_aspect_ratio.num) != (!st->codec->sample_aspect_ratio.den)){ - av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n", st->codec->sample_aspect_ratio.num, st->codec->sample_aspect_ratio.den); + st->sample_aspect_ratio.num= ff_get_v(bc); + st->sample_aspect_ratio.den= ff_get_v(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; } ff_get_v(bc); /* csp type */ - }else if (st->codec->codec_type == CODEC_TYPE_AUDIO){ + }else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO){ GET_V(st->codec->sample_rate , tmp > 0) ff_get_v(bc); // samplerate_den GET_V(st->codec->channels, tmp > 0) @@ -387,12 +398,15 @@ static void set_disposition_bits(AVFormatContext* avf, char* value, int stream_i static int decode_info_header(NUTContext *nut){ AVFormatContext *s= nut->avf; ByteIOContext *bc = s->pb; - uint64_t tmp; - unsigned int stream_id_plus1, chapter_start, chapter_len, count; + uint64_t tmp, chapter_start, chapter_len; + unsigned int stream_id_plus1, count; int chapter_id, i; int64_t value, end; char name[256], str_value[1024], type_str[256]; const char *type; + AVChapter *chapter= NULL; + AVStream *st= NULL; + AVMetadata **metadata = NULL; end= get_packetheader(nut, bc, 1, INFO_STARTCODE); end += url_ftell(bc); @@ -402,6 +416,19 @@ static int decode_info_header(NUTContext *nut){ chapter_start= ff_get_v(bc); chapter_len = ff_get_v(bc); count = ff_get_v(bc); + + if(chapter_id && !stream_id_plus1){ + int64_t start= chapter_start / nut->time_base_count; + chapter= ff_new_chapter(s, chapter_id, + nut->time_base[chapter_start % nut->time_base_count], + start, start + chapter_len, NULL); + metadata = &chapter->metadata; + } else if(stream_id_plus1) { + st= s->streams[stream_id_plus1 - 1]; + metadata = &st->metadata; + } else + metadata = &s->metadata; + for(i=0; iauthor , str_value, sizeof(s->author)); - else if(!strcmp(name, "Title")) - av_strlcpy(s->title , str_value, sizeof(s->title)); - else if(!strcmp(name, "Copyright")) - av_strlcpy(s->copyright, str_value, sizeof(s->copyright)); - else if(!strcmp(name, "Description")) - av_strlcpy(s->comment , str_value, sizeof(s->comment)); - else if(!strcmp(name, "Disposition")) + if(!strcmp(type, "UTF-8")){ + if(chapter_id==0 && !strcmp(name, "Disposition")) { set_disposition_bits(s, str_value, stream_id_plus1 - 1); + continue; + } + if(metadata && strcasecmp(name,"Uses") + && strcasecmp(name,"Depends") && strcasecmp(name,"Replaces")) + av_metadata_set2(metadata, name, str_value, 0); } } @@ -487,6 +511,7 @@ static int find_and_decode_index(NUTContext *nut){ int64_t filesize= url_fsize(bc); int64_t *syncpoints; int8_t *has_keyframe; + int ret= -1; url_fseek(bc, filesize-12, SEEK_SET); url_fseek(bc, filesize-get_be64(bc), SEEK_SET); @@ -503,7 +528,9 @@ static int find_and_decode_index(NUTContext *nut){ syncpoints= av_malloc(sizeof(int64_t)*syncpoint_count); has_keyframe= av_malloc(sizeof(int8_t)*(syncpoint_count+1)); for(i=0; i0) + syncpoints[i] = ff_get_v(bc); + if(syncpoints[i] <= 0) + goto fail; if(i) syncpoints[i] += syncpoints[i-1]; } @@ -520,7 +547,7 @@ static int find_and_decode_index(NUTContext *nut){ x>>=1; if(n+x >= syncpoint_count + 1){ av_log(s, AV_LOG_ERROR, "index overflow A\n"); - return -1; + goto fail; } while(x--) has_keyframe[n++]= flag; @@ -529,7 +556,7 @@ static int find_and_decode_index(NUTContext *nut){ while(x != 1){ if(n>=syncpoint_count + 1){ av_log(s, AV_LOG_ERROR, "index overflow B\n"); - return -1; + goto fail; } has_keyframe[n++]= x&1; x>>=1; @@ -537,7 +564,7 @@ static int find_and_decode_index(NUTContext *nut){ } if(has_keyframe[0]){ av_log(s, AV_LOG_ERROR, "keyframe before first syncpoint in index\n"); - return -1; + goto fail; } assert(n<=syncpoint_count+1); for(; j= 0) initialized_stream_count++; @@ -608,7 +639,7 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) if(startcode==0){ av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); - return -1; + return AVERROR_INVALIDDATA; }else if(startcode == SYNCPOINT_STARTCODE){ nut->next_startcode= startcode; break; @@ -628,6 +659,8 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) } assert(nut->next_startcode == SYNCPOINT_STARTCODE); + ff_metadata_conv_ctx(s, NULL, ff_nut_metadata_conv); + return 0; } @@ -640,7 +673,7 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, ui if(url_ftell(bc) > nut->last_syncpoint_pos + nut->max_distance){ av_log(s, AV_LOG_ERROR, "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n", url_ftell(bc), nut->last_syncpoint_pos, nut->max_distance); - return -1; + return AVERROR_INVALIDDATA; } flags = nut->frame_code[frame_code].flags; @@ -652,7 +685,7 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, ui *header_idx = nut->frame_code[frame_code].header_idx; if(flags & FLAG_INVALID) - return -1; + return AVERROR_INVALIDDATA; if(flags & FLAG_CODED) flags ^= ff_get_v(bc); if(flags & FLAG_STREAM_ID){ @@ -682,7 +715,7 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, ui if(*header_idx >= (unsigned)nut->header_count){ av_log(s, AV_LOG_ERROR, "header_idx invalid\n"); - return -1; + return AVERROR_INVALIDDATA; } if(size > 4096) *header_idx=0; @@ -692,7 +725,7 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, ui get_be32(bc); //FIXME check this }else if(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 -1; + return AVERROR_INVALIDDATA; } stc->last_pts= *pts; @@ -711,7 +744,7 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ size= decode_frame_header(nut, &pts, &stream_id, &header_idx, frame_code); if(size < 0) - return -1; + return size; stc= &nut->stream[stream_id]; @@ -735,7 +768,7 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ pkt->stream_index = stream_id; if (stc->last_flags & FLAG_KEY) - pkt->flags |= PKT_FLAG_KEY; + pkt->flags |= AV_PKT_FLAG_KEY; pkt->pts = pts; return 0; @@ -791,7 +824,7 @@ resync: av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", pos); tmp= find_any_startcode(bc, nut->last_syncpoint_pos+1); if(tmp==0) - return -1; + return AVERROR_INVALIDDATA; av_log(s, AV_LOG_DEBUG, "sync\n"); nut->next_startcode= tmp; } @@ -826,9 +859,9 @@ assert(0); static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags){ NUTContext *nut = s->priv_data; AVStream *st= s->streams[stream_index]; - syncpoint_t dummy={.ts= pts*av_q2d(st->time_base)*AV_TIME_BASE}; - syncpoint_t nopts_sp= {.ts= AV_NOPTS_VALUE, .back_ptr= AV_NOPTS_VALUE}; - syncpoint_t *sp, *next_node[2]= {&nopts_sp, &nopts_sp}; + Syncpoint dummy={.ts= pts*av_q2d(st->time_base)*AV_TIME_BASE}; + Syncpoint nopts_sp= {.ts= AV_NOPTS_VALUE, .back_ptr= AV_NOPTS_VALUE}; + Syncpoint *sp, *next_node[2]= {&nopts_sp, &nopts_sp}; int64_t pos, pos2, ts; int i; @@ -840,7 +873,8 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flag pos2= st->index_entries[index].pos; ts = st->index_entries[index].timestamp; }else{ - av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pts_cmp, next_node); + av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pts_cmp, + (void **) next_node); av_log(s, AV_LOG_DEBUG, "%"PRIu64"-%"PRIu64" %"PRId64"-%"PRId64"\n", next_node[0]->pos, next_node[1]->pos, next_node[0]->ts , next_node[1]->ts); pos= av_gen_search(s, -1, dummy.ts, next_node[0]->pos, next_node[1]->pos, next_node[1]->pos, @@ -849,7 +883,8 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flag if(!(flags & AVSEEK_FLAG_BACKWARD)){ dummy.pos= pos+16; next_node[1]= &nopts_sp; - av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, next_node); + av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp, + (void **) next_node); pos2= av_gen_search(s, -2, dummy.pos, next_node[0]->pos , next_node[1]->pos, next_node[1]->pos, next_node[0]->back_ptr, next_node[1]->back_ptr, flags, &ts, nut_read_timestamp); if(pos2>=0) @@ -857,7 +892,8 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flag //FIXME dir but I think it does not matter } dummy.pos= pos; - sp= av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, NULL); + sp= av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp, + NULL); assert(sp); pos2= sp->back_ptr - 15; @@ -878,17 +914,21 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flag static int nut_read_close(AVFormatContext *s) { NUTContext *nut = s->priv_data; + int i; av_freep(&nut->time_base); av_freep(&nut->stream); + ff_nut_free_sp(nut); + for(i = 1; i < nut->header_count; i++) + av_freep(&nut->header[i]); return 0; } -#ifdef CONFIG_NUT_DEMUXER +#if CONFIG_NUT_DEMUXER AVInputFormat nut_demuxer = { "nut", - "nut format", + NULL_IF_CONFIG_SMALL("NUT format"), sizeof(NUTContext), nut_probe, nut_read_header, @@ -896,5 +936,6 @@ AVInputFormat nut_demuxer = { nut_read_close, 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 }, }; #endif