X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=5464b783d37f852f09779f4b284e876b736fb50e;hb=4907f813581acd6cf68f1be9eb163464503e8208;hp=194c2f86dd4ddff19a219ccac074e5369663ddc1;hpb=add41decd94b2d3581a3715ba10f27168b8cdb1b;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index 194c2f86dd4..5464b783d37 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -3,20 +3,20 @@ * Copyright (c) 2001 Fabrice Bellard * Copyright (c) 2009 Baptiste Coudurier * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -26,6 +26,8 @@ //#define MOV_EXPORT_ALL_METADATA #include "libavutil/intreadwrite.h" +#include "libavutil/intfloat_readwrite.h" +#include "libavutil/mathematics.h" #include "libavutil/avstring.h" #include "libavutil/dict.h" #include "avformat.h" @@ -79,15 +81,15 @@ typedef struct MOVParseTableEntry { static const MOVParseTableEntry mov_default_parse_table[]; -static int mov_metadata_trkn(MOVContext *c, AVIOContext *pb, unsigned len) +static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb, unsigned len, const char *type) { char buf[16]; avio_rb16(pb); // unknown snprintf(buf, sizeof(buf), "%d", avio_rb16(pb)); - av_dict_set(&c->fc->metadata, "track", buf, 0); + av_dict_set(&c->fc->metadata, type, buf, 0); - avio_rb16(pb); // total tracks + avio_rb16(pb); // total tracks/discs return 0; } @@ -138,15 +140,18 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) const char *key = NULL; uint16_t str_size, langcode = 0; uint32_t data_type = 0; - int (*parse)(MOVContext*, AVIOContext*, unsigned) = NULL; + int (*parse)(MOVContext*, AVIOContext*, unsigned, const char *) = NULL; switch (atom.type) { case MKTAG(0xa9,'n','a','m'): key = "title"; break; case MKTAG(0xa9,'a','u','t'): case MKTAG(0xa9,'A','R','T'): key = "artist"; break; + case MKTAG( 'a','A','R','T'): key = "album_artist";break; case MKTAG(0xa9,'w','r','t'): key = "composer"; break; case MKTAG( 'c','p','r','t'): case MKTAG(0xa9,'c','p','y'): key = "copyright"; break; + case MKTAG(0xa9,'g','r','p'): key = "grouping"; break; + case MKTAG(0xa9,'l','y','r'): key = "lyrics"; break; case MKTAG(0xa9,'c','m','t'): case MKTAG(0xa9,'i','n','f'): key = "comment"; break; case MKTAG(0xa9,'a','l','b'): key = "album"; break; @@ -161,7 +166,9 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) case MKTAG( 't','v','e','n'): key = "episode_id";break; case MKTAG( 't','v','n','n'): key = "network"; break; case MKTAG( 't','r','k','n'): key = "track"; - parse = mov_metadata_trkn; break; + parse = mov_metadata_track_or_disc_number; break; + case MKTAG( 'd','i','s','k'): key = "disc"; + parse = mov_metadata_track_or_disc_number; break; } if (c->itunes_metadata && atom.size > 8) { @@ -196,7 +203,7 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) str_size = FFMIN3(sizeof(str)-1, str_size, atom.size); if (parse) - parse(c, pb, str_size); + parse(c, pb, str_size, key); else { if (data_type == 3 || (data_type == 0 && langcode < 0x800)) { // MAC Encoded mov_read_mac_string(c, pb, str_size, str, sizeof(str)); @@ -257,7 +264,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (atom.size < 0) atom.size = INT64_MAX; - while (total_size + 8 < atom.size && !pb->eof_reached) { + while (total_size + 8 < atom.size && !url_feof(pb)) { int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL; a.size = atom.size; a.type=0; @@ -449,7 +456,7 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->codec->codec_type = AVMEDIA_TYPE_AUDIO; else if(type == MKTAG('m','1','a',' ')) st->codec->codec_id = CODEC_ID_MP2; - else if(type == MKTAG('s','u','b','p')) + else if((type == MKTAG('s','u','b','p')) || (type == MKTAG('c','l','c','p'))) st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; avio_rb32(pb); /* component manufacture */ @@ -471,8 +478,7 @@ int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb, MOVAtom atom) avio_rb32(pb); /* version + flags */ ff_mp4_read_descr(fc, pb, &tag); if (tag == MP4ESDescrTag) { - avio_rb16(pb); /* ID */ - avio_r8(pb); /* priority */ + ff_mp4_parse_es_descr(pb, NULL); } else avio_rb16(pb); /* ID */ @@ -726,7 +732,7 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; st = c->fc->streams[c->fc->nb_streams-1]; - little_endian = avio_rb16(pb); + little_endian = avio_rb16(pb) & 0xFF; av_dlog(c->fc, "enda %d\n", little_endian); if (little_endian == 1) { switch (st->codec->codec_id) { @@ -1187,7 +1193,18 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) st->codec->width = sc->width; st->codec->height = sc->height; } else { - /* other codec type, just skip (rtp, mp4s, tmcd ...) */ + if (st->codec->codec_tag == MKTAG('t','m','c','d')) { + int val; + avio_rb32(pb); /* reserved */ + val = avio_rb32(pb); /* flags */ + if (val & 1) + st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE; + avio_rb32(pb); + avio_rb32(pb); + st->codec->time_base.den = get_byte(pb); + st->codec->time_base.num = 1; + } + /* other codec type, just skip (rtp, mp4s, ...) */ avio_skip(pb, size - (avio_tell(pb) - start_pos)); } /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ @@ -1464,6 +1481,11 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sample_count=avio_rb32(pb); sample_duration = avio_rb32(pb); + /* sample_duration < 0 is invalid based on the spec */ + if (sample_duration < 0) { + av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d", sample_duration); + sample_duration = 1; + } sc->stts_data[i].count= sample_count; sc->stts_data[i].duration= sample_duration; @@ -1509,7 +1531,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->ctts_data[i].count = count; sc->ctts_data[i].duration= duration; - if (duration < 0) + if (duration < 0 && i+1dts_shift = FFMAX(sc->dts_shift, -duration); } @@ -1536,7 +1558,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale); current_dts = -sc->time_offset; if (sc->ctts_data && sc->stts_data && - sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) { + sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) { /* more than 16 frames delay, dts are likely wrong this happens with files created by iMovie */ sc->wrong_dts = 1; @@ -1698,13 +1720,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } -static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref) +static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref) { /* try relative path, we do not try the absolute because it can leak information about our system to an attacker */ if (ref->nlvl_to > 0 && ref->nlvl_from > 0) { char filename[1024]; - char *src_path; + const char *src_path; int i, l; /* find a source dir */ @@ -1922,6 +1944,10 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->width = width >> 16; sc->height = height >> 16; + if (display_matrix[0][0] == -65536 && display_matrix[1][1] == -65536) { + av_dict_set(&st->metadata, "rotate", "180", 0); + } + // transform the display width/height according to the matrix // skip this if the display matrix is the default identity matrix // or if it is rotating the picture, ex iPhone 3GS @@ -2209,6 +2235,15 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + if (atom.size < 16) + return AVERROR_INVALIDDATA; + avio_skip(pb, 4); + ff_mov_read_chan(c->fc, atom.size - 4, c->fc->streams[0]->codec); + return 0; +} + static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('a','v','s','s'), mov_read_extradata }, { MKTAG('c','h','p','l'), mov_read_chpl }, @@ -2263,6 +2298,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('w','i','d','e'), mov_read_wide }, /* place holder */ { MKTAG('w','f','e','x'), mov_read_wfex }, { MKTAG('c','m','o','v'), mov_read_cmov }, +{ MKTAG('c','h','a','n'), mov_read_chan }, { 0, NULL } }; @@ -2363,7 +2399,7 @@ static void mov_read_chapters(AVFormatContext *s) avio_get_str16le(sc->pb, len, title, title_len); else { AV_WB16(title, ch); - avio_get_str(sc->pb, len - 2, title + 2, title_len - 2); + get_strz(sc->pb, title + 2, len - 1); } ff_new_chapter(s, i, st->time_base, sample->timestamp, end, title); @@ -2443,7 +2479,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) mov->found_mdat = 0; if (s->pb->seekable|| mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || - s->pb->eof_reached) + url_feof(s->pb)) return AVERROR_EOF; av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb)); goto retry; @@ -2474,7 +2510,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) } #if CONFIG_DV_DEMUXER if (mov->dv_demux && sc->dv_audio_container) { - dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); + dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); av_free(pkt->data); pkt->size = 0; ret = dv_get_packet(mov->dv_demux, pkt); @@ -2609,12 +2645,12 @@ static int mov_read_close(AVFormatContext *s) } AVInputFormat ff_mov_demuxer = { - "mov,mp4,m4a,3gp,3g2,mj2", - NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"), - sizeof(MOVContext), - mov_probe, - mov_read_header, - mov_read_packet, - mov_read_close, - mov_read_seek, + .name = "mov,mp4,m4a,3gp,3g2,mj2", + .long_name = NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"), + .priv_data_size = sizeof(MOVContext), + .read_probe = mov_probe, + .read_header = mov_read_header, + .read_packet = mov_read_packet, + .read_close = mov_read_close, + .read_seek = mov_read_seek, };