diff options
Diffstat (limited to 'ffmpeg/libavformat')
295 files changed, 12119 insertions, 8089 deletions
diff --git a/ffmpeg/libavformat/4xm.c b/ffmpeg/libavformat/4xm.c index 1e142f5..23279c4 100644 --- a/ffmpeg/libavformat/4xm.c +++ b/ffmpeg/libavformat/4xm.c @@ -57,7 +57,7 @@ #define GET_LIST_HEADER() \ fourcc_tag = avio_rl32(pb); \ - size = avio_rl32(pb); \ + size = avio_rl32(pb); \ if (fourcc_tag != LIST_TAG) \ return AVERROR_INVALIDDATA; \ fourcc_tag = avio_rl32(pb); @@ -72,8 +72,6 @@ typedef struct AudioTrack { } AudioTrack; typedef struct FourxmDemuxContext { - int width; - int height; int video_stream_index; int track_count; AudioTrack *tracks; @@ -91,6 +89,108 @@ static int fourxm_probe(AVProbeData *p) return AVPROBE_SCORE_MAX; } +static int parse_vtrk(AVFormatContext *s, + FourxmDemuxContext *fourxm, uint8_t *buf, int size, + int left) +{ + AVStream *st; + /* check that there is enough data */ + if (size != vtrk_SIZE || left < size + 8) { + return AVERROR_INVALIDDATA; + } + + /* allocate a new AVStream */ + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + avpriv_set_pts_info(st, 60, 1, fourxm->fps); + + fourxm->video_stream_index = st->index; + + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_4XM; + st->codec->extradata_size = 4; + st->codec->extradata = av_malloc(4); + AV_WL32(st->codec->extradata, AV_RL32(buf + 16)); + st->codec->width = AV_RL32(buf + 36); + st->codec->height = AV_RL32(buf + 40); + + return 0; +} + + +static int parse_strk(AVFormatContext *s, + FourxmDemuxContext *fourxm, uint8_t *buf, int size, + int left) +{ + AVStream *st; + int track; + /* check that there is enough data */ + if (size != strk_SIZE || left < size + 8) + return AVERROR_INVALIDDATA; + + track = AV_RL32(buf + 8); + if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1) { + av_log(s, AV_LOG_ERROR, "current_track too large\n"); + return AVERROR_INVALIDDATA; + } + + if (track + 1 > fourxm->track_count) { + if (av_reallocp_array(&fourxm->tracks, track + 1, sizeof(AudioTrack))) + return AVERROR(ENOMEM); + memset(&fourxm->tracks[fourxm->track_count], 0, + sizeof(AudioTrack) * (track + 1 - fourxm->track_count)); + fourxm->track_count = track + 1; + } + fourxm->tracks[track].adpcm = AV_RL32(buf + 12); + fourxm->tracks[track].channels = AV_RL32(buf + 36); + fourxm->tracks[track].sample_rate = AV_RL32(buf + 40); + fourxm->tracks[track].bits = AV_RL32(buf + 44); + fourxm->tracks[track].audio_pts = 0; + + if (fourxm->tracks[track].channels <= 0 || + fourxm->tracks[track].sample_rate <= 0 || + fourxm->tracks[track].bits <= 0) { + av_log(s, AV_LOG_ERROR, "audio header invalid\n"); + return AVERROR_INVALIDDATA; + } + if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) { + av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n"); + return AVERROR_INVALIDDATA; + } + + /* allocate a new AVStream */ + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->id = track; + avpriv_set_pts_info(st, 60, 1, fourxm->tracks[track].sample_rate); + + fourxm->tracks[track].stream_index = st->index; + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_tag = 0; + st->codec->channels = fourxm->tracks[track].channels; + st->codec->sample_rate = fourxm->tracks[track].sample_rate; + st->codec->bits_per_coded_sample = fourxm->tracks[track].bits; + st->codec->bit_rate = st->codec->channels * + st->codec->sample_rate * + st->codec->bits_per_coded_sample; + st->codec->block_align = st->codec->channels * + st->codec->bits_per_coded_sample; + + if (fourxm->tracks[track].adpcm){ + st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM; + } else if (st->codec->bits_per_coded_sample == 8) { + st->codec->codec_id = AV_CODEC_ID_PCM_U8; + } else + st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; + + return 0; +} + static int fourxm_read_header(AVFormatContext *s) { AVIOContext *pb = s->pb; @@ -100,11 +200,10 @@ static int fourxm_read_header(AVFormatContext *s) FourxmDemuxContext *fourxm = s->priv_data; unsigned char *header; int i, ret; - AVStream *st; fourxm->track_count = 0; - fourxm->tracks = NULL; - fourxm->fps = 1.0; + fourxm->tracks = NULL; + fourxm->fps = 1.0; /* skip the first 3 32-bit numbers */ avio_skip(pb, 12); @@ -119,7 +218,7 @@ static int fourxm_read_header(AVFormatContext *s) header = av_malloc(header_size); if (!header) return AVERROR(ENOMEM); - if (avio_read(pb, header, header_size) != header_size){ + if (avio_read(pb, header, header_size) != header_size) { av_free(header); return AVERROR(EIO); } @@ -127,123 +226,38 @@ static int fourxm_read_header(AVFormatContext *s) /* take the lazy approach and search for any and all vtrk and strk chunks */ for (i = 0; i < header_size - 8; i++) { fourcc_tag = AV_RL32(&header[i]); - size = AV_RL32(&header[i + 4]); + size = AV_RL32(&header[i + 4]); if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) { av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8); return AVERROR_INVALIDDATA; } if (fourcc_tag == std__TAG) { - if (header_size < i + 16) { + if (header_size - i < 16) { av_log(s, AV_LOG_ERROR, "std TAG truncated\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } fourxm->fps = av_int2float(AV_RL32(&header[i + 12])); } else if (fourcc_tag == vtrk_TAG) { - /* check that there is enough data */ - if (size != vtrk_SIZE) { - ret= AVERROR_INVALIDDATA; + if ((ret = parse_vtrk(s, fourxm, header + i, size, + header_size - i)) < 0) goto fail; - } - fourxm->width = AV_RL32(&header[i + 36]); - fourxm->height = AV_RL32(&header[i + 40]); - - /* allocate a new AVStream */ - st = avformat_new_stream(s, NULL); - if (!st){ - ret= AVERROR(ENOMEM); - goto fail; - } - avpriv_set_pts_info(st, 60, 1, fourxm->fps); - - fourxm->video_stream_index = st->index; - - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = AV_CODEC_ID_4XM; - st->codec->extradata_size = 4; - st->codec->extradata = av_malloc(4); - AV_WL32(st->codec->extradata, AV_RL32(&header[i + 16])); - st->codec->width = fourxm->width; - st->codec->height = fourxm->height; i += 8 + size; } else if (fourcc_tag == strk_TAG) { - int current_track; - /* check that there is enough data */ - if (size != strk_SIZE) { - ret= AVERROR_INVALIDDATA; - goto fail; - } - current_track = AV_RL32(&header[i + 8]); - if((unsigned)current_track >= UINT_MAX / sizeof(AudioTrack) - 1){ - av_log(s, AV_LOG_ERROR, "current_track too large\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - if (current_track + 1 > fourxm->track_count) { - fourxm->tracks = av_realloc_f(fourxm->tracks, - sizeof(AudioTrack), - current_track + 1); - if (!fourxm->tracks) { - ret = AVERROR(ENOMEM); - goto fail; - } - memset(&fourxm->tracks[fourxm->track_count], 0, - sizeof(AudioTrack) * (current_track + 1 - fourxm->track_count)); - fourxm->track_count = current_track + 1; - } - fourxm->tracks[current_track].adpcm = AV_RL32(&header[i + 12]); - fourxm->tracks[current_track].channels = AV_RL32(&header[i + 36]); - fourxm->tracks[current_track].sample_rate = AV_RL32(&header[i + 40]); - fourxm->tracks[current_track].bits = AV_RL32(&header[i + 44]); - fourxm->tracks[current_track].audio_pts = 0; - if( fourxm->tracks[current_track].channels <= 0 - || fourxm->tracks[current_track].sample_rate <= 0 - || fourxm->tracks[current_track].bits < 0){ - av_log(s, AV_LOG_ERROR, "audio header invalid\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - if(!fourxm->tracks[current_track].adpcm && fourxm->tracks[current_track].bits<8){ - av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } - i += 8 + size; - - /* allocate a new AVStream */ - st = avformat_new_stream(s, NULL); - if (!st){ - ret= AVERROR(ENOMEM); + if ((ret = parse_strk(s, fourxm, header + i, size, + header_size - i)) < 0) goto fail; - } - st->id = current_track; - avpriv_set_pts_info(st, 60, 1, fourxm->tracks[current_track].sample_rate); - - fourxm->tracks[current_track].stream_index = st->index; - - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_tag = 0; - st->codec->channels = fourxm->tracks[current_track].channels; - st->codec->sample_rate = fourxm->tracks[current_track].sample_rate; - st->codec->bits_per_coded_sample = fourxm->tracks[current_track].bits; - st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * - st->codec->bits_per_coded_sample; - st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; - if (fourxm->tracks[current_track].adpcm){ - st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM; - }else if (st->codec->bits_per_coded_sample == 8){ - st->codec->codec_id = AV_CODEC_ID_PCM_U8; - }else - st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; + i += 8 + size; } } /* skip over the LIST-MOVI chunk (which is where the stream should be */ GET_LIST_HEADER(); - if (fourcc_tag != MOVI_TAG){ - ret= AVERROR_INVALIDDATA; + if (fourcc_tag != MOVI_TAG) { + ret = AVERROR_INVALIDDATA; goto fail; } @@ -262,7 +276,7 @@ static int fourxm_read_packet(AVFormatContext *s, AVPacket *pkt) { FourxmDemuxContext *fourxm = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; unsigned int fourcc_tag; unsigned int size; int ret = 0; @@ -272,18 +286,16 @@ static int fourxm_read_packet(AVFormatContext *s, int audio_frame_count; while (!packet_read) { - if ((ret = avio_read(s->pb, header, 8)) < 0) return ret; fourcc_tag = AV_RL32(&header[0]); - size = AV_RL32(&header[4]); + size = AV_RL32(&header[4]); if (url_feof(pb)) return AVERROR(EIO); switch (fourcc_tag) { - case LIST_TAG: /* this is a good time to bump the video pts */ - fourxm->video_pts ++; + fourxm->video_pts++; /* skip the LIST-* tag and move on to the next fourcc */ avio_rl32(pb); @@ -300,45 +312,45 @@ static int fourxm_read_packet(AVFormatContext *s, if (size + 8 < size || av_new_packet(pkt, size + 8)) return AVERROR(EIO); pkt->stream_index = fourxm->video_stream_index; - pkt->pts = fourxm->video_pts; - pkt->pos = avio_tell(s->pb); + pkt->pts = fourxm->video_pts; + pkt->pos = avio_tell(s->pb); memcpy(pkt->data, header, 8); ret = avio_read(s->pb, &pkt->data[8], size); - if (ret < 0){ + if (ret < 0) { av_free_packet(pkt); - }else + } else { packet_read = 1; + av_shrink_packet(pkt, ret + 8); + } break; case snd__TAG: track_number = avio_rl32(pb); avio_skip(pb, 4); - size-=8; + size -= 8; - if (track_number < fourxm->track_count && fourxm->tracks[track_number].channels>0) { - ret= av_get_packet(s->pb, pkt, size); - if(ret<0) + if (track_number < fourxm->track_count && + fourxm->tracks[track_number].channels > 0) { + ret = av_get_packet(s->pb, pkt, size); + if (ret < 0) return AVERROR(EIO); pkt->stream_index = fourxm->tracks[track_number].stream_index; - pkt->pts = fourxm->tracks[track_number].audio_pts; + pkt->pts = fourxm->tracks[track_number].audio_pts; packet_read = 1; /* pts accounting */ audio_frame_count = size; if (fourxm->tracks[track_number].adpcm) - audio_frame_count -= - 2 * (fourxm->tracks[track_number].channels); - audio_frame_count /= - fourxm->tracks[track_number].channels; - if (fourxm->tracks[track_number].adpcm){ + audio_frame_count -= 2 * (fourxm->tracks[track_number].channels); + audio_frame_count /= fourxm->tracks[track_number].channels; + if (fourxm->tracks[track_number].adpcm) { audio_frame_count *= 2; - }else + } else audio_frame_count /= - (fourxm->tracks[track_number].bits / 8); + (fourxm->tracks[track_number].bits / 8); fourxm->tracks[track_number].audio_pts += audio_frame_count; - } else { avio_skip(pb, size); } diff --git a/ffmpeg/libavformat/Makefile b/ffmpeg/libavformat/Makefile index bc6ea16..dc8cac6 100644 --- a/ffmpeg/libavformat/Makefile +++ b/ffmpeg/libavformat/Makefile @@ -11,6 +11,7 @@ OBJS = allformats.o \ avio.o \ aviobuf.o \ cutils.o \ + format.o \ id3v1.o \ id3v2.o \ metadata.o \ @@ -20,9 +21,12 @@ OBJS = allformats.o \ riff.o \ sdp.o \ seek.o \ + url.o \ utils.o \ OBJS-$(CONFIG_NETWORK) += network.o +OBJS-$(CONFIG_RIFFDEC) += riffdec.o +OBJS-$(CONFIG_RIFFENC) += riffenc.o OBJS-$(CONFIG_RTPDEC) += rdt.o \ rtp.o \ rtpdec.o \ @@ -50,14 +54,15 @@ OBJS-$(CONFIG_SHARED) += log2_tab.o # muxers/demuxers OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o -OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o rawdec.o +OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o apetag.o img2.o rawdec.o OBJS-$(CONFIG_AC3_DEMUXER) += ac3dec.o rawdec.o OBJS-$(CONFIG_AC3_MUXER) += rawenc.o OBJS-$(CONFIG_ACT_DEMUXER) += act.o OBJS-$(CONFIG_ADF_DEMUXER) += bintext.o sauce.o +OBJS-$(CONFIG_ADP_DEMUXER) += adp.o OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o OBJS-$(CONFIG_ADX_MUXER) += rawenc.o -OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o +OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o apetag.o img2.o OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o OBJS-$(CONFIG_AFC_DEMUXER) += afc.o OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o pcm.o isom.o \ @@ -91,6 +96,7 @@ OBJS-$(CONFIG_BINTEXT_DEMUXER) += bintext.o sauce.o OBJS-$(CONFIG_BIT_DEMUXER) += bit.o OBJS-$(CONFIG_BIT_MUXER) += bit.o OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o +OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ @@ -102,6 +108,8 @@ OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o OBJS-$(CONFIG_CRC_MUXER) += crcenc.o +OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o +OBJS-$(CONFIG_DATA_MUXER) += rawdec.o OBJS-$(CONFIG_DAUD_DEMUXER) += daud.o OBJS-$(CONFIG_DAUD_MUXER) += daud.o OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o @@ -128,6 +136,7 @@ OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o rawdec.o \ + flac_picture.o \ oggparsevorbis.o \ vorbiscomment.o OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \ @@ -155,8 +164,11 @@ OBJS-$(CONFIG_H263_DEMUXER) += h263dec.o rawdec.o OBJS-$(CONFIG_H263_MUXER) += rawenc.o OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o OBJS-$(CONFIG_H264_MUXER) += rawenc.o +OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o +OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o -OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o mpegtsenc.o +OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o +OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_ICO_MUXER) += icoenc.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o @@ -191,7 +203,7 @@ OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \ isom.o rmsipr.o OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ isom.o avc.o \ - flacenc_header.o avlanguage.o + flacenc_header.o avlanguage.o wv.o OBJS-$(CONFIG_MD5_MUXER) += md5enc.o OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o subtitles.o @@ -249,11 +261,14 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ oggparsespeex.o \ oggparsetheora.o \ oggparsevorbis.o \ - vorbiscomment.o + vorbiscomment.o \ + flac_picture.o OBJS-$(CONFIG_OGG_MUXER) += oggenc.o \ vorbiscomment.o OBJS-$(CONFIG_OMA_DEMUXER) += omadec.o pcm.o oma.o OBJS-$(CONFIG_OMA_MUXER) += omaenc.o rawenc.o oma.o id3v2enc.o +OBJS-$(CONFIG_OPUS_MUXER) += oggenc.o \ + vorbiscomment.o OBJS-$(CONFIG_PAF_DEMUXER) += paf.o OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += pcmdec.o pcm.o OBJS-$(CONFIG_PCM_ALAW_MUXER) += pcmenc.o rawenc.o @@ -304,11 +319,13 @@ OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o +OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o OBJS-$(CONFIG_RL2_DEMUXER) += rl2.o OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o rm.o rmsipr.o OBJS-$(CONFIG_RM_MUXER) += rmenc.o rm.o OBJS-$(CONFIG_ROQ_DEMUXER) += idroqdec.o OBJS-$(CONFIG_ROQ_MUXER) += idroqenc.o rawenc.o +OBJS-$(CONFIG_RSD_DEMUXER) += rsd.o OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o @@ -348,6 +365,8 @@ OBJS-$(CONFIG_SOX_DEMUXER) += soxdec.o pcm.o OBJS-$(CONFIG_SOX_MUXER) += soxenc.o rawenc.o OBJS-$(CONFIG_SPDIF_DEMUXER) += spdif.o spdifdec.o OBJS-$(CONFIG_SPDIF_MUXER) += spdif.o spdifenc.o +OBJS-$(CONFIG_SPEEX_MUXER) += oggenc.o \ + vorbiscomment.o OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o OBJS-$(CONFIG_SRT_MUXER) += srtenc.o OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o @@ -364,10 +383,11 @@ OBJS-$(CONFIG_MKVTIMESTAMP_V2_MUXER) += mkvtimestamp_v2.o OBJS-$(CONFIG_TMV_DEMUXER) += tmv.o OBJS-$(CONFIG_TRUEHD_DEMUXER) += rawdec.o OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o -OBJS-$(CONFIG_TTA_DEMUXER) += tta.o +OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o +OBJS-$(CONFIG_VC1_MUXER) += rawenc.o OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o @@ -384,15 +404,16 @@ OBJS-$(CONFIG_WAV_MUXER) += wavenc.o OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \ isom.o avc.o \ - flacenc_header.o avlanguage.o + flacenc_header.o avlanguage.o wv.o OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o +OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o -OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv.o asfdec.o asf.o asfcrypt.o \ +OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o asfdec.o asf.o asfcrypt.o \ avlanguage.o mpegts.o isom.o -OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv.o asf.o asfenc.o -OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o img2.o -OBJS-$(CONFIG_WV_MUXER) += wvenc.o apetagenc.o +OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o asf.o asfenc.o +OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o wv.o apetag.o img2.o +OBJS-$(CONFIG_WV_MUXER) += wvenc.o wv.o apetag.o img2.o OBJS-$(CONFIG_XA_DEMUXER) += xa.o OBJS-$(CONFIG_XBIN_DEMUXER) += bintext.o sauce.o OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o @@ -402,10 +423,13 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o # external libraries +OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o +OBJS-$(CONFIG_LIBQUVI_DEMUXER) += libquvi.o OBJS-$(CONFIG_LIBRTMP) += librtmp.o +OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o # protocols I/O OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o @@ -417,6 +441,7 @@ OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o +OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o OBJS-$(CONFIG_HLS_PROTOCOL) += hlsproto.o OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o urldecode.o @@ -438,14 +463,21 @@ OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o +OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o + +OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o + +# Windows resource file +SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h -TESTPROGS = noproxy \ - seek \ +TESTPROGS = seek \ srtp \ url \ +TESTPROGS-$(CONFIG_NETWORK) += noproxy + TOOLS = aviocat \ ismindex \ pktdumper \ diff --git a/ffmpeg/libavformat/aacdec.c b/ffmpeg/libavformat/aacdec.c index 7c17dd0..d93e75e 100644 --- a/ffmpeg/libavformat/aacdec.c +++ b/ffmpeg/libavformat/aacdec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "rawdec.h" #include "id3v1.h" - +#include "apetag.h" static int adts_aac_probe(AVProbeData *p) { @@ -55,9 +55,9 @@ static int adts_aac_probe(AVProbeData *p) if(buf == buf0) first_frames= frames; } - if (first_frames>=3) return AVPROBE_SCORE_MAX/2+1; - else if(max_frames>500)return AVPROBE_SCORE_MAX/2; - else if(max_frames>=3) return AVPROBE_SCORE_MAX/4; + if (first_frames>=3) return AVPROBE_SCORE_EXTENSION + 1; + else if(max_frames>500)return AVPROBE_SCORE_EXTENSION; + else if(max_frames>=3) return AVPROBE_SCORE_EXTENSION / 2; else if(max_frames>=1) return 1; else return 0; } @@ -75,6 +75,12 @@ static int adts_aac_read_header(AVFormatContext *s) st->need_parsing = AVSTREAM_PARSE_FULL_RAW; ff_id3v1_read(s); + if (s->pb->seekable && + !av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + int64_t cur = avio_tell(s->pb); + ff_ape_parse_tag(s); + avio_seek(s->pb, cur, SEEK_SET); + } //LCM of all possible ADTS sample rates avpriv_set_pts_info(st, 64, 1, 28224000); diff --git a/ffmpeg/libavformat/ac3dec.c b/ffmpeg/libavformat/ac3dec.c index c531f8a..3db2339 100644 --- a/ffmpeg/libavformat/ac3dec.c +++ b/ffmpeg/libavformat/ac3dec.c @@ -79,9 +79,9 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) if(codec_id != expected_codec_id) return 0; // keep this in sync with mp3 probe, both need to avoid // issues with MPEG-files! - if (first_frames>=4) return AVPROBE_SCORE_MAX/2+1; - else if(max_frames>200)return AVPROBE_SCORE_MAX/2; - else if(max_frames>=4) return AVPROBE_SCORE_MAX/4; + if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1; + else if(max_frames>200)return AVPROBE_SCORE_EXTENSION; + else if(max_frames>=4) return AVPROBE_SCORE_EXTENSION/2; else if(max_frames>=1) return 1; else return 0; } diff --git a/ffmpeg/libavformat/act.c b/ffmpeg/libavformat/act.c index 78f1d3b..3f223d5 100644 --- a/ffmpeg/libavformat/act.c +++ b/ffmpeg/libavformat/act.c @@ -42,7 +42,7 @@ static int probe(AVProbeData *p) (AV_RL32(&p->buf[16]) != 16)) return 0; - //We cant be sure that this is ACT and not regular WAV + //We can't be sure that this is ACT and not regular WAV if (p->buf_size<512) return 0; diff --git a/ffmpeg/libavformat/adtsenc.c b/ffmpeg/libavformat/adtsenc.c index 14c72a8..f25f966 100644 --- a/ffmpeg/libavformat/adtsenc.c +++ b/ffmpeg/libavformat/adtsenc.c @@ -24,16 +24,20 @@ #include "libavcodec/put_bits.h" #include "libavcodec/avcodec.h" #include "libavcodec/mpeg4audio.h" +#include "libavutil/opt.h" #include "avformat.h" +#include "apetag.h" #define ADTS_HEADER_SIZE 7 typedef struct { + AVClass *class; int write_adts; int objecttype; int sample_rate_index; int channel_conf; int pce_size; + int apetag; uint8_t pce_data[MAX_PCE_SIZE]; } ADTSContext; @@ -158,11 +162,34 @@ static int adts_write_packet(AVFormatContext *s, AVPacket *pkt) } } avio_write(pb, pkt->data, pkt->size); - avio_flush(pb); return 0; } +static int adts_write_trailer(AVFormatContext *s) +{ + ADTSContext *adts = s->priv_data; + + if (adts->apetag) + ff_ape_write_tag(s); + + return 0; +} + +#define ENC AV_OPT_FLAG_ENCODING_PARAM +#define OFFSET(obj) offsetof(ADTSContext, obj) +static const AVOption options[] = { + { "write_apetag", "Enable APE tag writing", OFFSET(apetag), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC}, + { NULL }, +}; + +static const AVClass adts_muxer_class = { + .class_name = "ADTS muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_adts_muxer = { .name = "adts", .long_name = NULL_IF_CONFIG_SMALL("ADTS AAC (Advanced Audio Coding)"), @@ -173,4 +200,6 @@ AVOutputFormat ff_adts_muxer = { .video_codec = AV_CODEC_ID_NONE, .write_header = adts_write_header, .write_packet = adts_write_packet, + .write_trailer = adts_write_trailer, + .priv_class = &adts_muxer_class, }; diff --git a/ffmpeg/libavformat/adxdec.c b/ffmpeg/libavformat/adxdec.c index 49e1930..fe22c3a 100644 --- a/ffmpeg/libavformat/adxdec.c +++ b/ffmpeg/libavformat/adxdec.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2011 Justin Ruggles * - * 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 */ @@ -78,14 +78,8 @@ static int adx_read_header(AVFormatContext *s) c->header_size = avio_rb16(s->pb) + 4; avio_seek(s->pb, -4, SEEK_CUR); - avctx->extradata = av_mallocz(c->header_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!avctx->extradata) + if (ff_get_extradata(avctx, s->pb, c->header_size) < 0) return AVERROR(ENOMEM); - if (avio_read(s->pb, avctx->extradata, c->header_size) < c->header_size) { - av_freep(&avctx->extradata); - return AVERROR(EIO); - } - avctx->extradata_size = c->header_size; ret = avpriv_adx_decode_header(avctx, avctx->extradata, avctx->extradata_size, &c->header_size, diff --git a/ffmpeg/libavformat/afc.c b/ffmpeg/libavformat/afc.c index 183a8e0..8dbd232 100644 --- a/ffmpeg/libavformat/afc.c +++ b/ffmpeg/libavformat/afc.c @@ -39,10 +39,8 @@ static int afc_read_header(AVFormatContext *s) st->codec->codec_id = AV_CODEC_ID_ADPCM_AFC; st->codec->channels = 2; st->codec->channel_layout = AV_CH_LAYOUT_STEREO; - st->codec->extradata_size = 1; - st->codec->extradata = av_mallocz(1 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, 1)) return AVERROR(ENOMEM); st->codec->extradata[0] = 8 * st->codec->channels; diff --git a/ffmpeg/libavformat/aiff.h b/ffmpeg/libavformat/aiff.h index b3ef577..4470254 100644 --- a/ffmpeg/libavformat/aiff.h +++ b/ffmpeg/libavformat/aiff.h @@ -45,7 +45,8 @@ static const AVCodecTag ff_codec_aiff_tags[] = { { AV_CODEC_ID_MACE3, MKTAG('M','A','C','3') }, { AV_CODEC_ID_MACE6, MKTAG('M','A','C','6') }, { AV_CODEC_ID_GSM, MKTAG('G','S','M',' ') }, - { AV_CODEC_ID_ADPCM_G726, MKTAG('G','7','2','6') }, + { AV_CODEC_ID_ADPCM_G722, MKTAG('G','7','2','2') }, + { AV_CODEC_ID_ADPCM_G726LE, MKTAG('G','7','2','6') }, { AV_CODEC_ID_PCM_S16BE, MKTAG('t','w','o','s') }, { AV_CODEC_ID_PCM_S16LE, MKTAG('s','o','w','t') }, { AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') }, diff --git a/ffmpeg/libavformat/aiffdec.c b/ffmpeg/libavformat/aiffdec.c index 8d466fa..c362071 100644 --- a/ffmpeg/libavformat/aiffdec.c +++ b/ffmpeg/libavformat/aiffdec.c @@ -141,15 +141,15 @@ static unsigned int get_aiff_header(AVFormatContext *s, int size, case AV_CODEC_ID_MACE3: codec->block_align = 2*codec->channels; break; + case AV_CODEC_ID_ADPCM_G726LE: + codec->bits_per_coded_sample = 5; + case AV_CODEC_ID_ADPCM_G722: case AV_CODEC_ID_MACE6: codec->block_align = 1*codec->channels; break; case AV_CODEC_ID_GSM: codec->block_align = 33; break; - case AV_CODEC_ID_QCELP: - codec->block_align = 35; - break; default: aiff->block_duration = 1; break; @@ -192,7 +192,7 @@ static int aiff_probe(AVProbeData *p) static int aiff_read_header(AVFormatContext *s) { int ret, size, filesize; - int64_t offset = 0; + int64_t offset = 0, position; uint32_t tag; unsigned version = AIFF_C_VERSION1; AVIOContext *pb = s->pb; @@ -236,6 +236,7 @@ static int aiff_read_header(AVFormatContext *s) goto got_sound; break; case MKTAG('I', 'D', '3', ' '): + position = avio_tell(pb); ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); if (id3v2_extra_meta) if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) { @@ -243,6 +244,8 @@ static int aiff_read_header(AVFormatContext *s) return ret; } ff_id3v2_free_extra_meta(&id3v2_extra_meta); + if (position + size > avio_tell(pb)) + avio_skip(pb, position + size - avio_tell(pb)); break; case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */ version = avio_rb32(pb); @@ -275,14 +278,26 @@ static int aiff_read_header(AVFormatContext *s) case MKTAG('w', 'a', 'v', 'e'): if ((uint64_t)size > (1<<30)) return -1; - st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - st->codec->extradata_size = size; - avio_read(pb, st->codec->extradata, size); if (st->codec->codec_id == AV_CODEC_ID_QDM2 && size>=12*4 && !st->codec->block_align) { st->codec->block_align = AV_RB32(st->codec->extradata+11*4); aiff->block_duration = AV_RB32(st->codec->extradata+9*4); + } else if (st->codec->codec_id == AV_CODEC_ID_QCELP) { + char rate = 0; + if (size >= 25) + rate = st->codec->extradata[24]; + switch (rate) { + case 'H': // RATE_HALF + st->codec->block_align = 17; + break; + case 'F': // RATE_FULL + default: + st->codec->block_align = 35; + } + aiff->block_duration = 160; + st->codec->bit_rate = st->codec->sample_rate * (st->codec->block_align << 3) / + aiff->block_duration; } break; case MKTAG('C','H','A','N'): @@ -329,7 +344,7 @@ static int aiff_read_packet(AVFormatContext *s, return AVERROR_EOF; /* Now for that packet */ - if (st->codec->block_align >= 33) // GSM, QCLP, IMA4 + if (st->codec->block_align >= 17) // GSM, QCLP, IMA4 size = st->codec->block_align; else size = (MAX_SIZE / st->codec->block_align) * st->codec->block_align; diff --git a/ffmpeg/libavformat/aiffenc.c b/ffmpeg/libavformat/aiffenc.c index 7c0b4fb..6e3d8bc 100644 --- a/ffmpeg/libavformat/aiffenc.c +++ b/ffmpeg/libavformat/aiffenc.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "libavutil/intfloat.h" #include "libavutil/opt.h" #include "avformat.h" diff --git a/ffmpeg/libavformat/allformats.c b/ffmpeg/libavformat/allformats.c index 8c746ff..f1039dd 100644 --- a/ffmpeg/libavformat/allformats.c +++ b/ffmpeg/libavformat/allformats.c @@ -45,8 +45,7 @@ { \ extern URLProtocol ff_##x##_protocol; \ if (CONFIG_##X##_PROTOCOL) \ - ffurl_register_protocol(&ff_##x##_protocol, \ - sizeof(ff_##x##_protocol)); \ + ffurl_register_protocol(&ff_##x##_protocol); \ } void av_register_all(void) @@ -65,6 +64,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(AC3, ac3); REGISTER_DEMUXER (ACT, act); REGISTER_DEMUXER (ADF, adf); + REGISTER_DEMUXER (ADP, adp); REGISTER_MUXER (ADTS, adts); REGISTER_MUXDEMUX(ADX, adx); REGISTER_DEMUXER (AEA, aea); @@ -92,6 +92,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(BIT, bit); REGISTER_DEMUXER (BMV, bmv); REGISTER_DEMUXER (BRSTM, brstm); + REGISTER_DEMUXER (BOA, boa); REGISTER_DEMUXER (C93, c93); REGISTER_MUXDEMUX(CAF, caf); REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo); @@ -99,6 +100,7 @@ void av_register_all(void) REGISTER_DEMUXER (CDXL, cdxl); REGISTER_DEMUXER (CONCAT, concat); REGISTER_MUXER (CRC, crc); + REGISTER_MUXDEMUX(DATA, data); REGISTER_MUXDEMUX(DAUD, daud); REGISTER_DEMUXER (DFA, dfa); REGISTER_MUXDEMUX(DIRAC, dirac); @@ -132,7 +134,10 @@ void av_register_all(void) REGISTER_MUXDEMUX(H261, h261); REGISTER_MUXDEMUX(H263, h263); REGISTER_MUXDEMUX(H264, h264); + REGISTER_MUXER (HDS, hds); + REGISTER_DEMUXER (HEVC, hevc); REGISTER_MUXDEMUX(HLS, hls); + REGISTER_DEMUXER (HNM, hnm); REGISTER_MUXDEMUX(ICO, ico); REGISTER_DEMUXER (IDCIN, idcin); REGISTER_DEMUXER (IDF, idf); @@ -200,6 +205,7 @@ void av_register_all(void) REGISTER_DEMUXER (NUV, nuv); REGISTER_MUXDEMUX(OGG, ogg); REGISTER_MUXDEMUX(OMA, oma); + REGISTER_MUXER (OPUS, opus); REGISTER_DEMUXER (PAF, paf); REGISTER_MUXDEMUX(PCM_ALAW, pcm_alaw); REGISTER_MUXDEMUX(PCM_MULAW, pcm_mulaw); @@ -230,10 +236,12 @@ void av_register_all(void) REGISTER_DEMUXER (R3D, r3d); REGISTER_MUXDEMUX(RAWVIDEO, rawvideo); REGISTER_DEMUXER (REALTEXT, realtext); + REGISTER_DEMUXER (REDSPARK, redspark); REGISTER_DEMUXER (RL2, rl2); REGISTER_MUXDEMUX(RM, rm); REGISTER_MUXDEMUX(ROQ, roq); REGISTER_DEMUXER (RPL, rpl); + REGISTER_DEMUXER (RSD, rsd); REGISTER_MUXDEMUX(RSO, rso); REGISTER_MUXDEMUX(RTP, rtp); REGISTER_MUXDEMUX(RTSP, rtsp); @@ -242,8 +250,8 @@ void av_register_all(void) REGISTER_DEMUXER (SBG, sbg); REGISTER_DEMUXER (SDP, sdp); #if CONFIG_RTPDEC - av_register_rtp_dynamic_payload_handlers(); - av_register_rdt_dynamic_payload_handlers(); + ff_register_rtp_dynamic_payload_handlers(); + ff_register_rdt_dynamic_payload_handlers(); #endif REGISTER_DEMUXER (SEGAFILM, segafilm); REGISTER_MUXER (SEGMENT, segment); @@ -257,13 +265,14 @@ void av_register_all(void) REGISTER_DEMUXER (SOL, sol); REGISTER_MUXDEMUX(SOX, sox); REGISTER_MUXDEMUX(SPDIF, spdif); + REGISTER_MUXER (SPEEX, speex); REGISTER_MUXDEMUX(SRT, srt); REGISTER_DEMUXER (STR, str); REGISTER_DEMUXER (SUBVIEWER1, subviewer1); REGISTER_DEMUXER (SUBVIEWER, subviewer); REGISTER_MUXDEMUX(SWF, swf); REGISTER_DEMUXER (TAK, tak); - REGISTER_MUXER (TEE, tee); + REGISTER_MUXER (TEE, tee); REGISTER_DEMUXER (TEDCAPTIONS, tedcaptions); REGISTER_MUXER (TG2, tg2); REGISTER_MUXER (TGP, tgp); @@ -287,7 +296,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(WAV, wav); REGISTER_DEMUXER (WC3, wc3); REGISTER_MUXER (WEBM, webm); - REGISTER_DEMUXER (WEBVTT, webvtt); + REGISTER_MUXDEMUX(WEBVTT, webvtt); REGISTER_DEMUXER (WSAUD, wsaud); REGISTER_DEMUXER (WSVQA, wsvqa); REGISTER_MUXDEMUX(WTV, wtv); @@ -308,6 +317,7 @@ void av_register_all(void) REGISTER_PROTOCOL(FFRTMPCRYPT, ffrtmpcrypt); REGISTER_PROTOCOL(FFRTMPHTTP, ffrtmphttp); REGISTER_PROTOCOL(FILE, file); + REGISTER_PROTOCOL(FTP, ftp); REGISTER_PROTOCOL(GOPHER, gopher); REGISTER_PROTOCOL(HLS, hls); REGISTER_PROTOCOL(HTTP, http); @@ -329,13 +339,17 @@ void av_register_all(void) REGISTER_PROTOCOL(TCP, tcp); REGISTER_PROTOCOL(TLS, tls); REGISTER_PROTOCOL(UDP, udp); + REGISTER_PROTOCOL(UNIX, unix); /* external libraries */ + REGISTER_DEMUXER (LIBGME, libgme); REGISTER_DEMUXER (LIBMODPLUG, libmodplug); REGISTER_MUXDEMUX(LIBNUT, libnut); + REGISTER_DEMUXER (LIBQUVI, libquvi); REGISTER_PROTOCOL(LIBRTMP, librtmp); REGISTER_PROTOCOL(LIBRTMPE, librtmpe); REGISTER_PROTOCOL(LIBRTMPS, librtmps); REGISTER_PROTOCOL(LIBRTMPT, librtmpt); REGISTER_PROTOCOL(LIBRTMPTE, librtmpte); + REGISTER_PROTOCOL(LIBSSH, libssh); } diff --git a/ffmpeg/libavformat/amr.c b/ffmpeg/libavformat/amr.c index 07ab1ba..db9bb4e 100644 --- a/ffmpeg/libavformat/amr.c +++ b/ffmpeg/libavformat/amr.c @@ -56,7 +56,6 @@ static int amr_write_header(AVFormatContext *s) static int amr_write_packet(AVFormatContext *s, AVPacket *pkt) { avio_write(s->pb, pkt->data, pkt->size); - avio_flush(s->pb); return 0; } #endif /* CONFIG_AMR_MUXER */ @@ -133,8 +132,6 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) }; size = packed_size[mode]; - } else { - av_assert0(0); } if (!size || av_new_packet(pkt, size)) diff --git a/ffmpeg/libavformat/apc.c b/ffmpeg/libavformat/apc.c index bb28a62..21bb514 100644 --- a/ffmpeg/libavformat/apc.c +++ b/ffmpeg/libavformat/apc.c @@ -23,6 +23,7 @@ #include "libavutil/channel_layout.h" #include "avformat.h" +#include "internal.h" static int apc_probe(AVProbeData *p) { @@ -51,14 +52,9 @@ static int apc_read_header(AVFormatContext *s) avio_rl32(pb); /* number of samples */ st->codec->sample_rate = avio_rl32(pb); - st->codec->extradata_size = 2 * 4; - st->codec->extradata = av_malloc(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - /* initial predictor values for adpcm decoder */ - avio_read(pb, st->codec->extradata, 2 * 4); + if (ff_get_extradata(st->codec, pb, 2 * 4) < 0) + return AVERROR(ENOMEM); if (avio_rl32(pb)) { st->codec->channels = 2; diff --git a/ffmpeg/libavformat/ape.c b/ffmpeg/libavformat/ape.c index 09ed9c5..b677ba9 100644 --- a/ffmpeg/libavformat/ape.c +++ b/ffmpeg/libavformat/ape.c @@ -28,7 +28,7 @@ #include "apetag.h" /* The earliest and latest file formats supported by this library */ -#define APE_MIN_VERSION 3930 +#define APE_MIN_VERSION 3800 #define APE_MAX_VERSION 3990 #define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE] @@ -81,14 +81,19 @@ typedef struct { /* Seektable */ uint32_t *seektable; + uint8_t *bittable; } APEContext; static int ape_probe(AVProbeData * p) { - if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ') - return AVPROBE_SCORE_MAX; + int version = AV_RL16(p->buf+4); + if (AV_RL32(p->buf) != MKTAG('M', 'A', 'C', ' ')) + return 0; - return 0; + if (version < APE_MIN_VERSION || version > APE_MAX_VERSION) + return AVPROBE_SCORE_MAX/4; + + return AVPROBE_SCORE_MAX; } static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx) @@ -128,9 +133,13 @@ static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx) } else { for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) { if (i < ape_ctx->totalframes - 1) { - av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32" (%"PRIu32" bytes)\n", + av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32" (%"PRIu32" bytes)", i, ape_ctx->seektable[i], ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]); + if (ape_ctx->bittable) + av_log(s, AV_LOG_DEBUG, " + %2d bits\n", + ape_ctx->bittable[i]); + av_log(s, AV_LOG_DEBUG, "\n"); } else { av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32"\n", i, ape_ctx->seektable[i]); } @@ -253,7 +262,7 @@ static int ape_read_header(AVFormatContext * s) ape->totalframes); return AVERROR_INVALIDDATA; } - if (ape->seektablelength && (ape->seektablelength / sizeof(*ape->seektable)) < ape->totalframes) { + if (ape->seektablelength / sizeof(*ape->seektable) < ape->totalframes) { av_log(s, AV_LOG_ERROR, "Number of seek entries is less than number of frames: %zu vs. %"PRIu32"\n", ape->seektablelength / sizeof(*ape->seektable), ape->totalframes); @@ -263,6 +272,8 @@ static int ape_read_header(AVFormatContext * s) if(!ape->frames) return AVERROR(ENOMEM); ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength; + if (ape->fileversion < 3810) + ape->firstframe += ape->totalframes; ape->currentframe = 0; @@ -271,14 +282,20 @@ static int ape_read_header(AVFormatContext * s) ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1); if (ape->seektablelength > 0) { - ape->seektable = av_malloc(ape->seektablelength); + ape->seektable = av_mallocz(ape->seektablelength); if (!ape->seektable) return AVERROR(ENOMEM); - for (i = 0; i < ape->seektablelength / sizeof(uint32_t); i++) + for (i = 0; i < ape->seektablelength / sizeof(uint32_t) && !pb->eof_reached; i++) ape->seektable[i] = avio_rl32(pb); - }else{ - av_log(s, AV_LOG_ERROR, "Missing seektable\n"); - return AVERROR_INVALIDDATA; + if (ape->fileversion < 3810) { + ape->bittable = av_mallocz(ape->totalframes); + if (!ape->bittable) + return AVERROR(ENOMEM); + for (i = 0; i < ape->totalframes && !pb->eof_reached; i++) + ape->bittable[i] = avio_r8(pb); + } + if (pb->eof_reached) + av_log(s, AV_LOG_WARNING, "File truncated\n"); } ape->frames[0].pos = ape->firstframe; @@ -309,7 +326,14 @@ static int ape_read_header(AVFormatContext * s) } ape->frames[i].size = (ape->frames[i].size + 3) & ~3; } - + if (ape->fileversion < 3810) { + for (i = 0; i < ape->totalframes; i++) { + if (i < ape->totalframes - 1 && ape->bittable[i + 1]) + ape->frames[i].size += 4; + ape->frames[i].skip <<= 3; + ape->frames[i].skip += ape->bittable[i]; + } + } ape_dumpinfo(s, ape); @@ -336,8 +360,8 @@ static int ape_read_header(AVFormatContext * s) st->duration = total_blocks; avpriv_set_pts_info(st, 64, 1, ape->samplerate); - st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE); - st->codec->extradata_size = APE_EXTRADATA_SIZE; + if (ff_alloc_extradata(st->codec, APE_EXTRADATA_SIZE)) + return AVERROR(ENOMEM); AV_WL16(st->codec->extradata + 0, ape->fileversion); AV_WL16(st->codec->extradata + 2, ape->compressiontype); AV_WL16(st->codec->extradata + 4, ape->formatflags); @@ -393,6 +417,10 @@ static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) AV_WL32(pkt->data , nblocks); AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip); ret = avio_read(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size); + if (ret < 0) { + av_free_packet(pkt); + return ret; + } pkt->pts = ape->frames[ape->currentframe].pts; pkt->stream_index = 0; @@ -412,6 +440,7 @@ static int ape_read_close(AVFormatContext * s) av_freep(&ape->frames); av_freep(&ape->seektable); + av_freep(&ape->bittable); return 0; } diff --git a/ffmpeg/libavformat/apetag.c b/ffmpeg/libavformat/apetag.c index a445c84..6e59bc7 100644 --- a/ffmpeg/libavformat/apetag.c +++ b/ffmpeg/libavformat/apetag.c @@ -23,10 +23,12 @@ #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "avformat.h" +#include "avio_internal.h" #include "apetag.h" #include "internal.h" #define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) +#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30) #define APE_TAG_FLAG_IS_HEADER (1 << 29) #define APE_TAG_FLAG_IS_BINARY (1 << 1) @@ -86,14 +88,8 @@ static int ape_tag_read_field(AVFormatContext *s) st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; } else { - st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, s->pb, size) < 0) return AVERROR(ENOMEM); - if (avio_read(pb, st->codec->extradata, size) != size) { - av_freep(&st->codec->extradata); - return AVERROR(EIO); - } - st->codec->extradata_size = size; st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; } } else { @@ -114,7 +110,7 @@ static int ape_tag_read_field(AVFormatContext *s) int64_t ff_ape_parse_tag(AVFormatContext *s) { AVIOContext *pb = s->pb; - int file_size = avio_size(pb); + int64_t file_size = avio_size(pb); uint32_t val, fields, tag_bytes; uint8_t buf[8]; int64_t tag_start; @@ -167,3 +163,73 @@ int64_t ff_ape_parse_tag(AVFormatContext *s) return tag_start; } + +static int string_is_ascii(const uint8_t *str) +{ + while (*str && *str >= 0x20 && *str <= 0x7e ) str++; + return !*str; +} + +int ff_ape_write_tag(AVFormatContext *s) +{ + AVDictionaryEntry *e = NULL; + int size, ret, count = 0; + AVIOContext *dyn_bc = NULL; + uint8_t *dyn_buf = NULL; + + if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0) + goto end; + + // flags + avio_wl32(dyn_bc, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER | + APE_TAG_FLAG_IS_HEADER); + ffio_fill(dyn_bc, 0, 8); // reserved + + while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) { + int val_len; + + if (!string_is_ascii(e->key)) { + av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n"); + continue; + } + + val_len = strlen(e->value); + avio_wl32(dyn_bc, val_len); // value length + avio_wl32(dyn_bc, 0); // item flags + avio_put_str(dyn_bc, e->key); // key + avio_write(dyn_bc, e->value, val_len); // value + count++; + } + if (!count) + goto end; + + size = avio_close_dyn_buf(dyn_bc, &dyn_buf); + if (size <= 0) + goto end; + size += 20; + + // header + avio_write(s->pb, "APETAGEX", 8); // id + avio_wl32(s->pb, APE_TAG_VERSION); // version + avio_wl32(s->pb, size); + avio_wl32(s->pb, count); + + avio_write(s->pb, dyn_buf, size - 20); + + // footer + avio_write(s->pb, "APETAGEX", 8); // id + avio_wl32(s->pb, APE_TAG_VERSION); // version + avio_wl32(s->pb, size); // size + avio_wl32(s->pb, count); // tag count + + // flags + avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER); + ffio_fill(s->pb, 0, 8); // reserved + +end: + if (dyn_bc && !dyn_buf) + avio_close_dyn_buf(dyn_bc, &dyn_buf); + av_freep(&dyn_buf); + + return ret; +} diff --git a/ffmpeg/libavformat/apetag.h b/ffmpeg/libavformat/apetag.h index 0330c89..cf2a5f8 100644 --- a/ffmpeg/libavformat/apetag.h +++ b/ffmpeg/libavformat/apetag.h @@ -37,8 +37,8 @@ int64_t ff_ape_parse_tag(AVFormatContext *s); /** - * Write an APEv2 tag + * Write an APE tag into a file. */ -void ff_ape_write(AVFormatContext *s); +int ff_ape_write_tag(AVFormatContext *s); #endif /* AVFORMAT_APETAG_H */ diff --git a/ffmpeg/libavformat/apetagenc.c b/ffmpeg/libavformat/apetagenc.c deleted file mode 100644 index 42f5836..0000000 --- a/ffmpeg/libavformat/apetagenc.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * APE tag writer - * Copyright (c) 2012 Paul B Mahol - * - * This file is part of FFmpeg. - * - * 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. - * - * 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 FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/dict.h" -#include "avio_internal.h" -#include "avformat.h" -#include "apetag.h" - -static int string_is_ascii(const uint8_t *str) -{ - while (*str && *str >= 0x20 && *str <= 0x7e ) str++; - return !*str; -} - -void ff_ape_write(AVFormatContext *s) -{ - int64_t tag_bytes; - AVDictionaryEntry *t = NULL; - AVIOContext *pb = s->pb; - int tags = 0, vlen; - - tag_bytes = avio_tell(s->pb); - while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { - if (!string_is_ascii(t->key)) { - av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n"); - continue; - } - - vlen = strlen(t->value); - avio_wl32(pb, vlen + 1); - avio_wl32(pb, 0); // flags - avio_put_str(pb, t->key); - avio_put_str(pb, t->value); - tags++; - } - tag_bytes = avio_tell(s->pb) - tag_bytes; - - if (!tags) - return; - - avio_write(pb, APE_TAG_PREAMBLE, 8); - avio_wl32(pb, APE_TAG_VERSION); - avio_wl32(pb, tag_bytes + APE_TAG_FOOTER_BYTES); - avio_wl32(pb, tags); // item count - avio_wl32(pb, 0); // global flags - ffio_fill(pb, 0, 8); // reserved -} diff --git a/ffmpeg/libavformat/aqtitledec.c b/ffmpeg/libavformat/aqtitledec.c index 325946c..810f95b 100644 --- a/ffmpeg/libavformat/aqtitledec.c +++ b/ffmpeg/libavformat/aqtitledec.c @@ -43,7 +43,7 @@ static int aqt_probe(AVProbeData *p) const char *ptr = p->buf; if (sscanf(ptr, "-->> %d", &frame) == 1) - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; return 0; } @@ -70,7 +70,7 @@ static int aqt_read_header(AVFormatContext *s) line[strcspn(line, "\r\n")] = 0; - if (sscanf(line, "-->> %"PRId64, &frame) == 1) { + if (sscanf(line, "-->> %"SCNd64, &frame) == 1) { new_event = 1; pos = avio_tell(s->pb); if (sub) { diff --git a/ffmpeg/libavformat/asf.c b/ffmpeg/libavformat/asf.c index dd64a3f..80d24db 100644 --- a/ffmpeg/libavformat/asf.c +++ b/ffmpeg/libavformat/asf.c @@ -117,6 +117,10 @@ const ff_asf_guid ff_asf_marker_header = { 0x01, 0xCD, 0x87, 0xF4, 0x51, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65 }; +const ff_asf_guid ff_asf_reserved_4 = { + 0x20, 0xdb, 0xfe, 0x4c, 0xf6, 0x75, 0xCF, 0x11, 0x9c, 0x0f, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb +}; + /* I am not a number !!! This GUID is the one found on the PC used to * generate the stream */ const ff_asf_guid ff_asf_my_guid = { diff --git a/ffmpeg/libavformat/asf.h b/ffmpeg/libavformat/asf.h index 5ffc746..acad64d 100644 --- a/ffmpeg/libavformat/asf.h +++ b/ffmpeg/libavformat/asf.h @@ -39,8 +39,11 @@ typedef struct ASFStream { /* use for reading */ AVPacket pkt; int frag_offset; + int packet_obj_size; int timestamp; int64_t duration; + int skip_to_key; + int pkt_clean; int ds_span; /* descrambling */ int ds_packet_size; @@ -86,6 +89,8 @@ typedef struct ASFMainHeader { typedef struct ASFIndex { uint32_t packet_number; uint16_t packet_count; + uint64_t send_time; + uint64_t offset; } ASFIndex; extern const ff_asf_guid ff_asf_header; @@ -112,6 +117,7 @@ extern const ff_asf_guid ff_asf_ext_stream_audio_stream; extern const ff_asf_guid ff_asf_metadata_header; extern const ff_asf_guid ff_asf_metadata_library_header; extern const ff_asf_guid ff_asf_marker_header; +extern const ff_asf_guid ff_asf_reserved_4; extern const ff_asf_guid ff_asf_my_guid; extern const ff_asf_guid ff_asf_language_guid; extern const ff_asf_guid ff_asf_content_encryption; diff --git a/ffmpeg/libavformat/asfdec.c b/ffmpeg/libavformat/asfdec.c index 1d7f26c..1f8b25c 100644 --- a/ffmpeg/libavformat/asfdec.c +++ b/ffmpeg/libavformat/asfdec.c @@ -19,14 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -//#define DEBUG - #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bswap.h" #include "libavutil/common.h" #include "libavutil/dict.h" +#include "libavutil/internal.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "avformat.h" @@ -69,7 +68,6 @@ typedef struct { unsigned int packet_frag_size; int64_t packet_frag_timestamp; int packet_multi_size; - int packet_obj_size; int packet_time_delta; int packet_time_start; int64_t packet_pos; @@ -368,14 +366,8 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */ - asf_st = av_mallocz(sizeof(ASFStream)); - if (!asf_st) - return AVERROR(ENOMEM); - st->priv_data = asf_st; start_time = asf->hdr.preroll; - asf_st->stream_language_index = 128; // invalid stream index means no language info - if (!(asf->hdr.flags & 0x01)) { // if we aren't streaming... int64_t fsize = avio_size(pb); if (fsize <= 0 || (int64_t)asf->hdr.file_size <= 0 || FFABS(fsize - (int64_t)asf->hdr.file_size) < 10000) @@ -407,6 +399,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) st->id = avio_rl16(pb) & 0x7f; /* stream id */ // mapping of asf ID to AV stream ID; asf->asfid2avid[st->id] = s->nb_streams - 1; + asf_st = &asf->streams[st->id]; avio_rl32(pb); @@ -472,6 +465,8 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) st->codec->extradata_size = ffio_limit(pb, sizeX - 40); st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); avio_read(pb, st->codec->extradata, st->codec->extradata_size); } @@ -684,6 +679,7 @@ static int asf_read_metadata(AVFormatContext *s, int64_t size) static int asf_read_marker(AVFormatContext *s, int64_t size) { AVIOContext *pb = s->pb; + ASFContext *asf = s->priv_data; int i, count, name_len, ret; char name[1024]; @@ -701,6 +697,7 @@ static int asf_read_marker(AVFormatContext *s, int64_t size) avio_rl64(pb); // offset, 8 bytes pres_time = avio_rl64(pb); // presentation time + pres_time -= asf->hdr.preroll * 10000; avio_rl16(pb); // entry length avio_rl32(pb); // send time avio_rl32(pb); // flags @@ -731,6 +728,10 @@ static int asf_read_header(AVFormatContext *s) avio_r8(pb); avio_r8(pb); memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid)); + + for (i = 0; i<128; i++) + asf->streams[i].stream_language_index = 128; // invalid stream index means no language info + for (;;) { uint64_t gpos = avio_tell(pb); ff_get_guid(pb, &g); @@ -753,7 +754,9 @@ static int asf_read_header(AVFormatContext *s) if (ret < 0) return ret; } else if (!ff_guidcmp(&g, &ff_asf_stream_header)) { - asf_read_stream_properties(s, gsize); + int ret = asf_read_stream_properties(s, gsize); + if (ret < 0) + return ret; } else if (!ff_guidcmp(&g, &ff_asf_comment_header)) { asf_read_content_desc(s, gsize); } else if (!ff_guidcmp(&g, &ff_asf_language_guid)) { @@ -883,7 +886,7 @@ static int asf_read_header(AVFormatContext *s) * @param pb context to read data from * @return 0 on success, <0 on error */ -static int ff_asf_get_packet(AVFormatContext *s, AVIOContext *pb) +static int asf_get_packet(AVFormatContext *s, AVIOContext *pb) { ASFContext *asf = s->priv_data; uint32_t packet_length, padsize; @@ -1009,10 +1012,10 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb) if (asf->packet_replic_size >= 8) { int64_t end = avio_tell(pb) + asf->packet_replic_size; AVRational aspect; - asf->packet_obj_size = avio_rl32(pb); - if (asf->packet_obj_size >= (1 << 24) || asf->packet_obj_size <= 0) { + asfst->packet_obj_size = avio_rl32(pb); + if (asfst->packet_obj_size >= (1 << 24) || asfst->packet_obj_size <= 0) { av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n"); - asf->packet_obj_size = 0; + asfst->packet_obj_size = 0; return AVERROR_INVALIDDATA; } asf->packet_frag_timestamp = avio_rl32(pb); // timestamp @@ -1110,7 +1113,7 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb) * @return 0 if data was stored in pkt, <0 on error or 1 if more ASF * packets need to be loaded (through asf_get_packet()) */ -static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) +static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) { ASFContext *asf = s->priv_data; ASFStream *asf_st = 0; @@ -1119,8 +1122,7 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk if (url_feof(pb)) return AVERROR_EOF; - if (asf->packet_size_left < FRAME_HEADER_SIZE || - asf->packet_segments < 1) { + if (asf->packet_size_left < FRAME_HEADER_SIZE) { int ret = asf->packet_size_left + asf->packet_padsize; assert(ret >= 0); @@ -1135,13 +1137,13 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk } if (asf->packet_time_start == 0) { if (asf_read_frame_header(s, pb) < 0) { - asf->packet_segments = 0; + asf->packet_time_start = asf->packet_segments = 0; continue; } if (asf->stream_index < 0 || s->streams[asf->stream_index]->discard >= AVDISCARD_ALL || (!asf->packet_key_frame && - s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY)) { + (s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY || asf->streams[s->streams[asf->stream_index]->id].skip_to_key))) { asf->packet_time_start = 0; /* unhandled packet (should not happen) */ avio_skip(pb, asf->packet_frag_size); @@ -1151,7 +1153,8 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk asf->packet_frag_size); continue; } - asf->asf_st = s->streams[asf->stream_index]->priv_data; + asf->asf_st = &asf->streams[s->streams[asf->stream_index]->id]; + asf->asf_st->skip_to_key = 0; } asf_st = asf->asf_st; av_assert0(asf_st); @@ -1160,41 +1163,35 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk // frag_offset is here used as the beginning timestamp asf->packet_frag_timestamp = asf->packet_time_start; asf->packet_time_start += asf->packet_time_delta; - asf->packet_obj_size = asf->packet_frag_size = avio_r8(pb); + asf_st->packet_obj_size = asf->packet_frag_size = avio_r8(pb); asf->packet_size_left--; asf->packet_multi_size--; - if (asf->packet_multi_size < asf->packet_obj_size) { + if (asf->packet_multi_size < asf_st->packet_obj_size) { asf->packet_time_start = 0; avio_skip(pb, asf->packet_multi_size); asf->packet_size_left -= asf->packet_multi_size; continue; } - asf->packet_multi_size -= asf->packet_obj_size; - } - if (asf_st->frag_offset + asf->packet_frag_size <= asf_st->pkt.size && - asf_st->frag_offset + asf->packet_frag_size > asf->packet_obj_size) { - av_log(s, AV_LOG_INFO, "ignoring invalid packet_obj_size (%d %d %d %d)\n", - asf_st->frag_offset, asf->packet_frag_size, - asf->packet_obj_size, asf_st->pkt.size); - asf->packet_obj_size = asf_st->pkt.size; + asf->packet_multi_size -= asf_st->packet_obj_size; } - if (asf_st->pkt.size != asf->packet_obj_size || + if (asf_st->pkt.size != asf_st->packet_obj_size || // FIXME is this condition sufficient? asf_st->frag_offset + asf->packet_frag_size > asf_st->pkt.size) { if (asf_st->pkt.data) { av_log(s, AV_LOG_INFO, "freeing incomplete packet size %d, new %d\n", - asf_st->pkt.size, asf->packet_obj_size); + asf_st->pkt.size, asf_st->packet_obj_size); asf_st->frag_offset = 0; av_free_packet(&asf_st->pkt); } /* new packet */ - av_new_packet(&asf_st->pkt, asf->packet_obj_size); + av_new_packet(&asf_st->pkt, asf_st->packet_obj_size); asf_st->seq = asf->packet_seq; asf_st->pkt.dts = asf->packet_frag_timestamp - asf->hdr.preroll; asf_st->pkt.stream_index = asf->stream_index; asf_st->pkt.pos = asf_st->packet_pos = asf->packet_pos; + asf_st->pkt_clean = 0; if (asf_st->pkt.data && asf_st->palette_changed) { uint8_t *pal; @@ -1211,7 +1208,7 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk asf->stream_index, asf->packet_key_frame, asf_st->pkt.flags & AV_PKT_FLAG_KEY, s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO, - asf->packet_obj_size); + asf_st->packet_obj_size); if (s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO) asf->packet_key_frame = 1; if (asf->packet_key_frame) @@ -1235,6 +1232,11 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk continue; } + if (asf->packet_frag_offset != asf_st->frag_offset && !asf_st->pkt_clean) { + memset(asf_st->pkt.data + asf_st->frag_offset, 0, asf_st->pkt.size - asf_st->frag_offset); + asf_st->pkt_clean = 1; + } + ret = avio_read(pb, asf_st->pkt.data + asf->packet_frag_offset, asf->packet_frag_size); if (ret != asf->packet_frag_size) { @@ -1310,7 +1312,9 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk asf_st->frag_offset = 0; *pkt = asf_st->pkt; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS asf_st->pkt.destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif asf_st->pkt.buf = 0; asf_st->pkt.size = 0; @@ -1331,9 +1335,9 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) int ret; /* parse cached packets, if any */ - if ((ret = ff_asf_parse_packet(s, s->pb, pkt)) <= 0) + if ((ret = asf_parse_packet(s, s->pb, pkt)) <= 0) return ret; - if ((ret = ff_asf_get_packet(s, s->pb)) < 0) + if ((ret = asf_get_packet(s, s->pb)) < 0) assert(asf->packet_size_left < FRAME_HEADER_SIZE || asf->packet_segments < 1); asf->packet_time_start = 0; @@ -1350,7 +1354,6 @@ static void asf_reset_header(AVFormatContext *s) int i; asf->packet_size_left = 0; - asf->packet_segments = 0; asf->packet_flags = 0; asf->packet_property = 0; asf->packet_timestamp = 0; @@ -1364,21 +1367,34 @@ static void asf_reset_header(AVFormatContext *s) asf->packet_frag_size = 0; asf->packet_frag_timestamp = 0; asf->packet_multi_size = 0; - asf->packet_obj_size = 0; asf->packet_time_delta = 0; asf->packet_time_start = 0; - for (i = 0; i < s->nb_streams; i++) { - asf_st = s->streams[i]->priv_data; - if (!asf_st) - continue; + for (i = 0; i < 128; i++) { + asf_st = &asf->streams[i]; av_free_packet(&asf_st->pkt); + asf_st->packet_obj_size = 0; asf_st->frag_offset = 0; asf_st->seq = 0; } asf->asf_st = NULL; } +static void skip_to_key(AVFormatContext *s) +{ + ASFContext *asf = s->priv_data; + int i; + + for (i = 0; i < 128; i++) { + int j = asf->asfid2avid[i]; + ASFStream *asf_st = &asf->streams[i]; + if (j < 0 || s->streams[j]->codec->codec_type != AVMEDIA_TYPE_VIDEO) + continue; + + asf_st->skip_to_key = 1; + } +} + static int asf_read_close(AVFormatContext *s) { asf_reset_header(s); @@ -1389,6 +1405,7 @@ static int asf_read_close(AVFormatContext *s) static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit) { + ASFContext *asf = s->priv_data; AVPacket pkt1, *pkt = &pkt1; ASFStream *asf_st; int64_t pts; @@ -1407,6 +1424,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, if (avio_seek(s->pb, pos, SEEK_SET) < 0) return AV_NOPTS_VALUE; + ff_read_frame_flush(s); asf_reset_header(s); for (;;) { if (av_read_frame(s, pkt) < 0) { @@ -1420,8 +1438,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, if (pkt->flags & AV_PKT_FLAG_KEY) { i = pkt->stream_index; - asf_st = s->streams[i]->priv_data; - av_assert0(asf_st); + asf_st = &asf->streams[s->streams[i]->id]; // assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0); pos = asf_st->packet_pos; @@ -1528,6 +1545,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, if(avio_seek(s->pb, pos, SEEK_SET) < 0) return -1; asf_reset_header(s); + skip_to_key(s); return 0; } } @@ -1535,6 +1553,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0) return -1; asf_reset_header(s); + skip_to_key(s); return 0; } diff --git a/ffmpeg/libavformat/asfenc.c b/ffmpeg/libavformat/asfenc.c index f3aec9c..8e343b3 100644 --- a/ffmpeg/libavformat/asfenc.c +++ b/ffmpeg/libavformat/asfenc.c @@ -19,7 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/dict.h" +#include "libavutil/mathematics.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" @@ -182,6 +184,8 @@ 1 - /* Payload Flags */ \ 2 * PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS) +#define DATA_HEADER_SIZE 50 + typedef struct { uint32_t seqno; int is_streamed; @@ -205,6 +209,7 @@ typedef struct { uint16_t maximum_packet; uint32_t next_packet_number; uint16_t next_packet_count; + uint64_t next_packet_offset; int next_start_sec; int end_sec; } ASFContext; @@ -220,7 +225,7 @@ static const AVCodecTag codec_asf_bmp_tags[] = { void ff_put_guid(AVIOContext *s, const ff_asf_guid *g) { - assert(sizeof(*g) == 16); + av_assert0(sizeof(*g) == 16); avio_write(s, *g, sizeof(*g)); } @@ -287,6 +292,64 @@ static int64_t unix_to_file_time(int ti) return t; } +static int32_t get_send_time(ASFContext *asf, int64_t pres_time, uint64_t *offset) +{ + int i; + int32_t send_time = 0; + *offset = asf->data_offset + DATA_HEADER_SIZE; + for (i = 0; i < asf->next_start_sec; i++) { + if (pres_time <= asf->index_ptr[i].send_time) + break; + send_time = asf->index_ptr[i].send_time; + *offset = asf->index_ptr[i].offset; + } + + return send_time / 10000; +} + +static int asf_write_markers(AVFormatContext *s) +{ + ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; + int i; + AVRational scale = {1, 10000000}; + int64_t hpos = put_header(pb, &ff_asf_marker_header); + + ff_put_guid(pb, &ff_asf_reserved_4);// ASF spec mandates this reserved value + avio_wl32(pb, s->nb_chapters); // markers count + avio_wl16(pb, 0); // ASF spec mandates 0 for this + avio_wl16(pb, 0); // name length 0, no name given + + for (i = 0; i < s->nb_chapters; i++) { + AVChapter *c = s->chapters[i]; + AVDictionaryEntry *t = av_dict_get(c->metadata, "title", NULL, 0); + int64_t pres_time = av_rescale_q(c->start, c->time_base, scale); + uint64_t offset; + int32_t send_time = get_send_time(asf, pres_time, &offset); + int len = 0; + uint8_t *buf; + AVIOContext *dyn_buf; + if (t) { + if (avio_open_dyn_buf(&dyn_buf) < 0) + return AVERROR(ENOMEM); + avio_put_str16le(dyn_buf, t->value); + len = avio_close_dyn_buf(dyn_buf, &buf); + } + avio_wl64(pb, offset); // offset of the packet with send_time + avio_wl64(pb, pres_time + PREROLL_TIME * 10000); // presentation time + avio_wl16(pb, 12 + len); // entry length + avio_wl32(pb, send_time); // send time + avio_wl32(pb, 0); // flags, should be 0 + avio_wl32(pb, len / 2); // marker desc length in WCHARS! + if (t) { + avio_write(pb, buf, len); // marker desc + av_freep(&buf); + } + } + end_header(pb, hpos); + return 0; +} + /* write the header (used two times if non streamed) */ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) @@ -388,7 +451,12 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, } end_header(pb, hpos); } - + /* chapters using ASF markers */ + if (!asf->is_streamed && s->nb_chapters) { + int ret; + if (ret = asf_write_markers(s)) + return ret; + } /* stream headers */ for (n = 0; n < s->nb_streams; n++) { int64_t es_pos; @@ -457,7 +525,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, avio_wl16(pb, 40 + enc->extradata_size); /* size */ /* BITMAPINFOHEADER header */ - ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1); + ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1, 0); } end_header(pb, hpos); } @@ -519,14 +587,14 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, cur_pos = avio_tell(pb); header_size = cur_pos - header_offset; if (asf->is_streamed) { - header_size += 8 + 30 + 50; + header_size += 8 + 30 + DATA_HEADER_SIZE; avio_seek(pb, header_offset - 10 - 30, SEEK_SET); avio_wl16(pb, header_size); avio_seek(pb, header_offset - 2 - 30, SEEK_SET); avio_wl16(pb, header_size); - header_size -= 8 + 30 + 50; + header_size -= 8 + 30 + DATA_HEADER_SIZE; } header_size += 24 + 6; avio_seek(pb, header_offset - 14, SEEK_SET); @@ -555,10 +623,10 @@ static int asf_write_header(AVFormatContext *s) asf->nb_index_memory_alloc = ASF_INDEX_BLOCK; asf->maximum_packet = 0; - /* the data-chunk-size has to be 50, which is data_size - asf->data_offset - * at the moment this function is done. It is needed to use asf as - * streamable format. */ - if (asf_write_header1(s, 0, 50) < 0) { + /* the data-chunk-size has to be 50 (DATA_HEADER_SIZE), which is + * data_size - asf->data_offset at the moment this function is done. + * It is needed to use asf as a streamable format. */ + if (asf_write_header1(s, 0, DATA_HEADER_SIZE) < 0) { //av_free(asf); return -1; } @@ -600,7 +668,7 @@ static int put_payload_parsing_info(AVFormatContext *s, padsize -= PACKET_HEADER_MIN_SIZE; if (asf->multi_payloads_present) padsize--; - assert(padsize >= 0); + av_assert0(padsize >= 0); avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS); for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++) @@ -639,7 +707,7 @@ static void flush_packet(AVFormatContext *s) ASFContext *asf = s->priv_data; int packet_hdr_size, packet_filled_size; - assert(asf->packet_timestamp_end >= asf->packet_timestamp_start); + av_assert0(asf->packet_timestamp_end >= asf->packet_timestamp_start); if (asf->is_streamed) put_chunk(s, 0x4424, s->packet_size, 0); @@ -651,7 +719,7 @@ static void flush_packet(AVFormatContext *s) asf->packet_size_left); packet_filled_size = PACKET_SIZE - asf->packet_size_left; - assert(packet_hdr_size <= asf->packet_size_left); + av_assert0(packet_hdr_size <= asf->packet_size_left); memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left); avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size); @@ -759,8 +827,9 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst, stream->seq++; } -static void update_index(AVFormatContext *s, int start_sec, - uint32_t packet_number, uint16_t packet_count) +static int update_index(AVFormatContext *s, int start_sec, + uint32_t packet_number, uint16_t packet_count, + uint64_t packet_offset) { ASFContext *asf = s->priv_data; @@ -770,32 +839,48 @@ static void update_index(AVFormatContext *s, int start_sec, if (!asf->next_start_sec) { asf->next_packet_number = packet_number; asf->next_packet_count = packet_count; + asf->next_packet_offset = packet_offset; } if (start_sec > asf->nb_index_memory_alloc) { + int err; asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1); - asf->index_ptr = av_realloc( asf->index_ptr, sizeof(ASFIndex) * asf->nb_index_memory_alloc ); + if ((err = av_reallocp_array(&asf->index_ptr, + asf->nb_index_memory_alloc, + sizeof(*asf->index_ptr))) < 0) { + asf->nb_index_memory_alloc = 0; + return err; + } } for (i = asf->next_start_sec; i < start_sec; i++) { asf->index_ptr[i].packet_number = asf->next_packet_number; asf->index_ptr[i].packet_count = asf->next_packet_count; + asf->index_ptr[i].send_time = asf->next_start_sec * INT64_C(10000000); + asf->index_ptr[i].offset = asf->next_packet_offset; + } } asf->maximum_packet = FFMAX(asf->maximum_packet, packet_count); asf->next_packet_number = packet_number; asf->next_packet_count = packet_count; + asf->next_packet_offset = packet_offset; asf->next_start_sec = start_sec; + + return 0; } static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) { ASFContext *asf = s->priv_data; + AVIOContext *pb = s->pb; ASFStream *stream; AVCodecContext *codec; uint32_t packet_number; int64_t pts; int start_sec; int flags = pkt->flags; + int ret; + uint64_t offset = avio_tell(pb); codec = s->streams[pkt->stream_index]->codec; stream = &asf->streams[pkt->stream_index]; @@ -804,7 +889,7 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) flags &= ~AV_PKT_FLAG_KEY; pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts; - assert(pts != AV_NOPTS_VALUE); + av_assert0(pts != AV_NOPTS_VALUE); pts *= 10000; asf->duration = FFMAX(asf->duration, pts + pkt->duration * 10000); @@ -818,7 +903,9 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) /* check index */ if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) { uint16_t packet_count = asf->nb_packets - packet_number; - update_index(s, start_sec, packet_number, packet_count); + ret = update_index(s, start_sec, packet_number, packet_count, offset); + if (ret < 0) + return ret; } asf->end_sec = start_sec; @@ -849,6 +936,7 @@ static int asf_write_trailer(AVFormatContext *s) { ASFContext *asf = s->priv_data; int64_t file_size, data_size; + int ret; /* flush the current packet */ if (asf->pb.buf_ptr > asf->pb.buffer) @@ -857,7 +945,8 @@ static int asf_write_trailer(AVFormatContext *s) /* write index */ data_size = avio_tell(s->pb); if (!asf->is_streamed && asf->next_start_sec) { - update_index(s, asf->end_sec + 1, 0, 0); + if ((ret = update_index(s, asf->end_sec + 1, 0, 0, 0)) < 0) + return ret; asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->next_start_sec); } avio_flush(s->pb); @@ -871,7 +960,7 @@ static int asf_write_trailer(AVFormatContext *s) asf_write_header1(s, file_size, data_size - asf->data_offset); } - av_free(asf->index_ptr); + av_freep(&asf->index_ptr); return 0; } diff --git a/ffmpeg/libavformat/assdec.c b/ffmpeg/libavformat/assdec.c index 35fcb51..c9bd63b 100644 --- a/ffmpeg/libavformat/assdec.c +++ b/ffmpeg/libavformat/assdec.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "avformat.h" #include "internal.h" #include "subtitles.h" diff --git a/ffmpeg/libavformat/assenc.c b/ffmpeg/libavformat/assenc.c index bda507d..9fb9f23 100644 --- a/ffmpeg/libavformat/assenc.c +++ b/ffmpeg/libavformat/assenc.c @@ -20,9 +20,11 @@ */ #include "avformat.h" +#include "internal.h" typedef struct ASSContext{ unsigned int extra_index; + int write_ts; // 0: ssa (timing in payload), 1: ass (matroska like) }ASSContext; static int write_header(AVFormatContext *s) @@ -31,10 +33,13 @@ static int write_header(AVFormatContext *s) AVCodecContext *avctx= s->streams[0]->codec; uint8_t *last= NULL; - if(s->nb_streams != 1 || avctx->codec_id != AV_CODEC_ID_SSA){ + if (s->nb_streams != 1 || (avctx->codec_id != AV_CODEC_ID_SSA && + avctx->codec_id != AV_CODEC_ID_ASS)) { av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n"); return -1; } + ass->write_ts = avctx->codec_id == AV_CODEC_ID_ASS; + avpriv_set_pts_info(s->streams[0], 64, 1, 100); while(ass->extra_index < avctx->extradata_size){ uint8_t *p = avctx->extradata + ass->extra_index; @@ -57,9 +62,31 @@ static int write_header(AVFormatContext *s) static int write_packet(AVFormatContext *s, AVPacket *pkt) { - avio_write(s->pb, pkt->data, pkt->size); + ASSContext *ass = s->priv_data; - avio_flush(s->pb); + if (ass->write_ts) { + long int layer; + char *p; + int64_t start = pkt->pts; + int64_t end = start + pkt->duration; + int hh1, mm1, ss1, ms1; + int hh2, mm2, ss2, ms2; + + p = pkt->data + strcspn(pkt->data, ",") + 1; // skip ReadOrder + layer = strtol(p, &p, 10); + if (*p == ',') + p++; + hh1 = (int)(start / 360000); mm1 = (int)(start / 6000) % 60; + hh2 = (int)(end / 360000); mm2 = (int)(end / 6000) % 60; + ss1 = (int)(start / 100) % 60; ms1 = (int)(start % 100); + ss2 = (int)(end / 100) % 60; ms2 = (int)(end % 100); + if (hh1 > 9) hh1 = 9, mm1 = 59, ss1 = 59, ms1 = 99; + if (hh2 > 9) hh2 = 9, mm2 = 59, ss2 = 59, ms2 = 99; + avio_printf(s->pb, "Dialogue: %ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n", + layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p); + } else { + avio_write(s->pb, pkt->data, pkt->size); + } return 0; } diff --git a/ffmpeg/libavformat/astdec.c b/ffmpeg/libavformat/astdec.c index 8862744..3fa26dc 100644 --- a/ffmpeg/libavformat/astdec.c +++ b/ffmpeg/libavformat/astdec.c @@ -27,12 +27,15 @@ static int ast_probe(AVProbeData *p) { - if (AV_RL32(p->buf) == MKTAG('S','T','R','M') && - AV_RB16(p->buf + 10) && - AV_RB16(p->buf + 12) && - AV_RB32(p->buf + 16)) - return AVPROBE_SCORE_MAX / 3 * 2; - return 0; + if (AV_RL32(p->buf) != MKTAG('S','T','R','M')) + return 0; + + if (!AV_RB16(p->buf + 10) || + !AV_RB16(p->buf + 12) || AV_RB16(p->buf + 12) > 256 || + !AV_RB32(p->buf + 16) || AV_RB32(p->buf + 16) > 8*48000) + return AVPROBE_SCORE_MAX / 8; + + return AVPROBE_SCORE_MAX / 3 * 2; } static int ast_read_header(AVFormatContext *s) diff --git a/ffmpeg/libavformat/au.c b/ffmpeg/libavformat/au.c index a29e802..edf0f32 100644 --- a/ffmpeg/libavformat/au.c +++ b/ffmpeg/libavformat/au.c @@ -2,6 +2,8 @@ * AU muxer and demuxer * Copyright (c) 2001 Fabrice Bellard * + * first version by Francois Revol <revol@free.fr> + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -20,8 +22,6 @@ */ /* - * First version by Francois Revol revol@free.fr - * * Reference documents: * http://www.opengroup.org/public/pubs/external/auformat.html * http://www.goice.co.jp/member/mo/formats/au.html @@ -31,6 +31,7 @@ #include "internal.h" #include "avio_internal.h" #include "pcm.h" +#include "libavutil/avassert.h" /* if we don't know the size in advance */ #define AU_UNKNOWN_SIZE ((uint32_t)(~0)) @@ -45,8 +46,12 @@ static const AVCodecTag codec_au_tags[] = { { AV_CODEC_ID_PCM_S32BE, 5 }, { AV_CODEC_ID_PCM_F32BE, 6 }, { AV_CODEC_ID_PCM_F64BE, 7 }, + { AV_CODEC_ID_ADPCM_G726LE, 23 }, { AV_CODEC_ID_ADPCM_G722,24 }, + { AV_CODEC_ID_ADPCM_G726LE, 25 }, + { AV_CODEC_ID_ADPCM_G726LE, 26 }, { AV_CODEC_ID_PCM_ALAW, 27 }, + { AV_CODEC_ID_ADPCM_G726LE, MKBETAG('7','2','6','2') }, { AV_CODEC_ID_NONE, 0 }, }; @@ -101,7 +106,15 @@ static int au_read_header(AVFormatContext *s) } bps = av_get_bits_per_sample(codec); - if (!bps) { + if (codec == AV_CODEC_ID_ADPCM_G726LE) { + if (id == MKBETAG('7','2','6','2')) { + bps = 2; + } else { + const uint8_t bpcss[] = {4, 0, 3, 5}; + av_assert0(id >= 23 && id < 23 + 4); + bps = bpcss[id - 23]; + } + } else if (!bps) { avpriv_request_sample(s, "Unknown bits per sample"); return AVERROR_PATCHWELCOME; } @@ -124,6 +137,7 @@ static int au_read_header(AVFormatContext *s) st->codec->codec_id = codec; st->codec->channels = channels; st->codec->sample_rate = rate; + st->codec->bits_per_coded_sample = bps; st->codec->bit_rate = channels * rate * bps; st->codec->block_align = FFMAX(bps * st->codec->channels / 8, 1); if (data_size != AU_UNKNOWN_SIZE) diff --git a/ffmpeg/libavformat/audiointerleave.c b/ffmpeg/libavformat/audiointerleave.c index 35dd8d5..2aa95f3 100644 --- a/ffmpeg/libavformat/audiointerleave.c +++ b/ffmpeg/libavformat/audiointerleave.c @@ -74,8 +74,8 @@ int ff_audio_interleave_init(AVFormatContext *s, return 0; } -static int ff_interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, - int stream_index, int flush) +static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, + int stream_index, int flush) { AVStream *st = s->streams[stream_index]; AudioInterleaveContext *aic = st->priv_data; @@ -134,7 +134,7 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { AVPacket new_pkt; int ret; - while ((ret = ff_interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) { + while ((ret = interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) { ret = ff_interleave_add_packet(s, &new_pkt, compare_ts); if (ret < 0) return ret; diff --git a/ffmpeg/libavformat/avformat.h b/ffmpeg/libavformat/avformat.h index 4b8731c..52eef0d 100644 --- a/ffmpeg/libavformat/avformat.h +++ b/ffmpeg/libavformat/avformat.h @@ -337,8 +337,10 @@ typedef struct AVProbeData { int buf_size; /**< Size of buf except extra allocated bytes */ } AVProbeData; -#define AVPROBE_SCORE_MAX 100 ///< maximum score, half of that is used for file-extension-based detection #define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4) +#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension +#define AVPROBE_SCORE_MAX 100 ///< maximum score + #define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer /// Demuxer will use avio_open, no opened file should be provided by the caller. @@ -354,8 +356,8 @@ typedef struct AVProbeData { #define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */ #define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */ #define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */ -#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fallback to binary search via read_timestamp */ -#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fallback to generic search */ +#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fall back on binary search via read_timestamp */ +#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */ #define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */ #define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */ #if LIBAVFORMAT_VERSION_MAJOR <= 54 @@ -366,6 +368,14 @@ typedef struct AVProbeData { /**< Format does not require strictly increasing timestamps, but they must still be monotonic */ +#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative + timestamps. If not set the timestamp + will be shifted in av_write_frame and + av_interleaved_write_frame so they + start from 0. + The user or muxer can override this through + AVFormatContext.avoid_negative_ts + */ #define AVFMT_SEEK_TO_PTS 0x4000000 /**< Seeking is based on PTS */ @@ -626,6 +636,13 @@ typedef struct AVIndexEntry { #define AV_DISPOSITION_ATTACHED_PIC 0x0400 /** + * To specify text track kind (different from subtitles default). + */ +#define AV_DISPOSITION_CAPTIONS 0x10000 +#define AV_DISPOSITION_DESCRIPTIONS 0x20000 +#define AV_DISPOSITION_METADATA 0x40000 + +/** * Options for behavior on timestamp wrap detection. */ #define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap @@ -723,19 +740,6 @@ typedef struct AVStream { */ AVPacket attached_pic; - /** - * Real base framerate of the stream. - * This is the lowest framerate with which all timestamps can be - * represented accurately (it is the least common multiple of all - * framerates in the stream). Note, this value is just a guess! - * For example, if the time base is 1/90000 and all frames have either - * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. - * - * Code outside avformat should access this field using: - * av_stream_get/set_r_frame_rate(stream) - */ - AVRational r_frame_rate; - /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavformat and can be changed and @@ -752,6 +756,7 @@ typedef struct AVStream { int64_t last_dts; int64_t duration_gcd; int duration_count; + int64_t rfps_duration_sum; double (*duration_error)[2][MAX_STD_TIMEBASES]; int64_t codec_info_duration; int64_t codec_info_duration_fields; @@ -771,6 +776,11 @@ typedef struct AVStream { int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ +#if FF_API_REFERENCE_DTS + /* a hack to keep ABI compatibility for ffmpeg and other applications, which accesses parser even + * though it should not */ + int64_t do_not_use; +#endif // Timestamp generation support: /** * Timestamp corresponding to the last dts sync point. @@ -779,7 +789,6 @@ typedef struct AVStream { * a DTS is received from the underlying container. Otherwise set to * AV_NOPTS_VALUE by default. */ - int64_t reference_dts; int64_t first_dts; int64_t cur_dts; int64_t last_IP_pts; @@ -796,16 +805,6 @@ typedef struct AVStream { */ int codec_info_nb_frames; - /** - * Stream Identifier - * This is the MPEG-TS stream identifier +1 - * 0 means unknown - */ - int stream_identifier; - - int64_t interleaver_chunk_size; - int64_t interleaver_chunk_duration; - /* av_read_frame() support */ enum AVStreamParseType need_parsing; struct AVCodecParserContext *parser; @@ -824,6 +823,29 @@ typedef struct AVStream { unsigned int index_entries_allocated_size; /** + * Real base framerate of the stream. + * This is the lowest framerate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * framerates in the stream). Note, this value is just a guess! + * For example, if the time base is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + * + * Code outside avformat should access this field using: + * av_stream_get/set_r_frame_rate(stream) + */ + AVRational r_frame_rate; + + /** + * Stream Identifier + * This is the MPEG-TS stream identifier +1 + * 0 means unknown + */ + int stream_identifier; + + int64_t interleaver_chunk_size; + int64_t interleaver_chunk_duration; + + /** * stream probing state * -1 -> probing finished * 0 -> no probing requested @@ -1026,6 +1048,7 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_NOBUFFER 0x0040 ///< Do not buffer frames when possible #define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. #define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted +#define AVFMT_FLAG_FLUSH_PACKETS 0x0200 ///< Flush the AVIOContext every packet. #define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) @@ -1084,6 +1107,17 @@ typedef struct AVFormatContext { */ unsigned int max_picture_buffer; + /** + * Number of chapters in AVChapter array. + * When muxing, chapters are normally written in the file header, + * so nb_chapters should normally be initialized before write_header + * is called. Some muxers (e.g. mov and mkv) can also write chapters + * in the trailer. To write chapters in the trailer, nb_chapters + * must be zero when write_header is called and non-zero when + * write_trailer is called. + * muxing : set by user + * demuxing: set by libavformat + */ unsigned int nb_chapters; AVChapter **chapters; @@ -1213,6 +1247,22 @@ typedef struct AVFormatContext { */ int seek2any; + /** + * Flush the I/O context after each packet. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int flush_packets; + + /** + * format probing score. + * The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes + * the format. + * - encoding: unused + * - decoding: set by avformat, read by user via av_format_get_probe_score() (NO direct access) + */ + int probe_score; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavformat and can be changed and @@ -1250,8 +1300,60 @@ typedef struct AVFormatContext { */ #define RAW_PACKET_BUFFER_SIZE 2500000 int raw_packet_buffer_remaining_size; + + /** + * Offset to remap timestamps to be non-negative. + * Expressed in timebase units. + * @see AVStream.mux_ts_offset + */ + int64_t offset; + + /** + * Timebase for the timestamp offset. + */ + AVRational offset_timebase; + + /** + * IO repositioned flag. + * This is set by avformat when the underlaying IO context read pointer + * is repositioned, for example when doing byte based seeking. + * Demuxers can use the flag to detect such changes. + */ + int io_repositioned; + + /** + * Forced video codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_video_codec (NO direct access). + */ + AVCodec *video_codec; + + /** + * Forced audio codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_audio_codec (NO direct access). + */ + AVCodec *audio_codec; + + /** + * Forced subtitle codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_subtitle_codec (NO direct access). + */ + AVCodec *subtitle_codec; } AVFormatContext; +int av_format_get_probe_score(const AVFormatContext *s); +AVCodec * av_format_get_video_codec(const AVFormatContext *s); +void av_format_set_video_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_audio_codec(const AVFormatContext *s); +void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); +void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); + /** * Returns the method used to set ctx->duration. * @@ -1361,6 +1463,9 @@ const AVClass *avformat_get_class(void); * * When muxing, should be called by the user before avformat_write_header(). * + * User is required to call avcodec_close() and avformat_free_context() to + * clean up the allocation by avformat_new_stream(). + * * @param c If non-NULL, the AVCodecContext corresponding to the new stream * will be initialized to use this codec. This is needed for e.g. codec-specific * defaults to be set, so codec should be provided if it is known. @@ -1376,12 +1481,6 @@ AVProgram *av_new_program(AVFormatContext *s, int id); */ -#if FF_API_PKT_DUMP -attribute_deprecated void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload); -attribute_deprecated void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, - int dump_payload); -#endif - #if FF_API_ALLOC_OUTPUT_CONTEXT /** * @deprecated deprecated in favor of avformat_alloc_output_context2() @@ -1463,16 +1562,24 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score * @param logctx the log context * @param offset the offset within the bytestream to probe from * @param max_probe_size the maximum probe buffer size (zero for default) - * @return 0 in case of success, a negative value corresponding to an + * @return the score in case of success, a negative value corresponding to an + * the maximal score is AVPROBE_SCORE_MAX * AVERROR code otherwise */ +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size); + +/** + * Like av_probe_input_buffer2() but returns 0 on success + */ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size); /** * Open an input stream and read the header. The codecs are not opened. - * The stream must be closed with av_close_input_file(). + * The stream must be closed with avformat_close_input(). * * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). * May be a pointer to NULL, in which case an AVFormatContext is allocated by this @@ -1607,8 +1714,8 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt); * information possible for decoding. * * If pkt->buf is NULL, then the packet is valid until the next - * av_read_frame() or until av_close_input_file(). Otherwise the packet is valid - * indefinitely. In both cases the packet must be freed with + * av_read_frame() or until avformat_close_input(). Otherwise the packet + * is valid indefinitely. In both cases the packet must be freed with * av_free_packet when it is no longer needed. For video, the packet contains * exactly one frame. For audio, it contains an integer number of frames if each * frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames @@ -1652,6 +1759,7 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, * or if stream_index is -1, in AV_TIME_BASE units. * If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as * keyframes (this may not be supported by all demuxers). + * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored. * * @param stream_index index of the stream which is used as time base reference * @param min_ts smallest acceptable timestamp @@ -1738,7 +1846,7 @@ void av_set_pts_info(AVStream *s, int pts_wrap_bits, * * @param s Media file handle, must be allocated with avformat_alloc_context(). * Its oformat field must be set to the desired output format; - * Its pb field must be set to an already openened AVIOContext. + * Its pb field must be set to an already opened AVIOContext. * @param options An AVDictionary filled with AVFormatContext and muxer-private options. * On return this parameter will be destroyed and replaced with a dict containing * options that were not found. May be NULL. @@ -2101,6 +2209,16 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void); AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame); /** + * Guess the frame rate, based on both the container and codec information. + * + * @param ctx the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame for which the frame rate should be determined, may be NULL + * @return the guessed (valid) frame rate, 0/1 if no idea + */ +AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame); + +/** * Check if the stream st contained in s is matched by the stream specifier * spec. * diff --git a/ffmpeg/libavformat/avidec.c b/ffmpeg/libavformat/avidec.c index f6eb71e..17eb245 100644 --- a/ffmpeg/libavformat/avidec.c +++ b/ffmpeg/libavformat/avidec.c @@ -19,36 +19,40 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/intreadwrite.h" -#include "libavutil/mathematics.h" +#include <stdint.h> + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" #include "libavutil/bswap.h" #include "libavutil/opt.h" #include "libavutil/dict.h" -#include "libavutil/avstring.h" -#include "libavutil/avassert.h" +#include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mathematics.h" #include "avformat.h" -#include "internal.h" #include "avi.h" #include "dv.h" +#include "internal.h" #include "riff.h" typedef struct AVIStream { - int64_t frame_offset; /* current frame (video) or byte (audio) counter - (used to compute the pts) */ + int64_t frame_offset; /* current frame (video) or byte (audio) counter + * (used to compute the pts) */ int remaining; int packet_size; uint32_t scale; uint32_t rate; - int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */ - - int64_t cum_len; /* temporary storage (used during seek) */ + int sample_size; /* size of one sample (or packet) + * (in the rate/scale sense) in bytes */ - int prefix; ///< normally 'd'<<8 + 'c' or 'w'<<8 + 'b' + int64_t cum_len; /* temporary storage (used during seek) */ + int prefix; /* normally 'd'<<8 + 'c' or 'w'<<8 + 'b' */ int prefix_count; uint32_t pal[256]; int has_pal; - int dshow_block_align; ///< block align variable used to emulate bugs in the MS dshow demuxer + int dshow_block_align; /* block align variable used to emulate bugs in + * the MS dshow demuxer */ AVFormatContext *sub_ctx; AVPacket sub_pkt; @@ -59,9 +63,9 @@ typedef struct AVIStream { typedef struct { const AVClass *class; - int64_t riff_end; - int64_t movi_end; - int64_t fsize; + int64_t riff_end; + int64_t movi_end; + int64_t fsize; int64_t io_fsize; int64_t movi_list; int64_t last_pkt_pos; @@ -69,7 +73,7 @@ typedef struct { int is_odml; int non_interleaved; int stream_index; - DVDemuxContext* dv_demux; + DVDemuxContext *dv_demux; int odml_depth; int use_odml; #define MAX_ODML_DEPTH 1000 @@ -92,11 +96,11 @@ static const AVClass demuxer_class = { static const char avi_headers[][8] = { - { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' }, - { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' }, - { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19}, - { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' }, - { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' }, + { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' }, + { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' }, + { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19 }, + { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' }, + { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' }, { 0 } }; @@ -108,20 +112,21 @@ static const AVMetadataConv avi_metadata_conv[] = { static int avi_load_index(AVFormatContext *s); static int guess_ni_flag(AVFormatContext *s); -#define print_tag(str, tag, size) \ - av_dlog(NULL, "%s: tag=%c%c%c%c size=0x%x\n", \ - str, tag & 0xff, \ - (tag >> 8) & 0xff, \ - (tag >> 16) & 0xff, \ - (tag >> 24) & 0xff, \ - size) +#define print_tag(str, tag, size) \ + av_dlog(NULL, "pos:%"PRIX64" %s: tag=%c%c%c%c size=0x%x\n", \ + avio_tell(pb), str, tag & 0xff, \ + (tag >> 8) & 0xff, \ + (tag >> 16) & 0xff, \ + (tag >> 24) & 0xff, \ + size) -static inline int get_duration(AVIStream *ast, int len){ - if(ast->sample_size){ +static inline int get_duration(AVIStream *ast, int len) +{ + if (ast->sample_size) return len; - }else if (ast->dshow_block_align){ - return (len + ast->dshow_block_align - 1)/ast->dshow_block_align; - }else + else if (ast->dshow_block_align) + return (len + ast->dshow_block_align - 1) / ast->dshow_block_align; + else return 1; } @@ -133,164 +138,180 @@ static int get_riff(AVFormatContext *s, AVIOContext *pb) /* check RIFF header */ avio_read(pb, header, 4); - avi->riff_end = avio_rl32(pb); /* RIFF chunk size */ + avi->riff_end = avio_rl32(pb); /* RIFF chunk size */ avi->riff_end += avio_tell(pb); /* RIFF chunk end */ - avio_read(pb, header+4, 4); + avio_read(pb, header + 4, 4); - for(i=0; avi_headers[i][0]; i++) - if(!memcmp(header, avi_headers[i], 8)) + for (i = 0; avi_headers[i][0]; i++) + if (!memcmp(header, avi_headers[i], 8)) break; - if(!avi_headers[i][0]) + if (!avi_headers[i][0]) return AVERROR_INVALIDDATA; - if(header[7] == 0x19) - av_log(s, AV_LOG_INFO, "This file has been generated by a totally broken muxer.\n"); + if (header[7] == 0x19) + av_log(s, AV_LOG_INFO, + "This file has been generated by a totally broken muxer.\n"); return 0; } -static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ - AVIContext *avi = s->priv_data; - AVIOContext *pb = s->pb; - int longs_pre_entry= avio_rl16(pb); - int index_sub_type = avio_r8(pb); - int index_type = avio_r8(pb); - int entries_in_use = avio_rl32(pb); - int chunk_id = avio_rl32(pb); - int64_t base = avio_rl64(pb); - int stream_id= 10*((chunk_id&0xFF) - '0') + (((chunk_id>>8)&0xFF) - '0'); +static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) +{ + AVIContext *avi = s->priv_data; + AVIOContext *pb = s->pb; + int longs_pre_entry = avio_rl16(pb); + int index_sub_type = avio_r8(pb); + int index_type = avio_r8(pb); + int entries_in_use = avio_rl32(pb); + int chunk_id = avio_rl32(pb); + int64_t base = avio_rl64(pb); + int stream_id = ((chunk_id & 0xFF) - '0') * 10 + + ((chunk_id >> 8 & 0xFF) - '0'); AVStream *st; AVIStream *ast; int i; - int64_t last_pos= -1; - int64_t filesize= avi->fsize; - - av_dlog(s, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16"PRIX64"\n", - longs_pre_entry,index_type, entries_in_use, chunk_id, base); - - if(stream_id >= s->nb_streams || stream_id < 0) + int64_t last_pos = -1; + int64_t filesize = avi->fsize; + + av_dlog(s, + "longs_pre_entry:%d index_type:%d entries_in_use:%d " + "chunk_id:%X base:%16"PRIX64"\n", + longs_pre_entry, + index_type, + entries_in_use, + chunk_id, + base); + + if (stream_id >= s->nb_streams || stream_id < 0) return AVERROR_INVALIDDATA; - st= s->streams[stream_id]; + st = s->streams[stream_id]; ast = st->priv_data; - if(index_sub_type) + if (index_sub_type) return AVERROR_INVALIDDATA; avio_rl32(pb); - if(index_type && longs_pre_entry != 2) + if (index_type && longs_pre_entry != 2) return AVERROR_INVALIDDATA; - if(index_type>1) + if (index_type > 1) return AVERROR_INVALIDDATA; - if(filesize > 0 && base >= filesize){ + if (filesize > 0 && base >= filesize) { av_log(s, AV_LOG_ERROR, "ODML index invalid\n"); - if(base>>32 == (base & 0xFFFFFFFF) && (base & 0xFFFFFFFF) < filesize && filesize <= 0xFFFFFFFF) + if (base >> 32 == (base & 0xFFFFFFFF) && + (base & 0xFFFFFFFF) < filesize && + filesize <= 0xFFFFFFFF) base &= 0xFFFFFFFF; else return AVERROR_INVALIDDATA; } - for(i=0; i<entries_in_use; i++){ - if(index_type){ - int64_t pos= avio_rl32(pb) + base - 8; - int len = avio_rl32(pb); - int key= len >= 0; + for (i = 0; i < entries_in_use; i++) { + if (index_type) { + int64_t pos = avio_rl32(pb) + base - 8; + int len = avio_rl32(pb); + int key = len >= 0; len &= 0x7FFFFFFF; #ifdef DEBUG_SEEK av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len); #endif - if(url_feof(pb)) + if (url_feof(pb)) return AVERROR_INVALIDDATA; - if(last_pos == pos || pos == base - 8) - avi->non_interleaved= 1; - if(last_pos != pos && (len || !ast->sample_size)) - av_add_index_entry(st, pos, ast->cum_len, len, 0, key ? AVINDEX_KEYFRAME : 0); + if (last_pos == pos || pos == base - 8) + avi->non_interleaved = 1; + if (last_pos != pos && (len || !ast->sample_size)) + av_add_index_entry(st, pos, ast->cum_len, len, 0, + key ? AVINDEX_KEYFRAME : 0); ast->cum_len += get_duration(ast, len); - last_pos= pos; - }else{ + last_pos = pos; + } else { int64_t offset, pos; int duration; offset = avio_rl64(pb); avio_rl32(pb); /* size */ duration = avio_rl32(pb); - if(url_feof(pb)) + if (url_feof(pb)) return AVERROR_INVALIDDATA; pos = avio_tell(pb); - if(avi->odml_depth > MAX_ODML_DEPTH){ + if (avi->odml_depth > MAX_ODML_DEPTH) { av_log(s, AV_LOG_ERROR, "Too deeply nested ODML indexes\n"); return AVERROR_INVALIDDATA; } - if(avio_seek(pb, offset+8, SEEK_SET) < 0) + if (avio_seek(pb, offset + 8, SEEK_SET) < 0) return -1; avi->odml_depth++; read_braindead_odml_indx(s, frame_num); avi->odml_depth--; frame_num += duration; - if(avio_seek(pb, pos, SEEK_SET) < 0) { + if (avio_seek(pb, pos, SEEK_SET) < 0) { av_log(s, AV_LOG_ERROR, "Failed to restore position after reading index\n"); return -1; } } } - avi->index_loaded=2; + avi->index_loaded = 2; return 0; } -static void clean_index(AVFormatContext *s){ +static void clean_index(AVFormatContext *s) +{ int i; int64_t j; - for(i=0; i<s->nb_streams; i++){ - AVStream *st = s->streams[i]; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; AVIStream *ast = st->priv_data; - int n= st->nb_index_entries; - int max= ast->sample_size; + int n = st->nb_index_entries; + int max = ast->sample_size; int64_t pos, size, ts; - if(n != 1 || ast->sample_size==0) + if (n != 1 || ast->sample_size == 0) continue; - while(max < 1024) max+=max; + while (max < 1024) + max += max; - pos= st->index_entries[0].pos; - size= st->index_entries[0].size; - ts= st->index_entries[0].timestamp; + pos = st->index_entries[0].pos; + size = st->index_entries[0].size; + ts = st->index_entries[0].timestamp; - for(j=0; j<size; j+=max){ - av_add_index_entry(st, pos+j, ts+j, FFMIN(max, size-j), 0, AVINDEX_KEYFRAME); - } + for (j = 0; j < size; j += max) + av_add_index_entry(st, pos + j, ts + j, FFMIN(max, size - j), 0, + AVINDEX_KEYFRAME); } } -static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag, uint32_t size) +static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag, + uint32_t size) { AVIOContext *pb = s->pb; - char key[5] = {0}, *value; + char key[5] = { 0 }; + char *value; size += (size & 1); if (size == UINT_MAX) return AVERROR(EINVAL); - value = av_malloc(size+1); + value = av_malloc(size + 1); if (!value) return AVERROR(ENOMEM); avio_read(pb, value, size); - value[size]=0; + value[size] = 0; AV_WL32(key, tag); return av_dict_set(st ? &st->metadata : &s->metadata, key, value, - AV_DICT_DONT_STRDUP_VAL); + AV_DICT_DONT_STRDUP_VAL); } static const char months[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -303,10 +324,10 @@ static void avi_metadata_creation_time(AVDictionary **metadata, char *date) /* parse standard AVI date format (ie. "Mon Mar 10 15:04:43 2003") */ if (sscanf(date, "%*3s%*[ ]%3s%*[ ]%2d%*[ ]%8s%*[ ]%4d", month, &day, time, &year) == 4) { - for (i=0; i<12; i++) + for (i = 0; i < 12; i++) if (!av_strcasecmp(month, months[i])) { snprintf(buffer, sizeof(buffer), "%.4d-%.2d-%.2d %s", - year, i+1, day, time); + year, i + 1, day, time); av_dict_set(metadata, "creation_time", buffer, 0); } } else if (date[4] == '/' && date[7] == '/') { @@ -321,19 +342,25 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end) uint32_t tag = avio_rl32(s->pb); uint32_t size = avio_rl32(s->pb); switch (tag) { - case MKTAG('n', 'c', 't', 'g'): { /* Nikon Tags */ + case MKTAG('n', 'c', 't', 'g'): /* Nikon Tags */ + { uint64_t tag_end = avio_tell(s->pb) + size; while (avio_tell(s->pb) < tag_end) { - uint16_t tag = avio_rl16(s->pb); - uint16_t size = avio_rl16(s->pb); + uint16_t tag = avio_rl16(s->pb); + uint16_t size = avio_rl16(s->pb); const char *name = NULL; - char buffer[64] = {0}; + char buffer[64] = { 0 }; size -= avio_read(s->pb, buffer, - FFMIN(size, sizeof(buffer)-1)); + FFMIN(size, sizeof(buffer) - 1)); switch (tag) { - case 0x03: name = "maker"; break; - case 0x04: name = "model"; break; - case 0x13: name = "creation_time"; + case 0x03: + name = "maker"; + break; + case 0x04: + name = "model"; + break; + case 0x13: + name = "creation_time"; if (buffer[4] == ':' && buffer[7] == ':') buffer[4] = buffer[7] = '-'; break; @@ -360,13 +387,14 @@ static int avi_read_header(AVFormatContext *s) unsigned int size; int i; AVStream *st; - AVIStream *ast = NULL; - int avih_width=0, avih_height=0; - int amv_file_format=0; - uint64_t list_end = 0; + AVIStream *ast = NULL; + int avih_width = 0, avih_height = 0; + int amv_file_format = 0; + uint64_t list_end = 0; int ret; + AVDictionaryEntry *dict_entry; - avi->stream_index= -1; + avi->stream_index = -1; ret = get_riff(s, pb); if (ret < 0) @@ -375,22 +403,22 @@ static int avi_read_header(AVFormatContext *s) av_log(avi, AV_LOG_DEBUG, "use odml:%d\n", avi->use_odml); avi->io_fsize = avi->fsize = avio_size(pb); - if(avi->fsize<=0 || avi->fsize < avi->riff_end) - avi->fsize= avi->riff_end == 8 ? INT64_MAX : avi->riff_end; + if (avi->fsize <= 0 || avi->fsize < avi->riff_end) + avi->fsize = avi->riff_end == 8 ? INT64_MAX : avi->riff_end; /* first list tag */ stream_index = -1; - codec_type = -1; + codec_type = -1; frame_period = 0; - for(;;) { + for (;;) { if (url_feof(pb)) goto fail; - tag = avio_rl32(pb); + tag = avio_rl32(pb); size = avio_rl32(pb); print_tag("tag", tag, size); - switch(tag) { + switch (tag) { case MKTAG('L', 'I', 'S', 'T'): list_end = avio_tell(pb) + size; /* Ignored, except at start of video packets. */ @@ -400,21 +428,23 @@ static int avi_read_header(AVFormatContext *s) if (tag1 == MKTAG('m', 'o', 'v', 'i')) { avi->movi_list = avio_tell(pb) - 4; - if(size) avi->movi_end = avi->movi_list + size + (size & 1); - else avi->movi_end = avi->fsize; + if (size) + avi->movi_end = avi->movi_list + size + (size & 1); + else + avi->movi_end = avi->fsize; av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end); goto end_of_header; - } - else if (tag1 == MKTAG('I', 'N', 'F', 'O')) + } else if (tag1 == MKTAG('I', 'N', 'F', 'O')) ff_read_riff_info(s, size - 4); else if (tag1 == MKTAG('n', 'c', 'd', 't')) avi_read_nikon(s, list_end); break; - case MKTAG('I', 'D', 'I', 'T'): { - unsigned char date[64] = {0}; + case MKTAG('I', 'D', 'I', 'T'): + { + unsigned char date[64] = { 0 }; size += (size & 1); - size -= avio_read(pb, date, FFMIN(size, sizeof(date)-1)); + size -= avio_read(pb, date, FFMIN(size, sizeof(date) - 1)); avio_skip(pb, size); avi_metadata_creation_time(&s->metadata, date); break; @@ -424,7 +454,7 @@ static int avi_read_header(AVFormatContext *s) avio_skip(pb, size + (size & 1)); break; case MKTAG('a', 'm', 'v', 'h'): - amv_file_format=1; + amv_file_format = 1; case MKTAG('a', 'v', 'i', 'h'): /* AVI header */ /* using frame_period is bad idea */ @@ -436,51 +466,51 @@ static int avi_read_header(AVFormatContext *s) avio_skip(pb, 2 * 4); avio_rl32(pb); avio_rl32(pb); - avih_width=avio_rl32(pb); - avih_height=avio_rl32(pb); + avih_width = avio_rl32(pb); + avih_height = avio_rl32(pb); avio_skip(pb, size - 10 * 4); break; case MKTAG('s', 't', 'r', 'h'): /* stream header */ - tag1 = avio_rl32(pb); + tag1 = avio_rl32(pb); handler = avio_rl32(pb); /* codec tag */ - if(tag1 == MKTAG('p', 'a', 'd', 's')){ + if (tag1 == MKTAG('p', 'a', 'd', 's')) { avio_skip(pb, size - 8); break; - }else{ + } else { stream_index++; st = avformat_new_stream(s, NULL); if (!st) goto fail; st->id = stream_index; - ast = av_mallocz(sizeof(AVIStream)); + ast = av_mallocz(sizeof(AVIStream)); if (!ast) goto fail; st->priv_data = ast; } - if(amv_file_format) - tag1 = stream_index ? MKTAG('a','u','d','s') : MKTAG('v','i','d','s'); + if (amv_file_format) + tag1 = stream_index ? MKTAG('a', 'u', 'd', 's') + : MKTAG('v', 'i', 'd', 's'); print_tag("strh", tag1, -1); - if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){ + if (tag1 == MKTAG('i', 'a', 'v', 's') || + tag1 == MKTAG('i', 'v', 'a', 's')) { int64_t dv_dur; - /* - * After some consideration -- I don't think we - * have to support anything but DV in type1 AVIs. - */ + /* After some consideration -- I don't think we + * have to support anything but DV in type1 AVIs. */ if (s->nb_streams != 1) goto fail; if (handler != MKTAG('d', 'v', 's', 'd') && handler != MKTAG('d', 'v', 'h', 'd') && handler != MKTAG('d', 'v', 's', 'l')) - goto fail; + goto fail; ast = s->streams[0]->priv_data; av_freep(&s->streams[0]->codec->extradata); @@ -494,50 +524,53 @@ static int avi_read_header(AVFormatContext *s) avi->dv_demux = avpriv_dv_init_demux(s); if (!avi->dv_demux) goto fail; - } + } else + goto fail; s->streams[0]->priv_data = ast; avio_skip(pb, 3 * 4); ast->scale = avio_rl32(pb); - ast->rate = avio_rl32(pb); + ast->rate = avio_rl32(pb); avio_skip(pb, 4); /* start time */ dv_dur = avio_rl32(pb); if (ast->scale > 0 && ast->rate > 0 && dv_dur > 0) { - dv_dur *= AV_TIME_BASE; + dv_dur *= AV_TIME_BASE; s->duration = av_rescale(dv_dur, ast->scale, ast->rate); } - /* - * else, leave duration alone; timing estimation in utils.c - * will make a guess based on bitrate. - */ + /* else, leave duration alone; timing estimation in utils.c + * will make a guess based on bitrate. */ stream_index = s->nb_streams - 1; - avio_skip(pb, size - 9*4); + avio_skip(pb, size - 9 * 4); break; } av_assert0(stream_index < s->nb_streams); - st->codec->stream_codec_tag= handler; + st->codec->stream_codec_tag = handler; avio_rl32(pb); /* flags */ avio_rl16(pb); /* priority */ avio_rl16(pb); /* language */ avio_rl32(pb); /* initial frame */ ast->scale = avio_rl32(pb); - ast->rate = avio_rl32(pb); - if(!(ast->scale && ast->rate)){ - av_log(s, AV_LOG_WARNING, "scale/rate is %u/%u which is invalid. (This file has been generated by broken software.)\n", ast->scale, ast->rate); - if(frame_period){ - ast->rate = 1000000; + ast->rate = avio_rl32(pb); + if (!(ast->scale && ast->rate)) { + av_log(s, AV_LOG_WARNING, + "scale/rate is %u/%u which is invalid. " + "(This file has been generated by broken software.)\n", + ast->scale, + ast->rate); + if (frame_period) { + ast->rate = 1000000; ast->scale = frame_period; - }else{ - ast->rate = 25; + } else { + ast->rate = 25; ast->scale = 1; } } avpriv_set_pts_info(st, 64, ast->scale, ast->rate); - ast->cum_len=avio_rl32(pb); /* start */ + ast->cum_len = avio_rl32(pb); /* start */ st->nb_frames = avio_rl32(pb); st->start_time = 0; @@ -548,11 +581,11 @@ static int avi_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } ast->sample_size = avio_rl32(pb); /* sample ssize */ - ast->cum_len *= FFMAX(1, ast->sample_size); + ast->cum_len *= FFMAX(1, ast->sample_size); av_dlog(s, "%"PRIu32" %"PRIu32" %d\n", ast->rate, ast->scale, ast->sample_size); - switch(tag1) { + switch (tag1) { case MKTAG('v', 'i', 'd', 's'): codec_type = AVMEDIA_TYPE_VIDEO; @@ -570,14 +603,14 @@ static int avi_read_header(AVFormatContext *s) default: av_log(s, AV_LOG_INFO, "unknown stream type %X\n", tag1); } - if(ast->sample_size == 0) { + if (ast->sample_size == 0) { st->duration = st->nb_frames; if (st->duration > 0 && avi->io_fsize > 0 && avi->riff_end > avi->io_fsize) { av_log(s, AV_LOG_DEBUG, "File is truncated adjusting duration\n"); st->duration = av_rescale(st->duration, avi->io_fsize, avi->riff_end); } } - ast->frame_offset= ast->cum_len; + ast->frame_offset = ast->cum_len; avio_skip(pb, size - 12 * 4); break; case MKTAG('s', 't', 'r', 'f'): @@ -592,49 +625,56 @@ static int avi_read_header(AVFormatContext *s) if (cur_pos < list_end) size = FFMIN(size, list_end - cur_pos); st = s->streams[stream_index]; - switch(codec_type) { + if (st->codec->codec_type != AVMEDIA_TYPE_UNKNOWN) { + avio_skip(pb, size); + break; + } + switch (codec_type) { case AVMEDIA_TYPE_VIDEO: - if(amv_file_format){ - st->codec->width=avih_width; - st->codec->height=avih_height; + if (amv_file_format) { + st->codec->width = avih_width; + st->codec->height = avih_height; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = AV_CODEC_ID_AMV; + st->codec->codec_id = AV_CODEC_ID_AMV; avio_skip(pb, size); break; } tag1 = ff_get_bmp_header(pb, st, &esize); - if (tag1 == MKTAG('D', 'X', 'S', 'B') || tag1 == MKTAG('D','X','S','A')) { + if (tag1 == MKTAG('D', 'X', 'S', 'B') || + tag1 == MKTAG('D', 'X', 'S', 'A')) { st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - st->codec->codec_tag = tag1; - st->codec->codec_id = AV_CODEC_ID_XSUB; + st->codec->codec_tag = tag1; + st->codec->codec_id = AV_CODEC_ID_XSUB; break; } - if(size > 10*4 && size<(1<<30) && size < avi->fsize){ - if(esize == size-1 && (esize&1)) st->codec->extradata_size= esize - 10*4; - else st->codec->extradata_size= size - 10*4; - st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { - st->codec->extradata_size= 0; + if (size > 10 * 4 && size < (1 << 30) && size < avi->fsize) { + if (esize == size-1 && (esize&1)) { + st->codec->extradata_size = esize - 10 * 4; + } else + st->codec->extradata_size = size - 10 * 4; + if (ff_get_extradata(st->codec, pb, st->codec->extradata_size) < 0) return AVERROR(ENOMEM); - } - avio_read(pb, st->codec->extradata, st->codec->extradata_size); } - if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly + // FIXME: check if the encoder really did this correctly + if (st->codec->extradata_size & 1) avio_r8(pb); - /* Extract palette from extradata if bpp <= 8. */ - /* This code assumes that extradata contains only palette. */ - /* This is true for all paletted codecs implemented in FFmpeg. */ - if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) { + /* Extract palette from extradata if bpp <= 8. + * This code assumes that extradata contains only palette. + * This is true for all paletted codecs implemented in + * FFmpeg. */ + if (st->codec->extradata_size && + (st->codec->bits_per_coded_sample <= 8)) { int pal_size = (1 << st->codec->bits_per_coded_sample) << 2; const uint8_t *pal_src; pal_size = FFMIN(pal_size, st->codec->extradata_size); - pal_src = st->codec->extradata + st->codec->extradata_size - pal_size; - for (i = 0; i < pal_size/4; i++) + pal_src = st->codec->extradata + + st->codec->extradata_size - pal_size; + for (i = 0; i < pal_size / 4; i++) ast->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i); ast->has_pal = 1; } @@ -642,17 +682,26 @@ static int avi_read_header(AVFormatContext *s) print_tag("video", tag1, 0); st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_tag = tag1; - st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag1); - st->need_parsing = AVSTREAM_PARSE_HEADERS; // This is needed to get the pict type which is necessary for generating correct pts. - - if(st->codec->codec_tag==0 && st->codec->height > 0 && st->codec->extradata_size < 1U<<30){ - st->codec->extradata_size+= 9; - st->codec->extradata= av_realloc_f(st->codec->extradata, 1, st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if(st->codec->extradata) - memcpy(st->codec->extradata + st->codec->extradata_size - 9, "BottomUp", 9); + st->codec->codec_tag = tag1; + st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, + tag1); + /* This is needed to get the pict type which is necessary + * for generating correct pts. */ + st->need_parsing = AVSTREAM_PARSE_HEADERS; + + if (st->codec->codec_tag == 0 && st->codec->height > 0 && + st->codec->extradata_size < 1U << 30) { + st->codec->extradata_size += 9; + if ((ret = av_reallocp(&st->codec->extradata, + st->codec->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { + st->codec->extradata_size = 0; + return ret; + } else + memcpy(st->codec->extradata + st->codec->extradata_size - 9, + "BottomUp", 9); } - st->codec->height= FFABS(st->codec->height); + st->codec->height = FFABS(st->codec->height); // avio_skip(pb, size - 5 * 4); break; @@ -660,12 +709,19 @@ static int avi_read_header(AVFormatContext *s) ret = ff_get_wav_header(pb, st->codec, size); if (ret < 0) return ret; - ast->dshow_block_align= st->codec->block_align; - if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){ - av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align); - ast->sample_size= st->codec->block_align; + ast->dshow_block_align = st->codec->block_align; + if (ast->sample_size && st->codec->block_align && + ast->sample_size != st->codec->block_align) { + av_log(s, + AV_LOG_WARNING, + "sample size (%d) != block align (%d)\n", + ast->sample_size, + st->codec->block_align); + ast->sample_size = st->codec->block_align; } - if (size&1) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ + /* 2-aligned + * (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ + if (size & 1) avio_skip(pb, 1); /* Force parsing as several audio frames can be in * one packet and timestamps refer to packet start. */ @@ -673,24 +729,25 @@ static int avi_read_header(AVFormatContext *s) /* ADTS header is in extradata, AAC without header must be * stored as exact frames. Parser not needed and it will * fail. */ - if (st->codec->codec_id == AV_CODEC_ID_AAC && st->codec->extradata_size) + if (st->codec->codec_id == AV_CODEC_ID_AAC && + st->codec->extradata_size) st->need_parsing = AVSTREAM_PARSE_NONE; /* AVI files with Xan DPCM audio (wrongly) declare PCM * audio in the header but have Axan as stream_code_tag. */ - if (st->codec->stream_codec_tag == AV_RL32("Axan")){ + if (st->codec->stream_codec_tag == AV_RL32("Axan")) { st->codec->codec_id = AV_CODEC_ID_XAN_DPCM; st->codec->codec_tag = 0; ast->dshow_block_align = 0; } - if (amv_file_format){ - st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV; + if (amv_file_format) { + st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV; ast->dshow_block_align = 0; } - if(st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align <= 4 && ast->dshow_block_align) { + if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align <= 4 && ast->dshow_block_align) { av_log(s, AV_LOG_DEBUG, "overriding invalid dshow_block_align of %d\n", ast->dshow_block_align); ast->dshow_block_align = 0; } - if(st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 1024 && ast->sample_size == 1024 || + if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 1024 && ast->sample_size == 1024 || st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 4096 && ast->sample_size == 4096 || st->codec->codec_id == AV_CODEC_ID_MP3 && ast->dshow_block_align == 1152 && ast->sample_size == 1152) { av_log(s, AV_LOG_DEBUG, "overriding sample_size\n"); @@ -704,15 +761,17 @@ static int avi_read_header(AVFormatContext *s) break; default: st->codec->codec_type = AVMEDIA_TYPE_DATA; - st->codec->codec_id= AV_CODEC_ID_NONE; - st->codec->codec_tag= 0; + st->codec->codec_id = AV_CODEC_ID_NONE; + st->codec->codec_tag = 0; avio_skip(pb, size); break; } } break; case MKTAG('s', 't', 'r', 'd'): - if (stream_index >= (unsigned)s->nb_streams || s->streams[stream_index]->codec->extradata_size) { + if (stream_index >= (unsigned)s->nb_streams + || s->streams[stream_index]->codec->extradata_size + || s->streams[stream_index]->codec->codec_tag == MKTAG('H','2','6','4')) { avio_skip(pb, size); } else { uint64_t cur_pos = avio_tell(pb); @@ -720,29 +779,26 @@ static int avi_read_header(AVFormatContext *s) size = FFMIN(size, list_end - cur_pos); st = s->streams[stream_index]; - if(size<(1<<30)){ - st->codec->extradata_size= size; - st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { - st->codec->extradata_size= 0; + if (size<(1<<30)) { + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - } - avio_read(pb, st->codec->extradata, st->codec->extradata_size); } - if(st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly + if (st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly avio_r8(pb); } break; case MKTAG('i', 'n', 'd', 'x'): - i= avio_tell(pb); - if(pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && avi->use_odml && - read_braindead_odml_indx(s, 0) < 0 && (s->error_recognition & AV_EF_EXPLODE)) + i = avio_tell(pb); + if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && + avi->use_odml && + read_braindead_odml_indx(s, 0) < 0 && + (s->error_recognition & AV_EF_EXPLODE)) goto fail; - avio_seek(pb, i+size, SEEK_SET); + avio_seek(pb, i + size, SEEK_SET); break; case MKTAG('v', 'p', 'r', 'p'): - if(stream_index < (unsigned)s->nb_streams && size > 9*4){ + if (stream_index < (unsigned)s->nb_streams && size > 9 * 4) { AVRational active, active_aspect; st = s->streams[stream_index]; @@ -752,33 +808,35 @@ static int avi_read_header(AVFormatContext *s) avio_rl32(pb); avio_rl32(pb); - active_aspect.den= avio_rl16(pb); - active_aspect.num= avio_rl16(pb); - active.num = avio_rl32(pb); - active.den = avio_rl32(pb); - avio_rl32(pb); //nbFieldsPerFrame + active_aspect.den = avio_rl16(pb); + active_aspect.num = avio_rl16(pb); + active.num = avio_rl32(pb); + active.den = avio_rl32(pb); + avio_rl32(pb); // nbFieldsPerFrame - if(active_aspect.num && active_aspect.den && active.num && active.den){ - st->sample_aspect_ratio= av_div_q(active_aspect, active); + if (active_aspect.num && active_aspect.den && + active.num && active.den) { + st->sample_aspect_ratio = av_div_q(active_aspect, active); av_dlog(s, "vprp %d/%d %d/%d\n", active_aspect.num, active_aspect.den, active.num, active.den); } - size -= 9*4; + size -= 9 * 4; } avio_skip(pb, size); break; case MKTAG('s', 't', 'r', 'n'): - if(s->nb_streams){ - ret = avi_read_tag(s, s->streams[s->nb_streams-1], tag, size); + if (s->nb_streams) { + ret = avi_read_tag(s, s->streams[s->nb_streams - 1], tag, size); if (ret < 0) return ret; break; } default: - if(size > 1000000){ - av_log(s, AV_LOG_ERROR, "Something went wrong during header parsing, " - "I will ignore it and try to continue anyway.\n"); + if (size > 1000000) { + av_log(s, AV_LOG_ERROR, + "Something went wrong during header parsing, " + "I will ignore it and try to continue anyway.\n"); if (s->error_recognition & AV_EF_EXPLODE) goto fail; avi->movi_list = avio_tell(pb) - 4; @@ -791,32 +849,45 @@ static int avi_read_header(AVFormatContext *s) break; } } - end_of_header: + +end_of_header: /* check stream number */ if (stream_index != s->nb_streams - 1) { - fail: + +fail: return AVERROR_INVALIDDATA; } - if(!avi->index_loaded && pb->seekable) + if (!avi->index_loaded && pb->seekable) avi_load_index(s); - avi->index_loaded |= 1; + avi->index_loaded |= 1; avi->non_interleaved |= guess_ni_flag(s) | (s->flags & AVFMT_FLAG_SORT_DTS); - for(i=0; i<s->nb_streams; i++){ + + dict_entry = av_dict_get(s->metadata, "ISFT", NULL, 0); + if (dict_entry && !strcmp(dict_entry->value, "PotEncoder")) + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if ( st->codec->codec_id == AV_CODEC_ID_MPEG1VIDEO + || st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) + st->need_parsing = AVSTREAM_PARSE_FULL; + } + + for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - if(st->nb_index_entries) + if (st->nb_index_entries) break; } // DV-in-AVI cannot be non-interleaved, if set this must be // a mis-detection. - if(avi->dv_demux) - avi->non_interleaved=0; - if(i==s->nb_streams && avi->non_interleaved) { - av_log(s, AV_LOG_WARNING, "non-interleaved AVI without index, switching to interleaved\n"); - avi->non_interleaved=0; + if (avi->dv_demux) + avi->non_interleaved = 0; + if (i == s->nb_streams && avi->non_interleaved) { + av_log(s, AV_LOG_WARNING, + "Non-interleaved AVI without index, switching to interleaved\n"); + avi->non_interleaved = 0; } - if(avi->non_interleaved) { + if (avi->non_interleaved) { av_log(s, AV_LOG_INFO, "non-interleaved AVI\n"); clean_index(s); } @@ -827,16 +898,18 @@ static int avi_read_header(AVFormatContext *s) return 0; } -static int read_gab2_sub(AVStream *st, AVPacket *pkt) { - if (pkt->data && !strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data+5) == 2) { +static int read_gab2_sub(AVStream *st, AVPacket *pkt) +{ + if (pkt->size >= 7 && + !strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data + 5) == 2) { uint8_t desc[256]; - int score = AVPROBE_SCORE_MAX / 2, ret; + int score = AVPROBE_SCORE_EXTENSION, ret; AVIStream *ast = st->priv_data; AVInputFormat *sub_demuxer; AVRational time_base; - AVIOContext *pb = avio_alloc_context( pkt->data + 7, - pkt->size - 7, - 0, NULL, NULL, NULL, NULL); + AVIOContext *pb = avio_alloc_context(pkt->data + 7, + pkt->size - 7, + 0, NULL, NULL, NULL, NULL); AVProbeData pd; unsigned int desc_len = avio_rl32(pb); @@ -851,14 +924,15 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt) { avio_rl16(pb); /* flags? */ avio_rl32(pb); /* data size */ - pd = (AVProbeData) { .buf = pb->buf_ptr, .buf_size = pb->buf_end - pb->buf_ptr }; + pd = (AVProbeData) { .buf = pb->buf_ptr, + .buf_size = pb->buf_end - pb->buf_ptr }; if (!(sub_demuxer = av_probe_input_format2(&pd, 1, &score))) goto error; if (!(ast->sub_ctx = avformat_alloc_context())) goto error; - ast->sub_ctx->pb = pb; + ast->sub_ctx->pb = pb; if (!avformat_open_input(&ast->sub_ctx, "", sub_demuxer, NULL)) { ff_read_packet(ast->sub_ctx, &ast->sub_pkt); *st->codec = *ast->sub_ctx->streams[0]->codec; @@ -869,6 +943,7 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt) { ast->sub_buffer = pkt->data; memset(pkt, 0, sizeof(*pkt)); return 1; + error: av_freep(&pb); } @@ -886,7 +961,7 @@ static AVStream *get_subtitle_pkt(AVFormatContext *s, AVStream *next_st, next_ts = av_rescale_q(next_ast->frame_offset, next_st->time_base, AV_TIME_BASE_Q); - for (i=0; i<s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; ast = st->priv_data; if (st->discard < AVDISCARD_ALL && ast && ast->sub_pkt.data) { @@ -899,21 +974,23 @@ static AVStream *get_subtitle_pkt(AVFormatContext *s, AVStream *next_st, } if (sub_st) { - ast = sub_st->priv_data; - *pkt = ast->sub_pkt; + ast = sub_st->priv_data; + *pkt = ast->sub_pkt; pkt->stream_index = sub_st->index; + if (ff_read_packet(ast->sub_ctx, &ast->sub_pkt) < 0) ast->sub_pkt.data = NULL; } return sub_st; } -static int get_stream_idx(int *d){ - if( d[0] >= '0' && d[0] <= '9' - && d[1] >= '0' && d[1] <= '9'){ +static int get_stream_idx(unsigned *d) +{ + if (d[0] >= '0' && d[0] <= '9' && + d[1] >= '0' && d[1] <= '9') { return (d[0] - '0') * 10 + (d[1] - '0'); - }else{ - return 100; //invalid stream ID + } else { + return 100; // invalid stream ID } } @@ -932,52 +1009,53 @@ static int avi_sync(AVFormatContext *s, int exit_early) start_sync: memset(d, -1, sizeof(d)); - for(i=sync=avio_tell(pb); !url_feof(pb); i++) { + for (i = sync = avio_tell(pb); !url_feof(pb); i++) { int j; - for(j=0; j<7; j++) - d[j]= d[j+1]; - d[7]= avio_r8(pb); + for (j = 0; j < 7; j++) + d[j] = d[j + 1]; + d[7] = avio_r8(pb); - size= d[4] + (d[5]<<8) + (d[6]<<16) + (d[7]<<24); + size = d[4] + (d[5] << 8) + (d[6] << 16) + (d[7] << 24); - n= get_stream_idx(d+2); + n = get_stream_idx(d + 2); av_dlog(s, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n); - if(i + (uint64_t)size > avi->fsize || d[0] > 127) + if (i*(avi->io_fsize>0) + (uint64_t)size > avi->fsize || d[0] > 127) continue; - //parse ix## - if( (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams) - //parse JUNK - ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K') - ||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){ + // parse ix## + if ((d[0] == 'i' && d[1] == 'x' && n < s->nb_streams) || + // parse JUNK + (d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K') || + (d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')) { avio_skip(pb, size); goto start_sync; } - //parse stray LIST - if(d[0] == 'L' && d[1] == 'I' && d[2] == 'S' && d[3] == 'T'){ + // parse stray LIST + if (d[0] == 'L' && d[1] == 'I' && d[2] == 'S' && d[3] == 'T') { avio_skip(pb, 4); goto start_sync; } - n= get_stream_idx(d); + n = avi->dv_demux ? 0 : get_stream_idx(d); - if(!((i-avi->last_pkt_pos)&1) && get_stream_idx(d+1) < s->nb_streams) + if (!((i - avi->last_pkt_pos) & 1) && + get_stream_idx(d + 1) < s->nb_streams) continue; - //detect ##ix chunk and skip - if(d[2] == 'i' && d[3] == 'x' && n < s->nb_streams){ + // detect ##ix chunk and skip + if (d[2] == 'i' && d[3] == 'x' && n < s->nb_streams) { avio_skip(pb, size); goto start_sync; } - //parse ##dc/##wb - if(n < s->nb_streams){ + // parse ##dc/##wb + if (n < s->nb_streams) { AVStream *st; AVIStream *ast; - st = s->streams[n]; + st = s->streams[n]; ast = st->priv_data; if (!ast) { @@ -985,67 +1063,74 @@ start_sync: continue; } - if(s->nb_streams>=2){ - AVStream *st1 = s->streams[1]; - AVIStream *ast1= st1->priv_data; - //workaround for broken small-file-bug402.avi - if( d[2] == 'w' && d[3] == 'b' - && n==0 + if (s->nb_streams >= 2) { + AVStream *st1 = s->streams[1]; + AVIStream *ast1 = st1->priv_data; + // workaround for broken small-file-bug402.avi + if ( d[2] == 'w' && d[3] == 'b' + && n == 0 && st ->codec->codec_type == AVMEDIA_TYPE_VIDEO && st1->codec->codec_type == AVMEDIA_TYPE_AUDIO && ast->prefix == 'd'*256+'c' && (d[2]*256+d[3] == ast1->prefix || !ast1->prefix_count) - ){ - n=1; - st = st1; + ) { + n = 1; + st = st1; ast = ast1; - av_log(s, AV_LOG_WARNING, "Invalid stream + prefix combination, assuming audio.\n"); + av_log(s, AV_LOG_WARNING, + "Invalid stream + prefix combination, assuming audio.\n"); } } - - if( (st->discard >= AVDISCARD_DEFAULT && size==0) - /*|| (st->discard >= AVDISCARD_NONKEY && !(pkt->flags & AV_PKT_FLAG_KEY))*/ //FIXME needs a little reordering - || st->discard >= AVDISCARD_ALL){ + if (!avi->dv_demux && + ((st->discard >= AVDISCARD_DEFAULT && size == 0) /* || + // FIXME: needs a little reordering + (st->discard >= AVDISCARD_NONKEY && + !(pkt->flags & AV_PKT_FLAG_KEY)) */ + || st->discard >= AVDISCARD_ALL)) { if (!exit_early) { ast->frame_offset += get_duration(ast, size); + avio_skip(pb, size); + goto start_sync; } - avio_skip(pb, size); - goto start_sync; } - if (d[2] == 'p' && d[3] == 'c' && size<=4*256+4) { - int k = avio_r8(pb); + if (d[2] == 'p' && d[3] == 'c' && size <= 4 * 256 + 4) { + int k = avio_r8(pb); int last = (k + avio_r8(pb) - 1) & 0xFF; - avio_rl16(pb); //flags + avio_rl16(pb); // flags + // b + (g << 8) + (r << 16); for (; k <= last; k++) - ast->pal[k] = 0xFFU<<24 | avio_rb32(pb)>>8;// b + (g << 8) + (r << 16); - ast->has_pal= 1; - goto start_sync; - } else if( ((ast->prefix_count<5 || sync+9 > i) && d[2]<128 && d[3]<128) || - d[2]*256+d[3] == ast->prefix /*|| - (d[2] == 'd' && d[3] == 'c') || - (d[2] == 'w' && d[3] == 'b')*/) { + ast->pal[k] = 0xFFU<<24 | avio_rb32(pb)>>8; + ast->has_pal = 1; + goto start_sync; + } else if (((ast->prefix_count < 5 || sync + 9 > i) && + d[2] < 128 && d[3] < 128) || + d[2] * 256 + d[3] == ast->prefix /* || + (d[2] == 'd' && d[3] == 'c') || + (d[2] == 'w' && d[3] == 'b') */) { if (exit_early) return 0; - if(d[2]*256+d[3] == ast->prefix) + if (d[2] * 256 + d[3] == ast->prefix) ast->prefix_count++; - else{ - ast->prefix= d[2]*256+d[3]; - ast->prefix_count= 0; + else { + ast->prefix = d[2] * 256 + d[3]; + ast->prefix_count = 0; } - avi->stream_index= n; - ast->packet_size= size + 8; - ast->remaining= size; + avi->stream_index = n; + ast->packet_size = size + 8; + ast->remaining = size; - if(size || !ast->sample_size){ - uint64_t pos= avio_tell(pb) - 8; - if(!st->index_entries || !st->nb_index_entries || st->index_entries[st->nb_index_entries - 1].pos < pos){ - av_add_index_entry(st, pos, ast->frame_offset, size, 0, AVINDEX_KEYFRAME); + if (size || !ast->sample_size) { + uint64_t pos = avio_tell(pb) - 8; + if (!st->index_entries || !st->nb_index_entries || + st->index_entries[st->nb_index_entries - 1].pos < pos) { + av_add_index_entry(st, pos, ast->frame_offset, size, + 0, AVINDEX_KEYFRAME); } } return 0; @@ -1053,7 +1138,7 @@ start_sync: } } - if(pb->error) + if (pb->error) return pb->error; return AVERROR_EOF; } @@ -1064,106 +1149,117 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) AVIOContext *pb = s->pb; int err; #if FF_API_DESTRUCT_PACKET - void* dstr; + void *dstr; #endif if (CONFIG_DV_DEMUXER && avi->dv_demux) { int size = avpriv_dv_get_packet(avi->dv_demux, pkt); if (size >= 0) return size; + else + goto resync; } - if(avi->non_interleaved){ + if (avi->non_interleaved) { int best_stream_index = 0; - AVStream *best_st= NULL; + AVStream *best_st = NULL; AVIStream *best_ast; - int64_t best_ts= INT64_MAX; + int64_t best_ts = INT64_MAX; int i; - for(i=0; i<s->nb_streams; i++){ - AVStream *st = s->streams[i]; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; AVIStream *ast = st->priv_data; - int64_t ts= ast->frame_offset; + int64_t ts = ast->frame_offset; int64_t last_ts; - if(!st->nb_index_entries) + if (!st->nb_index_entries) continue; last_ts = st->index_entries[st->nb_index_entries - 1].timestamp; - if(!ast->remaining && ts > last_ts) + if (!ast->remaining && ts > last_ts) continue; - ts = av_rescale_q(ts, st->time_base, (AVRational){FFMAX(1, ast->sample_size), AV_TIME_BASE}); + ts = av_rescale_q(ts, st->time_base, + (AVRational) { FFMAX(1, ast->sample_size), + AV_TIME_BASE }); av_dlog(s, "%"PRId64" %d/%d %"PRId64"\n", ts, st->time_base.num, st->time_base.den, ast->frame_offset); - if(ts < best_ts){ - best_ts= ts; - best_st= st; - best_stream_index= i; + if (ts < best_ts) { + best_ts = ts; + best_st = st; + best_stream_index = i; } } - if(!best_st) + if (!best_st) return AVERROR_EOF; best_ast = best_st->priv_data; - best_ts = best_ast->frame_offset; - if(best_ast->remaining) - i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD); - else{ - i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY); - if(i>=0) - best_ast->frame_offset= best_st->index_entries[i].timestamp; + best_ts = best_ast->frame_offset; + if (best_ast->remaining) { + i = av_index_search_timestamp(best_st, + best_ts, + AVSEEK_FLAG_ANY | + AVSEEK_FLAG_BACKWARD); + } else { + i = av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY); + if (i >= 0) + best_ast->frame_offset = best_st->index_entries[i].timestamp; } - if(i>=0){ - int64_t pos= best_st->index_entries[i].pos; + if (i >= 0) { + int64_t pos = best_st->index_entries[i].pos; pos += best_ast->packet_size - best_ast->remaining; - if(avio_seek(s->pb, pos + 8, SEEK_SET) < 0) + if (avio_seek(s->pb, pos + 8, SEEK_SET) < 0) return AVERROR_EOF; av_assert0(best_ast->remaining <= best_ast->packet_size); - avi->stream_index= best_stream_index; - if(!best_ast->remaining) - best_ast->packet_size= - best_ast->remaining= best_st->index_entries[i].size; + avi->stream_index = best_stream_index; + if (!best_ast->remaining) + best_ast->packet_size = + best_ast->remaining = best_st->index_entries[i].size; } else return AVERROR_EOF; } resync: - if(avi->stream_index >= 0){ - AVStream *st= s->streams[ avi->stream_index ]; - AVIStream *ast= st->priv_data; + if (avi->stream_index >= 0) { + AVStream *st = s->streams[avi->stream_index]; + AVIStream *ast = st->priv_data; int size, err; - if(get_subtitle_pkt(s, st, pkt)) + if (get_subtitle_pkt(s, st, pkt)) return 0; - if(ast->sample_size <= 1) // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM - size= INT_MAX; - else if(ast->sample_size < 32) + // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM + if (ast->sample_size <= 1) + size = INT_MAX; + else if (ast->sample_size < 32) // arbitrary multiplier to avoid tiny packets for raw PCM data - size= 1024*ast->sample_size; + size = 1024 * ast->sample_size; else - size= ast->sample_size; + size = ast->sample_size; - if(size > ast->remaining) - size= ast->remaining; - avi->last_pkt_pos= avio_tell(pb); - err= av_get_packet(pb, pkt, size); - if(err<0) + if (size > ast->remaining) + size = ast->remaining; + avi->last_pkt_pos = avio_tell(pb); + err = av_get_packet(pb, pkt, size); + if (err < 0) return err; size = err; - if(ast->has_pal && pkt->size<(unsigned)INT_MAX/2){ + if (ast->has_pal && pkt->size < (unsigned)INT_MAX / 2) { uint8_t *pal; - pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); - if(!pal){ - av_log(s, AV_LOG_ERROR, "Failed to allocate data for palette\n"); - }else{ + pal = av_packet_new_side_data(pkt, + AV_PKT_DATA_PALETTE, + AVPALETTE_SIZE); + if (!pal) { + av_log(s, AV_LOG_ERROR, + "Failed to allocate data for palette\n"); + } else { memcpy(pal, ast->pal, AVPALETTE_SIZE); ast->has_pal = 0; } @@ -1172,50 +1268,61 @@ resync: if (CONFIG_DV_DEMUXER && avi->dv_demux) { AVBufferRef *avbuf = pkt->buf; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS dstr = pkt->destruct; +FF_ENABLE_DEPRECATION_WARNINGS #endif size = avpriv_dv_produce_packet(avi->dv_demux, pkt, - pkt->data, pkt->size, pkt->pos); + pkt->data, pkt->size, pkt->pos); #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS pkt->destruct = dstr; +FF_ENABLE_DEPRECATION_WARNINGS #endif - pkt->buf = avbuf; + pkt->buf = avbuf; pkt->flags |= AV_PKT_FLAG_KEY; if (size < 0) av_free_packet(pkt); - } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE - && !st->codec->codec_tag && read_gab2_sub(st, pkt)) { + } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE && + !st->codec->codec_tag && read_gab2_sub(st, pkt)) { ast->frame_offset++; avi->stream_index = -1; - ast->remaining = 0; + ast->remaining = 0; goto resync; } else { /* XXX: How to handle B-frames in AVI? */ pkt->dts = ast->frame_offset; // pkt->dts += ast->start; - if(ast->sample_size) + if (ast->sample_size) pkt->dts /= ast->sample_size; - av_dlog(s, "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d base:%d st:%d size:%d\n", - pkt->dts, ast->frame_offset, ast->scale, ast->rate, - ast->sample_size, AV_TIME_BASE, avi->stream_index, size); + av_dlog(s, + "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d " + "base:%d st:%d size:%d\n", + pkt->dts, + ast->frame_offset, + ast->scale, + ast->rate, + ast->sample_size, + AV_TIME_BASE, + avi->stream_index, + size); pkt->stream_index = avi->stream_index; - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->index_entries) { AVIndexEntry *e; int index; - av_assert0(st->index_entries); - index= av_index_search_timestamp(st, ast->frame_offset, 0); - e= &st->index_entries[index]; + index = av_index_search_timestamp(st, ast->frame_offset, 0); + e = &st->index_entries[index]; - if(index >= 0 && e->timestamp == ast->frame_offset){ - if (index == st->nb_index_entries-1){ + if (index >= 0 && e->timestamp == ast->frame_offset) { + if (index == st->nb_index_entries-1) { int key=1; int i; uint32_t state=-1; - for(i=0; i<FFMIN(size,256); i++){ - if(st->codec->codec_id == AV_CODEC_ID_MPEG4){ - if(state == 0x1B6){ + for (i=0; i<FFMIN(size,256); i++) { + if (st->codec->codec_id == AV_CODEC_ID_MPEG4) { + if (state == 0x1B6) { key= !(pkt->data[i]&0xC0); break; } @@ -1223,7 +1330,7 @@ resync: break; state= (state<<8) + pkt->data[i]; } - if(!key) + if (!key) e->flags &= ~AVINDEX_KEYFRAME; } if (e->flags & AVINDEX_KEYFRAME) @@ -1235,24 +1342,24 @@ resync: ast->frame_offset += get_duration(ast, pkt->size); } ast->remaining -= err; - if(!ast->remaining){ - avi->stream_index= -1; - ast->packet_size= 0; + if (!ast->remaining) { + avi->stream_index = -1; + ast->packet_size = 0; } - if(!avi->non_interleaved && pkt->pos >= 0 && ast->seek_pos > pkt->pos){ + if (!avi->non_interleaved && pkt->pos >= 0 && ast->seek_pos > pkt->pos) { av_free_packet(pkt); goto resync; } ast->seek_pos= 0; - if(!avi->non_interleaved && st->nb_index_entries>1 && avi->index_loaded>1){ + if (!avi->non_interleaved && st->nb_index_entries>1 && avi->index_loaded>1) { int64_t dts= av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q); - if(avi->dts_max - dts > 2*AV_TIME_BASE){ + if (avi->dts_max - dts > 2*AV_TIME_BASE) { avi->non_interleaved= 1; av_log(s, AV_LOG_INFO, "Switching to NI mode, due to poor interleaving\n"); - }else if(avi->dts_max < dts) + }else if (avi->dts_max < dts) avi->dts_max = dts; } @@ -1265,7 +1372,7 @@ resync: } /* XXX: We make the implicit supposition that the positions are sorted - for each stream. */ + * for each stream. */ static int avi_read_idx1(AVFormatContext *s, int size) { AVIContext *avi = s->priv_data; @@ -1274,8 +1381,8 @@ static int avi_read_idx1(AVFormatContext *s, int size) AVStream *st; AVIStream *ast; unsigned int index, tag, flags, pos, len, first_packet = 1; - unsigned last_pos= -1; - unsigned last_idx= -1; + unsigned last_pos = -1; + unsigned last_idx = -1; int64_t idx1_pos, first_packet_pos = 0, data_offset = 0; int anykey = 0; @@ -1284,39 +1391,38 @@ static int avi_read_idx1(AVFormatContext *s, int size) return AVERROR_INVALIDDATA; idx1_pos = avio_tell(pb); - avio_seek(pb, avi->movi_list+4, SEEK_SET); - if (avi_sync(s, 1) == 0) { + avio_seek(pb, avi->movi_list + 4, SEEK_SET); + if (avi_sync(s, 1) == 0) first_packet_pos = avio_tell(pb) - 8; - } avi->stream_index = -1; avio_seek(pb, idx1_pos, SEEK_SET); - if (s->nb_streams == 1 && s->streams[0]->codec->codec_tag == AV_RL32("MMES")){ + if (s->nb_streams == 1 && s->streams[0]->codec->codec_tag == AV_RL32("MMES")) { first_packet_pos = 0; data_offset = avi->movi_list; } /* Read the entries and sort them in each stream component. */ - for(i = 0; i < nb_index_entries; i++) { - if(url_feof(pb)) + for (i = 0; i < nb_index_entries; i++) { + if (url_feof(pb)) return -1; - tag = avio_rl32(pb); + tag = avio_rl32(pb); flags = avio_rl32(pb); - pos = avio_rl32(pb); - len = avio_rl32(pb); + pos = avio_rl32(pb); + len = avio_rl32(pb); av_dlog(s, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/", i, tag, flags, pos, len); - index = ((tag & 0xff) - '0') * 10; - index += ((tag >> 8) & 0xff) - '0'; + index = ((tag & 0xff) - '0') * 10; + index += (tag >> 8 & 0xff) - '0'; if (index >= s->nb_streams) continue; - st = s->streams[index]; + st = s->streams[index]; ast = st->priv_data; - if(first_packet && first_packet_pos && len) { - data_offset = first_packet_pos - pos; + if (first_packet && first_packet_pos) { + data_offset = first_packet_pos - pos; first_packet = 0; } pos += data_offset; @@ -1325,15 +1431,16 @@ static int avi_read_idx1(AVFormatContext *s, int size) // even if we have only a single stream, we should // switch to non-interleaved to get correct timestamps - if(last_pos == pos) - avi->non_interleaved= 1; - if(last_idx != pos && len) { - av_add_index_entry(st, pos, ast->cum_len, len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0); + if (last_pos == pos) + avi->non_interleaved = 1; + if (last_idx != pos && len) { + av_add_index_entry(st, pos, ast->cum_len, len, 0, + (flags & AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0); last_idx= pos; } ast->cum_len += get_duration(ast, len); - last_pos= pos; - anykey |= flags&AVIIF_INDEX; + last_pos = pos; + anykey |= flags&AVIIF_INDEX; } if (!anykey) { for (index = 0; index < s->nb_streams; index++) { @@ -1345,56 +1452,60 @@ static int avi_read_idx1(AVFormatContext *s, int size) return 0; } -static int guess_ni_flag(AVFormatContext *s){ +static int guess_ni_flag(AVFormatContext *s) +{ int i; - int64_t last_start=0; - int64_t first_end= INT64_MAX; - int64_t oldpos= avio_tell(s->pb); + int64_t last_start = 0; + int64_t first_end = INT64_MAX; + int64_t oldpos = avio_tell(s->pb); int *idx; int64_t min_pos, pos; - for(i=0; i<s->nb_streams; i++){ + for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - int n= st->nb_index_entries; + int n = st->nb_index_entries; unsigned int size; - if(n <= 0) + if (n <= 0) continue; - if(n >= 2){ - int64_t pos= st->index_entries[0].pos; + if (n >= 2) { + int64_t pos = st->index_entries[0].pos; avio_seek(s->pb, pos + 4, SEEK_SET); - size= avio_rl32(s->pb); - if(pos + size > st->index_entries[1].pos) - last_start= INT64_MAX; + size = avio_rl32(s->pb); + if (pos + size > st->index_entries[1].pos) + last_start = INT64_MAX; } - if(st->index_entries[0].pos > last_start) - last_start= st->index_entries[0].pos; - if(st->index_entries[n-1].pos < first_end) - first_end= st->index_entries[n-1].pos; + if (st->index_entries[0].pos > last_start) + last_start = st->index_entries[0].pos; + if (st->index_entries[n - 1].pos < first_end) + first_end = st->index_entries[n - 1].pos; } avio_seek(s->pb, oldpos, SEEK_SET); if (last_start > first_end) return 1; - idx= av_mallocz(sizeof(*idx) * s->nb_streams); + idx= av_calloc(s->nb_streams, sizeof(*idx)); + if (!idx) + return 0; for (min_pos=pos=0; min_pos!=INT64_MAX; pos= min_pos+1LU) { int64_t max_dts = INT64_MIN/2, min_dts= INT64_MAX/2; min_pos = INT64_MAX; for (i=0; i<s->nb_streams; i++) { AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; int n= st->nb_index_entries; while (idx[i]<n && st->index_entries[idx[i]].pos < pos) idx[i]++; if (idx[i] < n) { - min_dts = FFMIN(min_dts, av_rescale_q(st->index_entries[idx[i]].timestamp, st->time_base, AV_TIME_BASE_Q)); + min_dts = FFMIN(min_dts, av_rescale_q(st->index_entries[idx[i]].timestamp/FFMAX(ast->sample_size, 1), st->time_base, AV_TIME_BASE_Q)); min_pos = FFMIN(min_pos, st->index_entries[idx[i]].pos); } if (idx[i]) - max_dts = FFMAX(max_dts, av_rescale_q(st->index_entries[idx[i]-1].timestamp, st->time_base, AV_TIME_BASE_Q)); + max_dts = FFMAX(max_dts, av_rescale_q(st->index_entries[idx[i]-1].timestamp/FFMAX(ast->sample_size, 1), st->time_base, AV_TIME_BASE_Q)); } - if(max_dts - min_dts > 2*AV_TIME_BASE) { + if (max_dts - min_dts > 2*AV_TIME_BASE) { av_free(idx); return 1; } @@ -1408,15 +1519,15 @@ static int avi_load_index(AVFormatContext *s) AVIContext *avi = s->priv_data; AVIOContext *pb = s->pb; uint32_t tag, size; - int64_t pos= avio_tell(pb); + int64_t pos = avio_tell(pb); int64_t next; - int ret = -1; + int ret = -1; if (avio_seek(pb, avi->movi_end, SEEK_SET) < 0) goto the_end; // maybe truncated file av_dlog(s, "movi_end=0x%"PRIx64"\n", avi->movi_end); - for(;;) { - tag = avio_rl32(pb); + for (;;) { + tag = avio_rl32(pb); size = avio_rl32(pb); if (url_feof(pb)) break; @@ -1433,18 +1544,19 @@ static int avi_load_index(AVFormatContext *s) avi_read_idx1(s, size) >= 0) { avi->index_loaded=2; ret = 0; - }else if(tag == MKTAG('L', 'I', 'S', 'T')) { + }else if (tag == MKTAG('L', 'I', 'S', 'T')) { uint32_t tag1 = avio_rl32(pb); if (tag1 == MKTAG('I', 'N', 'F', 'O')) ff_read_riff_info(s, size - 4); - }else if(!ret) + }else if (!ret) break; if (avio_seek(pb, next, SEEK_SET) < 0) break; // something is wrong here } - the_end: + +the_end: avio_seek(pb, pos, SEEK_SET); return ret; } @@ -1452,14 +1564,15 @@ static int avi_load_index(AVFormatContext *s) static void seek_subtitle(AVStream *st, AVStream *st2, int64_t timestamp) { AVIStream *ast2 = st2->priv_data; - int64_t ts2 = av_rescale_q(timestamp, st->time_base, st2->time_base); + int64_t ts2 = av_rescale_q(timestamp, st->time_base, st2->time_base); av_free_packet(&ast2->sub_pkt); if (avformat_seek_file(ast2->sub_ctx, 0, INT64_MIN, ts2, ts2, 0) >= 0 || avformat_seek_file(ast2->sub_ctx, 0, ts2, ts2, INT64_MAX, 0) >= 0) ff_read_packet(ast2->sub_ctx, &ast2->sub_pkt); } -static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +static int avi_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) { AVIContext *avi = s->priv_data; AVStream *st; @@ -1467,17 +1580,25 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp int64_t pos, pos_min; AVIStream *ast; + /* Does not matter which stream is requested dv in avi has the + * stream information in the first video stream. + */ + if (avi->dv_demux) + stream_index = 0; + if (!avi->index_loaded) { /* we only load the index on demand */ avi_load_index(s); avi->index_loaded |= 1; } - av_assert0(stream_index>= 0); - - st = s->streams[stream_index]; - ast= st->priv_data; - index= av_index_search_timestamp(st, timestamp * FFMAX(ast->sample_size, 1), flags); - if (index<0) { + av_assert0(stream_index >= 0); + + st = s->streams[stream_index]; + ast = st->priv_data; + index = av_index_search_timestamp(st, + timestamp * FFMAX(ast->sample_size, 1), + flags); + if (index < 0) { if (st->nb_index_entries > 0) av_log(s, AV_LOG_DEBUG, "Failed to find timestamp %"PRId64 " in index %"PRId64 " .. %"PRId64 "\n", timestamp * FFMAX(ast->sample_size, 1), @@ -1487,7 +1608,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp } /* find the position */ - pos = st->index_entries[index].pos; + pos = st->index_entries[index].pos; timestamp = st->index_entries[index].timestamp / FFMAX(ast->sample_size, 1); av_dlog(s, "XX %"PRId64" %d %"PRId64"\n", @@ -1497,26 +1618,25 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp /* One and only one real stream for DV in AVI, and it has video */ /* offsets. Calling with other stream indexes should have failed */ /* the av_index_search_timestamp call above. */ - av_assert0(stream_index == 0); - if(avio_seek(s->pb, pos, SEEK_SET) < 0) + if (avio_seek(s->pb, pos, SEEK_SET) < 0) return -1; /* Feed the DV video stream version of the timestamp to the */ /* DV demux so it can synthesize correct timestamps. */ ff_dv_offset_reset(avi->dv_demux, timestamp); - avi->stream_index= -1; + avi->stream_index = -1; return 0; } - pos_min= pos; - for(i = 0; i < s->nb_streams; i++) { - AVStream *st2 = s->streams[i]; + pos_min = pos; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st2 = s->streams[i]; AVIStream *ast2 = st2->priv_data; - ast2->packet_size= - ast2->remaining= 0; + ast2->packet_size = + ast2->remaining = 0; if (ast2->sub_ctx) { seek_subtitle(st, st2, timestamp); @@ -1527,17 +1647,22 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp continue; // av_assert1(st2->codec->block_align); - av_assert0((int64_t)st2->time_base.num*ast2->rate == (int64_t)st2->time_base.den*ast2->scale); - index = av_index_search_timestamp( - st2, - av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1), - flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0)); - if(index<0) - index=0; - ast2->seek_pos= st2->index_entries[index].pos; - pos_min= FFMIN(pos_min,ast2->seek_pos); + av_assert0((int64_t)st2->time_base.num * ast2->rate == + (int64_t)st2->time_base.den * ast2->scale); + index = av_index_search_timestamp(st2, + av_rescale_q(timestamp, + st->time_base, + st2->time_base) * + FFMAX(ast2->sample_size, 1), + flags | + AVSEEK_FLAG_BACKWARD | + (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0)); + if (index < 0) + index = 0; + ast2->seek_pos = st2->index_entries[index].pos; + pos_min = FFMIN(pos_min,ast2->seek_pos); } - for(i = 0; i < s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { AVStream *st2 = s->streams[i]; AVIStream *ast2 = st2->priv_data; @@ -1548,9 +1673,9 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp st2, av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1), flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0)); - if(index<0) - index=0; - while(!avi->non_interleaved && index>0 && st2->index_entries[index-1].pos >= pos_min) + if (index < 0) + index = 0; + while (!avi->non_interleaved && index>0 && st2->index_entries[index-1].pos >= pos_min) index--; ast2->frame_offset = st2->index_entries[index].timestamp; } @@ -1560,8 +1685,8 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp av_log(s, AV_LOG_ERROR, "Seek failed\n"); return -1; } - avi->stream_index= -1; - avi->dts_max= INT_MIN; + avi->stream_index = -1; + avi->dts_max = INT_MIN; return 0; } @@ -1570,8 +1695,8 @@ static int avi_read_close(AVFormatContext *s) int i; AVIContext *avi = s->priv_data; - for(i=0;i<s->nb_streams;i++) { - AVStream *st = s->streams[i]; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; AVIStream *ast = st->priv_data; if (ast) { if (ast->sub_ctx) { @@ -1593,9 +1718,9 @@ static int avi_probe(AVProbeData *p) int i; /* check file header */ - for(i=0; avi_headers[i][0]; i++) - if(!memcmp(p->buf , avi_headers[i] , 4) && - !memcmp(p->buf+8, avi_headers[i]+4, 4)) + for (i = 0; avi_headers[i][0]; i++) + if (!memcmp(p->buf, avi_headers[i], 4) && + !memcmp(p->buf + 8, avi_headers[i] + 4, 4)) return AVPROBE_SCORE_MAX; return 0; diff --git a/ffmpeg/libavformat/avienc.c b/ffmpeg/libavformat/avienc.c index 15f0794..95e4e7e 100644 --- a/ffmpeg/libavformat/avienc.c +++ b/ffmpeg/libavformat/avienc.c @@ -26,6 +26,8 @@ #include "avi.h" #include "avio_internal.h" #include "riff.h" +#include "libavformat/avlanguage.h" +#include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "libavutil/avassert.h" @@ -57,7 +59,7 @@ typedef struct { typedef struct { int64_t frames_hdr_strm; - int audio_strm_length; + int64_t audio_strm_length; int packet_count; int entry; @@ -291,7 +293,7 @@ static int avi_write_header(AVFormatContext *s) // are not (yet) supported. if (stream->codec_id != AV_CODEC_ID_XSUB) break; case AVMEDIA_TYPE_VIDEO: - ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0); + ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0, 0); break; case AVMEDIA_TYPE_AUDIO: if ((ret = ff_put_wav_header(pb, stream)) < 0) { @@ -309,6 +311,16 @@ static int avi_write_header(AVFormatContext *s) ff_riff_write_info_tag(s->pb, "strn", t->value); t = NULL; } + if(stream->codec_id == AV_CODEC_ID_XSUB + && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) { + const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1); + t = NULL; + if (langstr) { + char* str = av_asprintf("Subtitle - %s-xx;02", langstr); + ff_riff_write_info_tag(s->pb, "strn", str); + av_free(str); + } + } } if (pb->seekable) { @@ -523,7 +535,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) int size= pkt->size; av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(pkt->dts), avist->packet_count, stream_index); - while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB){ + while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count){ AVPacket empty_packet; if(pkt->dts - avist->packet_count > 60000){ @@ -567,8 +579,11 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; if (idx->ents_allocated <= idx->entry) { idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1); - if (!idx->cluster) + if (!idx->cluster) { + idx->ents_allocated = 0; + idx->entry = 0; return AVERROR(ENOMEM); + } idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); if (!idx->cluster[cl]) return AVERROR(ENOMEM); @@ -587,7 +602,6 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) if (size & 1) avio_w8(pb, 0); - avio_flush(pb); return 0; } @@ -637,7 +651,7 @@ static int avi_write_trailer(AVFormatContext *s) for (i=0; i<s->nb_streams; i++) { AVIStream *avist= s->streams[i]->priv_data; for (j=0; j<avist->indexes.ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++) - av_free(avist->indexes.cluster[j]); + av_freep(&avist->indexes.cluster[j]); av_freep(&avist->indexes.cluster); avist->indexes.ents_allocated = avist->indexes.entry = 0; } @@ -659,5 +673,4 @@ AVOutputFormat ff_avi_muxer = { .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags, ff_codec_wav_tags, 0 }, - .flags = AVFMT_VARIABLE_FPS, }; diff --git a/ffmpeg/libavformat/avio.c b/ffmpeg/libavformat/avio.c index f6af0cb..225d982 100644 --- a/ffmpeg/libavformat/avio.c +++ b/ffmpeg/libavformat/avio.c @@ -42,8 +42,10 @@ URLProtocol *ffurl_protocol_next(URLProtocol *prev) static const char *urlcontext_to_name(void *ptr) { URLContext *h = (URLContext *)ptr; - if(h->prot) return h->prot->name; - else return "NULL"; + if (h->prot) + return h->prot->name; + else + return "NULL"; } static void *urlcontext_child_next(void *obj, void *prev) @@ -68,49 +70,44 @@ static const AVClass *urlcontext_child_class_next(const AVClass *prev) if (p->priv_data_class) return p->priv_data_class; return NULL; - } -static const AVOption options[] = {{NULL}}; +static const AVOption options[] = { { NULL } }; const AVClass ffurl_context_class = { - .class_name = "URLContext", - .item_name = urlcontext_to_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, - .child_next = urlcontext_child_next, + .class_name = "URLContext", + .item_name = urlcontext_to_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .child_next = urlcontext_child_next, .child_class_next = urlcontext_child_class_next, }; /*@}*/ - const char *avio_enum_protocols(void **opaque, int output) { URLProtocol *p; *opaque = ffurl_protocol_next(*opaque); - if (!(p = *opaque)) return NULL; + if (!(p = *opaque)) + return NULL; if ((output && p->url_write) || (!output && p->url_read)) return p->name; return avio_enum_protocols(opaque, output); } -int ffurl_register_protocol(URLProtocol *protocol, int size) +int ffurl_register_protocol(URLProtocol *protocol) { URLProtocol **p; - if (size < sizeof(URLProtocol)) { - URLProtocol* temp = av_mallocz(sizeof(URLProtocol)); - memcpy(temp, protocol, size); - protocol = temp; - } p = &first_protocol; - while (*p != NULL) p = &(*p)->next; - *p = protocol; + while (*p != NULL) + p = &(*p)->next; + *p = protocol; protocol->next = NULL; return 0; } -static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, - const char *filename, int flags, - const AVIOInterruptCB *int_cb) +static int url_alloc_for_protocol(URLContext **puc, struct URLProtocol *up, + const char *filename, int flags, + const AVIOInterruptCB *int_cb) { URLContext *uc; int err; @@ -135,18 +132,22 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, goto fail; } uc->av_class = &ffurl_context_class; - uc->filename = (char *) &uc[1]; + uc->filename = (char *)&uc[1]; strcpy(uc->filename, filename); - uc->prot = up; - uc->flags = flags; - uc->is_streamed = 0; /* default = not streamed */ + uc->prot = up; + uc->flags = flags; + uc->is_streamed = 0; /* default = not streamed */ uc->max_packet_size = 0; /* default: stream file */ if (up->priv_data_size) { uc->priv_data = av_mallocz(up->priv_data_size); + if (!uc->priv_data) { + err = AVERROR(ENOMEM); + goto fail; + } if (up->priv_data_class) { int proto_len= strlen(up->name); char *start = strchr(uc->filename, ','); - *(const AVClass**)uc->priv_data = up->priv_data_class; + *(const AVClass **)uc->priv_data = up->priv_data_class; av_opt_set_defaults(uc->priv_data); if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){ int ret= 0; @@ -178,8 +179,11 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, *puc = uc; return 0; - fail: +fail: *puc = NULL; + if (uc) + av_freep(&uc->priv_data); + av_freep(&uc); #if CONFIG_NETWORK if (up->flags & URL_PROTOCOL_FLAG_NETWORK) ff_network_close(); @@ -187,19 +191,22 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, return err; } -int ffurl_connect(URLContext* uc, AVDictionary **options) +int ffurl_connect(URLContext *uc, AVDictionary **options) { int err = - uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) : + uc->prot->url_open2 ? uc->prot->url_open2(uc, + uc->filename, + uc->flags, + options) : uc->prot->url_open(uc, uc->filename, uc->flags); if (err) return err; uc->is_connected = 1; - //We must be careful here as ffurl_seek() could be slow, for example for http - if( (uc->flags & AVIO_FLAG_WRITE) - || !strcmp(uc->prot->name, "file")) - if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0) - uc->is_streamed= 1; + /* We must be careful here as ffurl_seek() could be slow, + * for example for http */ + if ((uc->flags & AVIO_FLAG_WRITE) || !strcmp(uc->prot->name, "file")) + if (!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0) + uc->is_streamed = 1; return 0; } @@ -225,7 +232,8 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, is_dos_path(filename)) strcpy(proto_str, "file"); else - av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str))); + av_strlcpy(proto_str, filename, + FFMIN(proto_len + 1, sizeof(proto_str))); if ((ptr = strchr(proto_str, ','))) *ptr = '\0'; @@ -235,12 +243,14 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, while (up = ffurl_protocol_next(up)) { if (!strcmp(proto_str, up->name)) - return url_alloc_for_protocol (puc, up, filename, flags, int_cb); + return url_alloc_for_protocol(puc, up, filename, flags, int_cb); if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME && !strcmp(proto_nested, up->name)) - return url_alloc_for_protocol (puc, up, filename, flags, int_cb); + return url_alloc_for_protocol(puc, up, filename, flags, int_cb); } *puc = NULL; + if (!strcmp("https", proto_str)) + av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.\n"); return AVERROR_PROTOCOL_NOT_FOUND; } @@ -262,8 +272,11 @@ fail: return ret; } -static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min, - int (*transfer_func)(URLContext *h, unsigned char *buf, int size)) +static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf, + int size, int size_min, + int (*transfer_func)(URLContext *h, + uint8_t *buf, + int size)) { int ret, len; int fast_retries = 5; @@ -271,7 +284,9 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int len = 0; while (len < size_min) { - ret = transfer_func(h, buf+len, size-len); + if (ff_check_interrupt(&h->interrupt_callback)) + return AVERROR_EXIT; + ret = transfer_func(h, buf + len, size - len); if (ret == AVERROR(EINTR)) continue; if (h->flags & AVIO_FLAG_NONBLOCK) @@ -290,12 +305,10 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int av_usleep(1000); } } else if (ret < 1) - return ret < 0 ? ret : len; + return (ret < 0 && ret != AVERROR_EOF) ? ret : len; if (ret) - fast_retries = FFMAX(fast_retries, 2); + fast_retries = FFMAX(fast_retries, 2); len += ret; - if (len < size && ff_check_interrupt(&h->interrupt_callback)) - return AVERROR_EXIT; } return len; } @@ -339,7 +352,8 @@ int ffurl_closep(URLContext **hh) { URLContext *h= *hh; int ret = 0; - if (!h) return 0; /* can happen when ffurl_open fails */ + if (!h) + return 0; /* can happen when ffurl_open fails */ if (h->is_connected && h->prot->url_close) ret = h->prot->url_close(h); @@ -385,8 +399,8 @@ int64_t ffurl_size(URLContext *h) { int64_t pos, size; - size= ffurl_seek(h, 0, AVSEEK_SIZE); - if(size<0){ + size = ffurl_seek(h, 0, AVSEEK_SIZE); + if (size < 0) { pos = ffurl_seek(h, 0, SEEK_CUR); if ((size = ffurl_seek(h, -1, SEEK_END)) < 0) return size; diff --git a/ffmpeg/libavformat/avio.h b/ffmpeg/libavformat/avio.h index 8de28bf..4f4ac3c 100644 --- a/ffmpeg/libavformat/avio.h +++ b/ffmpeg/libavformat/avio.h @@ -120,26 +120,32 @@ typedef struct AVIOContext { * max filesize, used to limit allocations * This field is internal to libavformat and access from outside is not allowed. */ - int64_t maxsize; + int64_t maxsize; - /** - * avio_read and avio_write should if possible be satisfied directly - * instead of going through a buffer, and avio_seek will always - * call the underlying seek function directly. - */ - int direct; + /** + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ + int direct; /** * Bytes read statistic * This field is internal to libavformat and access from outside is not allowed. */ - int64_t bytes_read; + int64_t bytes_read; /** * seek statistic * This field is internal to libavformat and access from outside is not allowed. */ - int seek_count; + int seek_count; + + /** + * writeout statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int writeout_count; } AVIOContext; /* unbuffered I/O */ @@ -362,7 +368,7 @@ int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen); * In case of failure the pointed to value is set to NULL. * @param flags flags which control how the resource indicated by url * is to be opened - * @return 0 in case of success, a negative value corresponding to an + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int avio_open(AVIOContext **s, const char *url, int flags); @@ -381,7 +387,7 @@ int avio_open(AVIOContext **s, const char *url, int flags); * @param options A dictionary filled with protocol-private options. On return * this parameter will be destroyed and replaced with a dict containing options * that were not found. May be NULL. - * @return 0 in case of success, a negative value corresponding to an + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int avio_open2(AVIOContext **s, const char *url, int flags, diff --git a/ffmpeg/libavformat/avio_internal.h b/ffmpeg/libavformat/avio_internal.h index cf36764..8441d49 100644 --- a/ffmpeg/libavformat/avio_internal.h +++ b/ffmpeg/libavformat/avio_internal.h @@ -38,6 +38,23 @@ int ffio_init_context(AVIOContext *s, /** + * Read size bytes from AVIOContext, returning a pointer. + * Note that the data pointed at by the returned pointer is only + * valid until the next call that references the same IO context. + * @param s IO context + * @param buf pointer to buffer into which to assemble the requested + * data if it is not available in contiguous addresses in the + * underlying buffer + * @param size number of bytes requested + * @param data address at which to store pointer: this will be a + * a direct pointer into the underlying buffer if the requested + * number of bytes are available at contiguous addresses, otherwise + * will be a copy of buf + * @return number of bytes read or AVERROR + */ +int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data); + +/** * Read size bytes from AVIOContext into buf. * This reads at most 1 packet. If that is not enough fewer bytes will be * returned. @@ -61,7 +78,7 @@ static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s) * @param s The read-only AVIOContext to rewind * @param buf The probe buffer containing the first buf_size bytes of the file * @param buf_size The size of buf - * @return 0 in case of success, a negative value corresponding to an + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **buf, int buf_size); @@ -71,6 +88,15 @@ uint64_t ffio_read_varlen(AVIOContext *bc); /** @warning must be called before any I/O */ int ffio_set_buf_size(AVIOContext *s, int buf_size); +/** + * Ensures that the requested seekback buffer size will be available + * + * Will ensure that when reading sequentially up to buf_size, seeking + * within the current pos and pos+buf_size is possible. + * Once the stream position moves outside this window this gurantee is lost. + */ +int ffio_ensure_seekback(AVIOContext *s, int buf_size); + int ffio_limit(AVIOContext *s, int size); void ffio_init_checksum(AVIOContext *s, @@ -99,9 +125,27 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size); * * @param s Used to return the pointer to the created AVIOContext. * In case of failure the pointed to value is set to NULL. - * @return 0 in case of success, a negative value corresponding to an + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int ffio_fdopen(AVIOContext **s, URLContext *h); +/** + * Open a write-only fake memory stream. The written data is not stored + * anywhere - this is only used for measuring the amount of data + * written. + * + * @param s new IO context + * @return zero if no error. + */ +int ffio_open_null_buf(AVIOContext **s); + +/** + * Close a null buffer. + * + * @param s an IO context opened by ffio_open_null_buf + * @return the number of bytes written to the null buffer + */ +int ffio_close_null_buf(AVIOContext *s); + #endif /* AVFORMAT_AVIO_INTERNAL_H */ diff --git a/ffmpeg/libavformat/aviobuf.c b/ffmpeg/libavformat/aviobuf.c index 7a73a17..eb5a6e5 100644 --- a/ffmpeg/libavformat/aviobuf.c +++ b/ffmpeg/libavformat/aviobuf.c @@ -92,7 +92,7 @@ int ffio_init_context(AVIOContext *s, s->must_flush = 0; s->eof_reached = 0; s->error = 0; - s->seekable = AVIO_SEEKABLE_NORMAL; + s->seekable = seek ? AVIO_SEEKABLE_NORMAL : 0; s->max_packet_size = 0; s->update_checksum = NULL; @@ -131,6 +131,7 @@ static void writeout(AVIOContext *s, const uint8_t *data, int len) s->error = ret; } } + s->writeout_count ++; s->pos += len; } @@ -318,15 +319,22 @@ int avio_put_str16le(AVIOContext *s, const char *str) { const uint8_t *q = str; int ret = 0; + int err = 0; while (*q) { uint32_t ch; uint16_t tmp; - GET_UTF8(ch, *q++, break;) + GET_UTF8(ch, *q++, goto invalid;) PUT_UTF16(ch, tmp, avio_wl16(s, tmp); ret += 2;) + continue; +invalid: + av_log(s, AV_LOG_ERROR, "Invaid UTF8 sequence in avio_put_str16le\n"); + err = AVERROR(EINVAL); } avio_wl16(s, 0); + if (err) + return err; ret += 2; return ret; } @@ -391,12 +399,11 @@ void avio_wb24(AVIOContext *s, unsigned int val) static void fill_buffer(AVIOContext *s) { - uint8_t *dst = !s->max_packet_size && - s->buf_end - s->buffer < s->buffer_size ? - s->buf_end : s->buffer; - int len = s->buffer_size - (dst - s->buffer); int max_buffer_size = s->max_packet_size ? s->max_packet_size : IO_BUFFER_SIZE; + uint8_t *dst = s->buf_end - s->buffer + max_buffer_size < s->buffer_size ? + s->buf_end : s->buffer; + int len = s->buffer_size - (dst - s->buffer); /* can't fill the buffer without read_packet, just set EOF if appropriate */ if (!s->read_packet && s->buf_ptr >= s->buf_end) @@ -415,10 +422,13 @@ static void fill_buffer(AVIOContext *s) /* make buffer smaller in case it ended up large after probing */ if (s->read_packet && s->buffer_size > max_buffer_size) { - ffio_set_buf_size(s, max_buffer_size); + if (dst == s->buffer) { + ffio_set_buf_size(s, max_buffer_size); - s->checksum_ptr = dst = s->buffer; - len = s->buffer_size; + s->checksum_ptr = dst = s->buffer; + } + av_assert0(len >= max_buffer_size); + len = max_buffer_size; } if (s->read_packet) @@ -522,6 +532,18 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size) return size1 - size; } +int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data) +{ + if (s->buf_end - s->buf_ptr >= size && !s->write_flag) { + *data = s->buf_ptr; + s->buf_ptr += size; + return size; + } else { + *data = buf; + return avio_read(s, buf, size); + } +} + int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size) { int len; @@ -722,6 +744,31 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) return 0; } +int ffio_ensure_seekback(AVIOContext *s, int buf_size) +{ + uint8_t *buffer; + int max_buffer_size = s->max_packet_size ? + s->max_packet_size : IO_BUFFER_SIZE; + + buf_size += s->buf_ptr - s->buffer + max_buffer_size; + + if (buf_size < s->buffer_size || s->seekable) + return 0; + av_assert0(!s->write_flag); + + buffer = av_malloc(buf_size); + if (!buffer) + return AVERROR(ENOMEM); + + memcpy(buffer, s->buffer, s->buffer_size); + av_free(s->buffer); + s->buf_ptr = buffer + (s->buf_ptr - s->buffer); + s->buf_end = buffer + (s->buf_end - s->buffer); + s->buffer = buffer; + s->buffer_size = buf_size; + return 0; +} + int ffio_set_buf_size(AVIOContext *s, int buf_size) { uint8_t *buffer; @@ -827,7 +874,9 @@ int avio_close(AVIOContext *s) avio_flush(s); h = s->opaque; av_freep(&s->buffer); - if (!s->write_flag) + if (s->write_flag) + av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count); + else av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count); av_free(s); return ffurl_close(h); @@ -907,9 +956,12 @@ static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size) } if (new_allocated_size > d->allocated_size) { - d->buffer = av_realloc_f(d->buffer, 1, new_allocated_size); - if(d->buffer == NULL) - return AVERROR(ENOMEM); + int err; + if ((err = av_reallocp(&d->buffer, new_allocated_size)) < 0) { + d->allocated_size = 0; + d->size = 0; + return err; + } d->allocated_size = new_allocated_size; } memcpy(d->buffer + d->pos, buf, buf_size); @@ -984,11 +1036,17 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) { - DynBuffer *d = s->opaque; + DynBuffer *d; int size; static const char padbuf[FF_INPUT_BUFFER_PADDING_SIZE] = {0}; int padding = 0; + if (!s) { + *pbuffer = NULL; + return 0; + } + d = s->opaque; + /* don't attempt to pad fixed-size packet buffers */ if (!s->max_packet_size) { avio_write(s, padbuf, sizeof(padbuf)); @@ -1003,3 +1061,36 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) av_free(s); return size - padding; } + +static int null_buf_write(void *opaque, uint8_t *buf, int buf_size) +{ + DynBuffer *d = opaque; + + d->pos += buf_size; + if (d->pos > d->size) + d->size = d->pos; + return buf_size; +} + +int ffio_open_null_buf(AVIOContext **s) +{ + int ret = url_open_dyn_buf_internal(s, 0); + if (ret >= 0) { + AVIOContext *pb = *s; + pb->write_packet = null_buf_write; + } + return ret; +} + +int ffio_close_null_buf(AVIOContext *s) +{ + DynBuffer *d = s->opaque; + int size; + + avio_flush(s); + + size = d->size; + av_free(d); + av_free(s); + return size; +} diff --git a/ffmpeg/libavformat/avisynth.c b/ffmpeg/libavformat/avisynth.c index d31031d..2f438d9 100644 --- a/ffmpeg/libavformat/avisynth.c +++ b/ffmpeg/libavformat/avisynth.c @@ -1,5 +1,5 @@ /* - * Avi/AvxSynth support + * AviSynth/AvxSynth support * Copyright (c) 2012 AvxSynth Team. * * This file is part of FFmpeg @@ -18,72 +18,62 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/internal.h" +#include "libavcodec/internal.h" #include "avformat.h" #include "internal.h" -#include "libavcodec/internal.h" -// Enable function pointer definitions for runtime loading. +/* Enable function pointer definitions for runtime loading. */ #define AVSC_NO_DECLSPEC -// Shut up ffmpeg error messages. -// avisynth_c.h contains inline functions that call these functions. -#undef malloc -#undef free -#undef printf - -// Platform-specific directives for AviSynth vs AvxSynth. +/* Platform-specific directives for AviSynth vs AvxSynth. */ #ifdef _WIN32 #include <windows.h> #undef EXTERN_C #include "compat/avisynth/avisynth_c.h" + #include "compat/avisynth/avisynth_c_25.h" #define AVISYNTH_LIB "avisynth" + #define USING_AVISYNTH #else #include <dlfcn.h> #include "compat/avisynth/avxsynth_c.h" - #if defined (__APPLE__) - #define AVISYNTH_LIB "libavxsynth.dylib" - #else - #define AVISYNTH_LIB "libavxsynth.so" - #endif + #if defined (__APPLE__) + #define AVISYNTH_LIB "libavxsynth.dylib" + #else + #define AVISYNTH_LIB "libavxsynth.so" + #endif #define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_GLOBAL) #define GetProcAddress dlsym #define FreeLibrary dlclose #endif -// AvxSynth doesn't have these colorspaces, so disable them -#ifndef _WIN32 -#define avs_is_yv24(vi) 0 -#define avs_is_yv16(vi) 0 -#define avs_is_yv411(vi) 0 -#define avs_is_y8(vi) 0 -#endif - -typedef struct { +typedef struct AviSynthLibrary { void *library; -#define AVSC_DECLARE_FUNC(name) name##_func name +#define AVSC_DECLARE_FUNC(name) name ## _func name + AVSC_DECLARE_FUNC(avs_bit_blt); + AVSC_DECLARE_FUNC(avs_clip_get_error); AVSC_DECLARE_FUNC(avs_create_script_environment); AVSC_DECLARE_FUNC(avs_delete_script_environment); + AVSC_DECLARE_FUNC(avs_get_audio); AVSC_DECLARE_FUNC(avs_get_error); - AVSC_DECLARE_FUNC(avs_clip_get_error); - AVSC_DECLARE_FUNC(avs_invoke); - AVSC_DECLARE_FUNC(avs_release_value); + AVSC_DECLARE_FUNC(avs_get_frame); + AVSC_DECLARE_FUNC(avs_get_version); AVSC_DECLARE_FUNC(avs_get_video_info); - AVSC_DECLARE_FUNC(avs_take_clip); + AVSC_DECLARE_FUNC(avs_invoke); AVSC_DECLARE_FUNC(avs_release_clip); - AVSC_DECLARE_FUNC(avs_bit_blt); - AVSC_DECLARE_FUNC(avs_get_audio); - AVSC_DECLARE_FUNC(avs_get_frame); + AVSC_DECLARE_FUNC(avs_release_value); AVSC_DECLARE_FUNC(avs_release_video_frame); + AVSC_DECLARE_FUNC(avs_take_clip); #undef AVSC_DECLARE_FUNC } AviSynthLibrary; -struct AviSynthContext { +typedef struct AviSynthContext { AVS_ScriptEnvironment *env; AVS_Clip *clip; const AVS_VideoInfo *vi; - // avisynth_read_packet_video() iterates over this. + /* avisynth_read_packet_video() iterates over this. */ int n_planes; const int *planes; @@ -93,103 +83,96 @@ struct AviSynthContext { int error; - // Linked list pointers. + /* Linked list pointers. */ struct AviSynthContext *next; -}; -typedef struct AviSynthContext AviSynthContext; +} AviSynthContext; -static const int avs_planes_packed[1] = {0}; -static const int avs_planes_grey[1] = {AVS_PLANAR_Y}; -static const int avs_planes_yuv[3] = {AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V}; +static const int avs_planes_packed[1] = { 0 }; +static const int avs_planes_grey[1] = { AVS_PLANAR_Y }; +static const int avs_planes_yuv[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, + AVS_PLANAR_V }; -// A conflict between C++ global objects, atexit, and dynamic loading requires -// us to register our own atexit handler to prevent double freeing. -static AviSynthLibrary *avs_library = NULL; -static int avs_atexit_called = 0; +/* A conflict between C++ global objects, atexit, and dynamic loading requires + * us to register our own atexit handler to prevent double freeing. */ +static AviSynthLibrary avs_library; +static int avs_atexit_called = 0; -// Linked list of AviSynthContexts. An atexit handler destroys this list. +/* Linked list of AviSynthContexts. An atexit handler destroys this list. */ static AviSynthContext *avs_ctx_list = NULL; static av_cold void avisynth_atexit_handler(void); -static av_cold int avisynth_load_library(void) { - avs_library = av_mallocz(sizeof(AviSynthLibrary)); - if (!avs_library) +static av_cold int avisynth_load_library(void) +{ + avs_library.library = LoadLibrary(AVISYNTH_LIB); + if (!avs_library.library) return AVERROR_UNKNOWN; - avs_library->library = LoadLibrary(AVISYNTH_LIB); - if (!avs_library->library) - goto init_fail; +#define LOAD_AVS_FUNC(name, continue_on_fail) \ + avs_library.name = \ + (void *)GetProcAddress(avs_library.library, #name); \ + if (!continue_on_fail && !avs_library.name) \ + goto fail; -#define LOAD_AVS_FUNC(name, continue_on_fail) \ -{ \ - avs_library->name = (void*)GetProcAddress(avs_library->library, #name); \ - if(!continue_on_fail && !avs_library->name) \ - goto fail; \ -} + LOAD_AVS_FUNC(avs_bit_blt, 0); + LOAD_AVS_FUNC(avs_clip_get_error, 0); LOAD_AVS_FUNC(avs_create_script_environment, 0); LOAD_AVS_FUNC(avs_delete_script_environment, 0); + LOAD_AVS_FUNC(avs_get_audio, 0); LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6 - LOAD_AVS_FUNC(avs_clip_get_error, 0); - LOAD_AVS_FUNC(avs_invoke, 0); - LOAD_AVS_FUNC(avs_release_value, 0); + LOAD_AVS_FUNC(avs_get_frame, 0); + LOAD_AVS_FUNC(avs_get_version, 0); LOAD_AVS_FUNC(avs_get_video_info, 0); - LOAD_AVS_FUNC(avs_take_clip, 0); + LOAD_AVS_FUNC(avs_invoke, 0); LOAD_AVS_FUNC(avs_release_clip, 0); - LOAD_AVS_FUNC(avs_bit_blt, 0); - LOAD_AVS_FUNC(avs_get_audio, 0); - LOAD_AVS_FUNC(avs_get_frame, 0); + LOAD_AVS_FUNC(avs_release_value, 0); LOAD_AVS_FUNC(avs_release_video_frame, 0); + LOAD_AVS_FUNC(avs_take_clip, 0); #undef LOAD_AVS_FUNC atexit(avisynth_atexit_handler); return 0; fail: - FreeLibrary(avs_library->library); -init_fail: - av_freep(&avs_library); + FreeLibrary(avs_library.library); return AVERROR_UNKNOWN; } -// Note that avisynth_context_create and avisynth_context_destroy -// do not allocate or free the actual context! That is taken care of -// by libavformat. -static av_cold int avisynth_context_create(AVFormatContext *s) { - AviSynthContext *avs = (AviSynthContext *)s->priv_data; +/* Note that avisynth_context_create and avisynth_context_destroy + * do not allocate or free the actual context! That is taken care of + * by libavformat. */ +static av_cold int avisynth_context_create(AVFormatContext *s) +{ + AviSynthContext *avs = s->priv_data; int ret; - if (!avs_library) { + if (!avs_library.library) if (ret = avisynth_load_library()) return ret; - } - if (!avs) - return AVERROR_UNKNOWN; + avs->env = avs_library.avs_create_script_environment(3); + if (avs_library.avs_get_error) { + const char *error = avs_library.avs_get_error(avs->env); + if (error) { + av_log(s, AV_LOG_ERROR, "%s\n", error); + return AVERROR_UNKNOWN; + } + } if (!avs_ctx_list) { avs_ctx_list = avs; } else { - avs->next = avs_ctx_list; + avs->next = avs_ctx_list; avs_ctx_list = avs; } - avs->env = avs_library->avs_create_script_environment(3); - if (avs_library->avs_get_error) { - const char *error = avs_library->avs_get_error(avs->env); - if (error) { - av_log(s, AV_LOG_ERROR, "%s\n", error); - av_free(avs); - return AVERROR_UNKNOWN; - } - } - return 0; } -static av_cold void avisynth_context_destroy(AviSynthContext *avs) { +static av_cold void avisynth_context_destroy(AviSynthContext *avs) +{ if (avs_atexit_called) - return; + return; if (avs == avs_ctx_list) { avs_ctx_list = avs->next; @@ -201,16 +184,17 @@ static av_cold void avisynth_context_destroy(AviSynthContext *avs) { } if (avs->clip) { - avs_library->avs_release_clip(avs->clip); + avs_library.avs_release_clip(avs->clip); avs->clip = NULL; } if (avs->env) { - avs_library->avs_delete_script_environment(avs->env); + avs_library.avs_delete_script_environment(avs->env); avs->env = NULL; } } -static av_cold void avisynth_atexit_handler(void) { +static av_cold void avisynth_atexit_handler(void) +{ AviSynthContext *avs = avs_ctx_list; while (avs) { @@ -218,66 +202,69 @@ static av_cold void avisynth_atexit_handler(void) { avisynth_context_destroy(avs); avs = next; } - FreeLibrary(avs_library->library); - av_freep(&avs_library); + FreeLibrary(avs_library.library); avs_atexit_called = 1; } -// Create AVStream from audio and video data. -static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) { +/* Create AVStream from audio and video data. */ +static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) +{ AviSynthContext *avs = s->priv_data; int planar = 0; // 0: packed, 1: YUV, 2: Y8 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = CODEC_ID_RAWVIDEO; - st->codec->width = avs->vi->width; - st->codec->height = avs->vi->height; - - st->time_base = (AVRational) {avs->vi->fps_denominator, avs->vi->fps_numerator}; - st->avg_frame_rate = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator}; - st->start_time = 0; - st->duration = avs->vi->num_frames; - st->nb_frames = avs->vi->num_frames; + st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + st->codec->width = avs->vi->width; + st->codec->height = avs->vi->height; + + st->time_base = (AVRational) { avs->vi->fps_denominator, + avs->vi->fps_numerator }; + st->avg_frame_rate = (AVRational) { avs->vi->fps_numerator, + avs->vi->fps_denominator }; + st->start_time = 0; + st->duration = avs->vi->num_frames; + st->nb_frames = avs->vi->num_frames; switch (avs->vi->pixel_type) { -#ifdef _WIN32 +#ifdef USING_AVISYNTH case AVS_CS_YV24: - st->codec->pix_fmt = PIX_FMT_YUV444P; - planar = 1; + st->codec->pix_fmt = AV_PIX_FMT_YUV444P; + planar = 1; break; case AVS_CS_YV16: - st->codec->pix_fmt = PIX_FMT_YUV422P; - planar = 1; + st->codec->pix_fmt = AV_PIX_FMT_YUV422P; + planar = 1; break; case AVS_CS_YV411: - st->codec->pix_fmt = PIX_FMT_YUV411P; - planar = 1; + st->codec->pix_fmt = AV_PIX_FMT_YUV411P; + planar = 1; break; case AVS_CS_Y8: - st->codec->pix_fmt = PIX_FMT_GRAY8; - planar = 2; + st->codec->pix_fmt = AV_PIX_FMT_GRAY8; + planar = 2; break; #endif case AVS_CS_BGR24: - st->codec->pix_fmt = PIX_FMT_RGB24; + st->codec->pix_fmt = AV_PIX_FMT_BGR24; break; case AVS_CS_BGR32: - st->codec->pix_fmt = PIX_FMT_RGB32; + st->codec->pix_fmt = AV_PIX_FMT_RGB32; break; case AVS_CS_YUY2: - st->codec->pix_fmt = PIX_FMT_YUYV422; + st->codec->pix_fmt = AV_PIX_FMT_YUYV422; break; case AVS_CS_YV12: - st->codec->pix_fmt = PIX_FMT_YUV420P; - planar = 1; + st->codec->pix_fmt = AV_PIX_FMT_YUV420P; + planar = 1; break; case AVS_CS_I420: // Is this even used anywhere? - st->codec->pix_fmt = PIX_FMT_YUV420P; - planar = 1; + st->codec->pix_fmt = AV_PIX_FMT_YUV420P; + planar = 1; break; default: - av_log(s, AV_LOG_ERROR, "unknown AviSynth colorspace %d\n", avs->vi->pixel_type); + av_log(s, AV_LOG_ERROR, + "unknown AviSynth colorspace %d\n", avs->vi->pixel_type); avs->error = 1; return AVERROR_UNKNOWN; } @@ -285,52 +272,56 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) { switch (planar) { case 2: // Y8 avs->n_planes = 1; - avs->planes = avs_planes_grey; + avs->planes = avs_planes_grey; break; case 1: // YUV avs->n_planes = 3; - avs->planes = avs_planes_yuv; + avs->planes = avs_planes_yuv; break; default: avs->n_planes = 1; - avs->planes = avs_planes_packed; + avs->planes = avs_planes_packed; } return 0; } -static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) { +static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) +{ AviSynthContext *avs = s->priv_data; - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->sample_rate = avs->vi->audio_samples_per_second; - st->codec->channels = avs->vi->nchannels; - st->time_base = (AVRational) {1, avs->vi->audio_samples_per_second}; + st->codec->channels = avs->vi->nchannels; + st->time_base = (AVRational) { 1, + avs->vi->audio_samples_per_second }; switch (avs->vi->sample_type) { case AVS_SAMPLE_INT8: - st->codec->codec_id = CODEC_ID_PCM_U8; + st->codec->codec_id = AV_CODEC_ID_PCM_U8; break; case AVS_SAMPLE_INT16: - st->codec->codec_id = CODEC_ID_PCM_S16LE; + st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; break; case AVS_SAMPLE_INT24: - st->codec->codec_id = CODEC_ID_PCM_S24LE; + st->codec->codec_id = AV_CODEC_ID_PCM_S24LE; break; case AVS_SAMPLE_INT32: - st->codec->codec_id = CODEC_ID_PCM_S32LE; + st->codec->codec_id = AV_CODEC_ID_PCM_S32LE; break; case AVS_SAMPLE_FLOAT: - st->codec->codec_id = CODEC_ID_PCM_F32LE; + st->codec->codec_id = AV_CODEC_ID_PCM_F32LE; break; default: - av_log(s, AV_LOG_ERROR, "unknown AviSynth sample type %d\n", avs->vi->sample_type); + av_log(s, AV_LOG_ERROR, + "unknown AviSynth sample type %d\n", avs->vi->sample_type); avs->error = 1; return AVERROR_UNKNOWN; } return 0; } -static int avisynth_create_stream(AVFormatContext *s) { +static int avisynth_create_stream(AVFormatContext *s) +{ AviSynthContext *avs = s->priv_data; AVStream *st; int ret; @@ -355,32 +346,45 @@ static int avisynth_create_stream(AVFormatContext *s) { return 0; } -static int avisynth_open_file(AVFormatContext *s) { - AviSynthContext *avs = (AviSynthContext *)s->priv_data; +static int avisynth_open_file(AVFormatContext *s) +{ + AviSynthContext *avs = s->priv_data; AVS_Value arg, val; int ret; +#ifdef USING_AVISYNTH + char filename_ansi[MAX_PATH * 4]; + wchar_t filename_wc[MAX_PATH * 4]; +#endif if (ret = avisynth_context_create(s)) return ret; +#ifdef USING_AVISYNTH + /* Convert UTF-8 to ANSI code page */ + MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4); + WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi, + MAX_PATH * 4, NULL, NULL); + arg = avs_new_value_string(filename_ansi); +#else arg = avs_new_value_string(s->filename); - val = avs_library->avs_invoke(avs->env, "Import", arg, 0); +#endif + val = avs_library.avs_invoke(avs->env, "Import", arg, 0); if (avs_is_error(val)) { av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val)); ret = AVERROR_UNKNOWN; goto fail; } if (!avs_is_clip(val)) { - av_log(s, AV_LOG_ERROR, "%s\n", "AviSynth script did not return a clip"); + av_log(s, AV_LOG_ERROR, "AviSynth script did not return a clip\n"); ret = AVERROR_UNKNOWN; goto fail; } - avs->clip = avs_library->avs_take_clip(val, avs->env); - avs->vi = avs_library->avs_get_video_info(avs->clip); + avs->clip = avs_library.avs_take_clip(val, avs->env); + avs->vi = avs_library.avs_get_video_info(avs->clip); - // Release the AVS_Value as it will go out of scope. - avs_library->avs_release_value(val); + /* Release the AVS_Value as it will go out of scope. */ + avs_library.avs_release_value(val); if (ret = avisynth_create_stream(s)) goto fail; @@ -392,7 +396,9 @@ fail: return ret; } -static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pkt, int *discard) { +static void avisynth_next_stream(AVFormatContext *s, AVStream **st, + AVPacket *pkt, int *discard) +{ AviSynthContext *avs = s->priv_data; pkt->stream_index = avs->curr_stream++; @@ -407,50 +413,59 @@ static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pk return; } -// Copy AviSynth clip data into an AVPacket. -static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, int discard) { +/* Copy AviSynth clip data into an AVPacket. */ +static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, + int discard) +{ AviSynthContext *avs = s->priv_data; AVS_VideoFrame *frame; - unsigned char* dst_p; - const unsigned char* src_p; - int i, plane, rowsize, planeheight, pitch, bits; - const char* error; + unsigned char *dst_p; + const unsigned char *src_p; + int n, i, plane, rowsize, planeheight, pitch, bits; + const char *error; if (avs->curr_frame >= avs->vi->num_frames) return AVERROR_EOF; - // This must happen even if the stream is discarded to prevent desync. - avs->curr_frame++; + /* This must happen even if the stream is discarded to prevent desync. */ + n = avs->curr_frame++; if (discard) return 0; - pkt->pts = avs->curr_frame; - pkt->dts = avs->curr_frame; + pkt->pts = n; + pkt->dts = n; pkt->duration = 1; - // Define the bpp values for the new AviSynth 2.6 colorspaces - if (avs_is_yv24(avs->vi)) { +#ifdef USING_AVISYNTH + /* Define the bpp values for the new AviSynth 2.6 colorspaces. + * Since AvxSynth doesn't have these functions, special-case + * it in order to avoid implicit declaration errors. */ + + if (avs_is_yv24(avs->vi)) bits = 24; - } else if (avs_is_yv16(avs->vi)) { + else if (avs_is_yv16(avs->vi)) bits = 16; - } else if (avs_is_yv411(avs->vi)) { + else if (avs_is_yv411(avs->vi)) bits = 12; - } else if (avs_is_y8(avs->vi)) { + else if (avs_is_y8(avs->vi)) bits = 8; - } else { + else +#endif bits = avs_bits_per_pixel(avs->vi); - } - // Without cast to int64_t, calculation overflows at about 9k x 9k resolution. - pkt->size = (((int64_t)avs->vi->width * (int64_t)avs->vi->height) * bits) / 8; + /* Without the cast to int64_t, calculation overflows at about 9k x 9k + * resolution. */ + pkt->size = (((int64_t)avs->vi->width * + (int64_t)avs->vi->height) * bits) / 8; if (!pkt->size) return AVERROR_UNKNOWN; - pkt->data = av_malloc(pkt->size); - if (!pkt->data) - return AVERROR_UNKNOWN; + if (av_new_packet(pkt, (int)pkt->size) < 0) { + av_free(pkt); + return AVERROR(ENOMEM); + } - frame = avs_library->avs_get_frame(avs->clip, avs->curr_frame); - error = avs_library->avs_clip_get_error(avs->clip); + frame = avs_library.avs_get_frame(avs->clip, n); + error = avs_library.avs_clip_get_error(avs->clip); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); avs->error = 1; @@ -462,48 +477,64 @@ static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, int dis for (i = 0; i < avs->n_planes; i++) { plane = avs->planes[i]; src_p = avs_get_read_ptr_p(frame, plane); - rowsize = avs_get_row_size_p(frame, plane); - planeheight = avs_get_height_p(frame, plane); pitch = avs_get_pitch_p(frame, plane); - // Flip RGB video. +#ifdef USING_AVISYNTH + if (avs_library.avs_get_version(avs->clip) == 3) { + rowsize = avs_get_row_size_p_25(frame, plane); + planeheight = avs_get_height_p_25(frame, plane); + } else { + rowsize = avs_get_row_size_p(frame, plane); + planeheight = avs_get_height_p(frame, plane); + } +#else + rowsize = avs_get_row_size_p(frame, plane); + planeheight = avs_get_height_p(frame, plane); +#endif + + /* Flip RGB video. */ if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) { src_p = src_p + (planeheight - 1) * pitch; pitch = -pitch; } - avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, rowsize, planeheight); + avs_library.avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, + rowsize, planeheight); dst_p += rowsize * planeheight; } - avs_library->avs_release_video_frame(frame); + avs_library.avs_release_video_frame(frame); return 0; } -static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int discard) { +static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, + int discard) +{ AviSynthContext *avs = s->priv_data; AVRational fps, samplerate; int samples; - const char* error; + int64_t n; + const char *error; if (avs->curr_sample >= avs->vi->num_audio_samples) return AVERROR_EOF; - fps.num = avs->vi->fps_numerator; - fps.den = avs->vi->fps_denominator; + fps.num = avs->vi->fps_numerator; + fps.den = avs->vi->fps_denominator; samplerate.num = avs->vi->audio_samples_per_second; samplerate.den = 1; if (avs_has_video(avs->vi)) { if (avs->curr_frame < avs->vi->num_frames) - samples = av_rescale_q(avs->curr_frame, samplerate, fps) - avs->curr_sample; + samples = av_rescale_q(avs->curr_frame, samplerate, fps) - + avs->curr_sample; else samples = av_rescale_q(1, samplerate, fps); } else { samples = 1000; } - // After seeking, audio may catch up with video. + /* After seeking, audio may catch up with video. */ if (samples <= 0) { pkt->size = 0; pkt->data = NULL; @@ -513,24 +544,26 @@ static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int dis if (avs->curr_sample + samples > avs->vi->num_audio_samples) samples = avs->vi->num_audio_samples - avs->curr_sample; - // This must happen even if the stream is discarded to prevent desync. + /* This must happen even if the stream is discarded to prevent desync. */ + n = avs->curr_sample; avs->curr_sample += samples; if (discard) return 0; - pkt->pts = avs->curr_sample; - pkt->dts = avs->curr_sample; + pkt->pts = n; + pkt->dts = n; pkt->duration = samples; - pkt->size = avs_bytes_per_channel_sample(avs->vi) * samples * avs->vi->nchannels; + pkt->size = avs_bytes_per_channel_sample(avs->vi) * + samples * avs->vi->nchannels; if (!pkt->size) return AVERROR_UNKNOWN; pkt->data = av_malloc(pkt->size); if (!pkt->data) - return AVERROR_UNKNOWN; + return AVERROR(ENOMEM); - avs_library->avs_get_audio(avs->clip, pkt->data, avs->curr_sample, samples); - error = avs_library->avs_clip_get_error(avs->clip); + avs_library.avs_get_audio(avs->clip, pkt->data, n, samples); + error = avs_library.avs_clip_get_error(avs->clip); if (error) { av_log(s, AV_LOG_ERROR, "%s\n", error); avs->error = 1; @@ -540,7 +573,8 @@ static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int dis return 0; } -static av_cold int avisynth_read_header(AVFormatContext *s) { +static av_cold int avisynth_read_header(AVFormatContext *s) +{ int ret; // Calling library must implement a lock for thread-safe opens. @@ -556,7 +590,8 @@ static av_cold int avisynth_read_header(AVFormatContext *s) { return 0; } -static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) { +static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) +{ AviSynthContext *avs = s->priv_data; AVStream *st; int discard = 0; @@ -565,9 +600,10 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) { if (avs->error) return AVERROR_UNKNOWN; - pkt->destruct = av_destruct_packet; + av_free_packet(pkt); - // If either stream reaches EOF, try to read the other one before giving up. + /* If either stream reaches EOF, try to read the other one before + * giving up. */ avisynth_next_stream(s, &st, pkt, &discard); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { ret = avisynth_read_packet_video(s, pkt, discard); @@ -575,18 +611,19 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) { avisynth_next_stream(s, &st, pkt, &discard); return avisynth_read_packet_audio(s, pkt, discard); } - return ret; } else { ret = avisynth_read_packet_audio(s, pkt, discard); if (ret == AVERROR_EOF && avs_has_video(avs->vi)) { avisynth_next_stream(s, &st, pkt, &discard); return avisynth_read_packet_video(s, pkt, discard); } - return ret; } + + return ret; } -static av_cold int avisynth_read_close(AVFormatContext *s) { +static av_cold int avisynth_read_close(AVFormatContext *s) +{ if (avpriv_lock_avformat()) return AVERROR_UNKNOWN; @@ -595,7 +632,9 @@ static av_cold int avisynth_read_close(AVFormatContext *s) { return 0; } -static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { +static int avisynth_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) +{ AviSynthContext *avs = s->priv_data; AVStream *st; AVRational fps, samplerate; @@ -603,13 +642,16 @@ static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t time if (avs->error) return AVERROR_UNKNOWN; - fps = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator}; - samplerate = (AVRational) {avs->vi->audio_samples_per_second, 1}; + fps = (AVRational) { avs->vi->fps_numerator, + avs->vi->fps_denominator }; + samplerate = (AVRational) { avs->vi->audio_samples_per_second, 1 }; st = s->streams[stream_index]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - // AviSynth frame counts are signed int. - if ((timestamp >= avs->vi->num_frames) || (timestamp > INT_MAX) || (timestamp < 0)) + /* AviSynth frame counts are signed int. */ + if ((timestamp >= avs->vi->num_frames) || + (timestamp > INT_MAX) || + (timestamp < 0)) return AVERROR_EOF; avs->curr_frame = timestamp; if (avs_has_audio(avs->vi)) @@ -617,9 +659,9 @@ static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t time } else { if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0)) return AVERROR_EOF; - // Force frame granularity for seeking. + /* Force frame granularity for seeking. */ if (avs_has_video(avs->vi)) { - avs->curr_frame = av_rescale_q(timestamp, fps, samplerate); + avs->curr_frame = av_rescale_q(timestamp, fps, samplerate); avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps); } else { avs->curr_sample = timestamp; diff --git a/ffmpeg/libavformat/avr.c b/ffmpeg/libavformat/avr.c index 473136e..a33134e 100644 --- a/ffmpeg/libavformat/avr.c +++ b/ffmpeg/libavformat/avr.c @@ -26,9 +26,15 @@ static int avr_probe(AVProbeData *p) { - if (AV_RL32(p->buf) == MKTAG('2', 'B', 'I', 'T')) - return AVPROBE_SCORE_MAX / 2; - return 0; + if (AV_RL32(p->buf) != MKTAG('2', 'B', 'I', 'T')) + return 0; + + if (!AV_RB16(p->buf+12) || AV_RB16(p->buf+12) > 256) // channels + return AVPROBE_SCORE_EXTENSION/2; + if (AV_RB16(p->buf+14) > 256) // bps + return AVPROBE_SCORE_EXTENSION/2; + + return AVPROBE_SCORE_EXTENSION; } static int avr_read_header(AVFormatContext *s) @@ -69,16 +75,9 @@ static int avr_read_header(AVFormatContext *s) avio_skip(s->pb, 20); avio_skip(s->pb, 64); - if (!sign && bps == 8) { - st->codec->codec_id = AV_CODEC_ID_PCM_U8; - } else if (!sign && bps == 16) { - st->codec->codec_id = AV_CODEC_ID_PCM_U16BE; - } else if (sign == 0xFFFFu && bps == 8) { - st->codec->codec_id = AV_CODEC_ID_PCM_S8; - } else if (sign == 0xFFFFu && bps == 16) { - st->codec->codec_id = AV_CODEC_ID_PCM_S16BE; - } else { - avpriv_request_sample(s, "bits per sample %d", bps); + st->codec->codec_id = ff_get_pcm_codec_id(bps, 0, 1, sign); + if (st->codec->codec_id == AV_CODEC_ID_NONE) { + avpriv_request_sample(s, "Bps %d and sign %d", bps, sign); return AVERROR_PATCHWELCOME; } diff --git a/ffmpeg/libavformat/avs.c b/ffmpeg/libavformat/avs.c index ec9198b..7814301 100644 --- a/ffmpeg/libavformat/avs.c +++ b/ffmpeg/libavformat/avs.c @@ -50,7 +50,9 @@ static int avs_probe(AVProbeData * p) d = p->buf; if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0) - return 55; + /* Ensure the buffer probe scores higher than the extension probe. + * This avoids problems with misdetection as AviSynth scripts. */ + return AVPROBE_SCORE_EXTENSION + 5; return 0; } diff --git a/ffmpeg/libavformat/bethsoftvid.c b/ffmpeg/libavformat/bethsoftvid.c index b8f08c1..6b84b79 100644 --- a/ffmpeg/libavformat/bethsoftvid.c +++ b/ffmpeg/libavformat/bethsoftvid.c @@ -61,6 +61,9 @@ static int vid_probe(AVProbeData *p) if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0)) return 0; + if (p->buf[4] != 2) + return AVPROBE_SCORE_MAX / 4; + return AVPROBE_SCORE_MAX; } diff --git a/ffmpeg/libavformat/bfi.c b/ffmpeg/libavformat/bfi.c index a28e09a..b65a582 100644 --- a/ffmpeg/libavformat/bfi.c +++ b/ffmpeg/libavformat/bfi.c @@ -81,6 +81,8 @@ static int bfi_read_header(AVFormatContext * s) /*Load the palette to extradata */ avio_skip(pb, 8); vstream->codec->extradata = av_malloc(768); + if (!vstream->codec->extradata) + return AVERROR(ENOMEM); vstream->codec->extradata_size = 768; avio_read(pb, vstream->codec->extradata, vstream->codec->extradata_size); @@ -134,6 +136,10 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt) video_offset = avio_rl32(pb); audio_size = video_offset - audio_offset; bfi->video_size = chunk_size - video_offset; + if (audio_size < 0 || bfi->video_size < 0) { + av_log(s, AV_LOG_ERROR, "Invalid audio/video offsets or chunk size\n"); + return AVERROR_INVALIDDATA; + } //Tossing an audio packet at the audio decoder. ret = av_get_packet(pb, pkt, audio_size); @@ -142,9 +148,7 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt) pkt->pts = bfi->audio_frame; bfi->audio_frame += ret; - } - - else { + } else if (bfi->video_size > 0) { //Tossing a video packet at the video decoder. ret = av_get_packet(pb, pkt, bfi->video_size); @@ -152,10 +156,13 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt) return ret; pkt->pts = bfi->video_frame; - bfi->video_frame += bfi->video_size ? ret / bfi->video_size : 1; + bfi->video_frame += ret / bfi->video_size; /* One less frame to read. A cursory decrement. */ bfi->nframes--; + } else { + /* Empty video packet */ + ret = AVERROR(EAGAIN); } bfi->avflag = !bfi->avflag; diff --git a/ffmpeg/libavformat/bink.c b/ffmpeg/libavformat/bink.c index 887f70a..95b615a 100644 --- a/ffmpeg/libavformat/bink.c +++ b/ffmpeg/libavformat/bink.c @@ -116,11 +116,8 @@ static int read_header(AVFormatContext *s) vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_id = AV_CODEC_ID_BINKVIDEO; - vst->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!vst->codec->extradata) + if (ff_get_extradata(vst->codec, pb, 4) < 0) return AVERROR(ENOMEM); - vst->codec->extradata_size = 4; - avio_read(pb, vst->codec->extradata, 4); bink->num_audio_tracks = avio_rl32(pb); @@ -152,10 +149,8 @@ static int read_header(AVFormatContext *s) ast->codec->channels = 1; ast->codec->channel_layout = AV_CH_LAYOUT_MONO; } - ast->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!ast->codec->extradata) + if (ff_alloc_extradata(ast->codec, 4)) return AVERROR(ENOMEM); - ast->codec->extradata_size = 4; AV_WL32(ast->codec->extradata, vst->codec->codec_tag); } diff --git a/ffmpeg/libavformat/bintext.c b/ffmpeg/libavformat/bintext.c index 91f95f3..d50a8d9 100644 --- a/ffmpeg/libavformat/bintext.c +++ b/ffmpeg/libavformat/bintext.c @@ -43,8 +43,8 @@ typedef struct { int chars_per_frame; /**< characters to send decoder per frame; set by private options as characters per second, and then converted to characters per frame at runtime */ - char *video_size; /**< video size (WxH pixels) (private option) */ - char *framerate; /**< frames per second (private option) */ + int width, height; /**< video size (WxH pixels) (private option) */ + AVRational framerate; /**< frames per second (private option) */ uint64_t fsize; /**< file size less metadata buffer */ } BinDemuxContext; @@ -57,29 +57,15 @@ static AVStream * init_stream(AVFormatContext *s) st->codec->codec_tag = 0; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - if (bin->video_size) { - if (av_parse_video_size(&st->codec->width, &st->codec->height, bin->video_size) < 0) { - av_log(s, AV_LOG_ERROR, "Could not parse video size: '%s'\n", bin->video_size); - return NULL; - } - } else { + if (!bin->width) { st->codec->width = (80<<3); st->codec->height = (25<<4); } - if (bin->framerate) { - AVRational framerate; - if (av_parse_video_rate(&framerate, bin->framerate) < 0) { - av_log(s, AV_LOG_ERROR, "Could not parse framerate: '%s'\n", bin->framerate); - return NULL; - } - avpriv_set_pts_info(st, 60, framerate.den, framerate.num); - } else { - avpriv_set_pts_info(st, 60, 1, 25); - } + avpriv_set_pts_info(st, 60, bin->framerate.den, bin->framerate.num); /* simulate tty display speed */ - bin->chars_per_frame = FFMAX(av_q2d(st->time_base) * bin->chars_per_frame, 1); + bin->chars_per_frame = av_clip(av_q2d(st->time_base) * bin->chars_per_frame, 1, INT_MAX); return st; } @@ -150,9 +136,7 @@ static int bintext_read_header(AVFormatContext *s) return AVERROR(ENOMEM); st->codec->codec_id = AV_CODEC_ID_BINTEXT; - st->codec->extradata_size = 2; - st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, 2)) return AVERROR(ENOMEM); st->codec->extradata[0] = 16; st->codec->extradata[1] = 0; @@ -162,7 +146,7 @@ static int bintext_read_header(AVFormatContext *s) bin->fsize = avio_size(pb); if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0) next_tag_read(s, &bin->fsize); - if (!bin->video_size) { + if (!bin->width) { predict_width(st->codec, bin->fsize, got_width); calculate_height(st->codec, bin->fsize); } @@ -208,8 +192,7 @@ static int xbin_read_header(AVFormatContext *s) st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256); st->codec->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT; - st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, st->codec->extradata_size)) return AVERROR(ENOMEM); st->codec->extradata[0] = fontheight; st->codec->extradata[1] = flags; @@ -241,9 +224,7 @@ static int adf_read_header(AVFormatContext *s) return AVERROR(ENOMEM); st->codec->codec_id = AV_CODEC_ID_BINTEXT; - st->codec->extradata_size = 2 + 48 + 4096; - st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, 2 + 48 + 4096)) return AVERROR(ENOMEM); st->codec->extradata[0] = 16; st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT; @@ -261,7 +242,7 @@ static int adf_read_header(AVFormatContext *s) bin->fsize = avio_size(pb) - 1 - 192 - 4096; st->codec->width = 80<<3; ff_sauce_read(s, &bin->fsize, &got_width, 0); - if (!bin->video_size) + if (!bin->width) calculate_height(st->codec, bin->fsize); avio_seek(pb, 1 + 192 + 4096, SEEK_SET); } @@ -298,9 +279,7 @@ static int idf_read_header(AVFormatContext *s) return AVERROR(ENOMEM); st->codec->codec_id = AV_CODEC_ID_IDF; - st->codec->extradata_size = 2 + 48 + 4096; - st->codec->extradata = av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, 2 + 48 + 4096)) return AVERROR(ENOMEM); st->codec->extradata[0] = 16; st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT; @@ -314,7 +293,7 @@ static int idf_read_header(AVFormatContext *s) bin->fsize = avio_size(pb) - 12 - 4096 - 48; ff_sauce_read(s, &bin->fsize, &got_width, 0); - if (!bin->video_size) + if (!bin->width) calculate_height(st->codec, bin->fsize); avio_seek(pb, 12, SEEK_SET); return 0; @@ -346,8 +325,8 @@ static int read_packet(AVFormatContext *s, #define OFFSET(x) offsetof(BinDemuxContext, x) static const AVOption options[] = { { "linespeed", "set simulated line speed (bytes per second)", OFFSET(chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM}, - { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, - { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, + { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, + { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, { NULL }, }; diff --git a/ffmpeg/libavformat/bit.c b/ffmpeg/libavformat/bit.c index 9f6ea4a..0be471a 100644 --- a/ffmpeg/libavformat/bit.c +++ b/ffmpeg/libavformat/bit.c @@ -44,7 +44,7 @@ static int probe(AVProbeData *p) return 0; i+=j; } - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; } static int read_header(AVFormatContext *s) @@ -139,7 +139,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) init_get_bits(&gb, pkt->data, 8*10); for(i=0; i< 8 * 10; i++) avio_wl16(pb, get_bits1(&gb) ? BIT_1 : BIT_0); - avio_flush(pb); return 0; } diff --git a/ffmpeg/libavformat/bmv.c b/ffmpeg/libavformat/bmv.c index ce157e8..f7a6068 100644 --- a/ffmpeg/libavformat/bmv.c +++ b/ffmpeg/libavformat/bmv.c @@ -2,20 +2,20 @@ * Discworld II BMV demuxer * Copyright (c) 2011 Konstantin Shishkov. * - * 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 */ @@ -71,8 +71,7 @@ static int bmv_read_header(AVFormatContext *s) static int bmv_read_packet(AVFormatContext *s, AVPacket *pkt) { BMVContext *c = s->priv_data; - int type; - void *tmp; + int type, err; while (c->get_next) { if (s->pb->eof_reached) @@ -85,10 +84,8 @@ static int bmv_read_packet(AVFormatContext *s, AVPacket *pkt) c->size = avio_rl24(s->pb); if (!c->size) return AVERROR_INVALIDDATA; - tmp = av_realloc(c->packet, c->size + 1); - if (!tmp) - return AVERROR(ENOMEM); - c->packet = tmp; + if ((err = av_reallocp(&c->packet, c->size + 1)) < 0) + return err; c->packet[0] = type; if (avio_read(s->pb, c->packet + 1, c->size) != c->size) return AVERROR(EIO); diff --git a/ffmpeg/libavformat/cafdec.c b/ffmpeg/libavformat/cafdec.c index 337758e..0b5d59c 100644 --- a/ffmpeg/libavformat/cafdec.c +++ b/ffmpeg/libavformat/cafdec.c @@ -130,8 +130,7 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size) } avio_read(pb, preamble, ALAC_PREAMBLE); - st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, ALAC_HEADER)) return AVERROR(ENOMEM); /* For the old style cookie, we skip 12 bytes, then read 36 bytes. @@ -154,13 +153,9 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size) avio_read(pb, &st->codec->extradata[24], ALAC_NEW_KUKI - 12); avio_skip(pb, size - ALAC_NEW_KUKI); } - st->codec->extradata_size = ALAC_HEADER; } else { - st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, pb, size) < 0) return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, size); - st->codec->extradata_size = size; } return 0; diff --git a/ffmpeg/libavformat/cafenc.c b/ffmpeg/libavformat/cafenc.c index 11bb055..ae36b85 100644 --- a/ffmpeg/libavformat/cafenc.c +++ b/ffmpeg/libavformat/cafenc.c @@ -86,8 +86,9 @@ static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels) { return 1152; case AV_CODEC_ID_AC3: return 1536; - case AV_CODEC_ID_ALAC: case AV_CODEC_ID_QDM2: + return 2048 * channels; + case AV_CODEC_ID_ALAC: return 4096; case AV_CODEC_ID_ADPCM_IMA_WAV: return (1024 - 4 * channels) * 8 / (4 * channels) + 1; @@ -107,6 +108,11 @@ static int caf_write_header(AVFormatContext *s) unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id); int64_t chunk_size = 0; + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "CAF files have exactly one stream\n"); + return AVERROR(EINVAL); + } + switch (enc->codec_id) { case AV_CODEC_ID_AAC: case AV_CODEC_ID_AC3: diff --git a/ffmpeg/libavformat/cavsvideodec.c b/ffmpeg/libavformat/cavsvideodec.c index c035128..5ca3c80 100644 --- a/ffmpeg/libavformat/cavsvideodec.c +++ b/ffmpeg/libavformat/cavsvideodec.c @@ -61,7 +61,7 @@ static int cavsvideo_probe(AVProbeData *p) } } if(seq && seq*9<=pic*10) - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; return 0; } diff --git a/ffmpeg/libavformat/cdxl.c b/ffmpeg/libavformat/cdxl.c index 185b745..ab8a846 100644 --- a/ffmpeg/libavformat/cdxl.c +++ b/ffmpeg/libavformat/cdxl.c @@ -41,7 +41,7 @@ typedef struct CDXLDemuxContext { static int cdxl_read_probe(AVProbeData *p) { - int score = AVPROBE_SCORE_MAX / 2 + 10; + int score = AVPROBE_SCORE_EXTENSION + 10; if (p->buf_size < CDXL_HEADER_SIZE) return 0; diff --git a/ffmpeg/libavformat/concat.c b/ffmpeg/libavformat/concat.c index f97354c..3bbc83d 100644 --- a/ffmpeg/libavformat/concat.c +++ b/ffmpeg/libavformat/concat.c @@ -56,7 +56,7 @@ static av_cold int concat_close(URLContext *h) static av_cold int concat_open(URLContext *h, const char *uri, int flags) { - char *node_uri = NULL, *tmp_uri; + char *node_uri = NULL; int err = 0; int64_t size; size_t len, i; @@ -74,7 +74,7 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags) return AVERROR(ENAMETOOLONG); } - if (!(nodes = av_malloc(sizeof(*nodes) * len))) { + if (!(nodes = av_realloc(NULL, sizeof(*nodes) * len))) { return AVERROR(ENOMEM); } else data->nodes = nodes; @@ -85,11 +85,8 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags) for (i = 0; *uri; i++) { /* parsing uri */ len = strcspn(uri, AV_CAT_SEPARATOR); - if (!(tmp_uri = av_realloc(node_uri, len+1))) { - err = AVERROR(ENOMEM); + if ((err = av_reallocp(&node_uri, len + 1)) < 0) break; - } else - node_uri = tmp_uri; av_strlcpy(node_uri, uri, len+1); uri += len + strspn(uri+len, AV_CAT_SEPARATOR); diff --git a/ffmpeg/libavformat/concatdec.c b/ffmpeg/libavformat/concatdec.c index 5359ad1..86f82e0 100644 --- a/ffmpeg/libavformat/concatdec.c +++ b/ffmpeg/libavformat/concatdec.c @@ -23,6 +23,7 @@ #include "libavutil/parseutils.h" #include "avformat.h" #include "internal.h" +#include "url.h" typedef struct { char *url; @@ -216,6 +217,8 @@ static int concat_read_header(AVFormatContext *avf) } if (ret < 0) FAIL(ret); + if (!cat->nb_files) + FAIL(AVERROR_INVALIDDATA); for (i = 0; i < cat->nb_files; i++) { if (cat->files[i].start_time == AV_NOPTS_VALUE) @@ -276,6 +279,9 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) (ret = open_next_file(avf)) < 0) break; } + if (ret < 0) + return ret; + delta = av_rescale_q(cat->cur_file->start_time - cat->avf->start_time, AV_TIME_BASE_Q, cat->avf->streams[pkt->stream_index]->time_base); @@ -341,7 +347,7 @@ static int real_seek(AVFormatContext *avf, int stream, return ret; ret = try_seek(avf, stream, min_ts, ts, max_ts, flags); - if (ret < 0 && !(flags & AVSEEK_FLAG_BACKWARD) && + if (ret < 0 && left < cat->nb_files - 1 && cat->files[left + 1].start_time < max_ts) { if ((ret = open_file(avf, left + 1)) < 0) diff --git a/ffmpeg/libavformat/crypto.c b/ffmpeg/libavformat/crypto.c index 5d518be..a9b6e47 100644 --- a/ffmpeg/libavformat/crypto.c +++ b/ffmpeg/libavformat/crypto.c @@ -2,20 +2,20 @@ * Decryption protocol handler * Copyright (c) 2011 Martin Storsjo * - * 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 */ diff --git a/ffmpeg/libavformat/daud.c b/ffmpeg/libavformat/daud.c index fb62ab1..6983785 100644 --- a/ffmpeg/libavformat/daud.c +++ b/ffmpeg/libavformat/daud.c @@ -68,7 +68,6 @@ static int daud_write_packet(struct AVFormatContext *s, AVPacket *pkt) avio_wb16(s->pb, pkt->size); avio_wb16(s->pb, 0x8010); // unknown avio_write(s->pb, pkt->data, pkt->size); - avio_flush(s->pb); return 0; } diff --git a/ffmpeg/libavformat/dfa.c b/ffmpeg/libavformat/dfa.c index 8cf2f24..9cd13e2 100644 --- a/ffmpeg/libavformat/dfa.c +++ b/ffmpeg/libavformat/dfa.c @@ -28,6 +28,9 @@ static int dfa_probe(AVProbeData *p) if (p->buf_size < 4 || AV_RL32(p->buf) != MKTAG('D', 'F', 'I', 'A')) return 0; + if (AV_RL32(p->buf + 16) != 0x80) + return AVPROBE_SCORE_MAX / 4; + return AVPROBE_SCORE_MAX; } @@ -36,13 +39,15 @@ static int dfa_read_header(AVFormatContext *s) AVIOContext *pb = s->pb; AVStream *st; int frames; + int version; uint32_t mspf; if (avio_rl32(pb) != MKTAG('D', 'F', 'I', 'A')) { av_log(s, AV_LOG_ERROR, "Invalid magic for DFA\n"); return AVERROR_INVALIDDATA; } - avio_skip(pb, 2); // unused + + version = avio_rl16(pb); frames = avio_rl16(pb); st = avformat_new_stream(s, NULL); @@ -62,6 +67,12 @@ static int dfa_read_header(AVFormatContext *s) avio_skip(pb, 128 - 16); // padding st->duration = frames; + if (ff_alloc_extradata(st->codec, 2)) + return AVERROR(ENOMEM); + AV_WL16(st->codec->extradata, version); + if (version == 0x100) + st->sample_aspect_ratio = (AVRational){2, 1}; + return 0; } diff --git a/ffmpeg/libavformat/diracdec.c b/ffmpeg/libavformat/diracdec.c index 6636ead..e061ba5 100644 --- a/ffmpeg/libavformat/diracdec.c +++ b/ffmpeg/libavformat/diracdec.c @@ -25,10 +25,19 @@ static int dirac_probe(AVProbeData *p) { - if (AV_RL32(p->buf) == MKTAG('B', 'B', 'C', 'D')) - return AVPROBE_SCORE_MAX; - else + unsigned size; + if (AV_RL32(p->buf) != MKTAG('B', 'B', 'C', 'D')) return 0; + + size = AV_RB32(p->buf+5); + if (size < 13) + return 0; + if (size + 13LL > p->buf_size) + return AVPROBE_SCORE_MAX / 4; + if (AV_RL32(p->buf + size) != MKTAG('B', 'B', 'C', 'D')) + return 0; + + return AVPROBE_SCORE_MAX; } FF_DEF_RAWVIDEO_DEMUXER(dirac, "raw Dirac", dirac_probe, NULL, AV_CODEC_ID_DIRAC) diff --git a/ffmpeg/libavformat/dsicin.c b/ffmpeg/libavformat/dsicin.c index b8ca57c..4a54680 100644 --- a/ffmpeg/libavformat/dsicin.c +++ b/ffmpeg/libavformat/dsicin.c @@ -155,6 +155,8 @@ static int cin_read_frame_header(CinDemuxContext *cin, AVIOContext *pb) { if (avio_rl32(pb) != 0xAA55AA55) return AVERROR_INVALIDDATA; + if (hdr->video_frame_size < 0 || hdr->audio_frame_size < 0) + return AVERROR_INVALIDDATA; return 0; } diff --git a/ffmpeg/libavformat/dtsdec.c b/ffmpeg/libavformat/dtsdec.c index 5c05758..23cbe93 100644 --- a/ffmpeg/libavformat/dtsdec.c +++ b/ffmpeg/libavformat/dtsdec.c @@ -34,6 +34,7 @@ static int dts_probe(AVProbeData *p) uint32_t state = -1; int markers[3] = {0}; int sum, max; + int64_t diff = 0; buf = p->buf; @@ -54,13 +55,17 @@ static int dts_probe(AVProbeData *p) if (state == DCA_MARKER_14B_LE) if ((bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007) markers[2]++; + + if (buf - p->buf >= 4) + diff += FFABS(AV_RL16(buf) - AV_RL16(buf-4)); } sum = markers[0] + markers[1] + markers[2]; max = markers[1] > markers[0]; max = markers[2] > markers[max] ? 2 : max; if (markers[max] > 3 && p->buf_size / markers[max] < 32*1024 && - markers[max] * 4 > sum * 3) - return AVPROBE_SCORE_MAX/2+1; + markers[max] * 4 > sum * 3 && + diff / p->buf_size > 200) + return AVPROBE_SCORE_EXTENSION + 1; return 0; } diff --git a/ffmpeg/libavformat/dv.c b/ffmpeg/libavformat/dv.c index a04735a..f972478 100644 --- a/ffmpeg/libavformat/dv.c +++ b/ffmpeg/libavformat/dv.c @@ -32,7 +32,7 @@ #include "avformat.h" #include "internal.h" #include "libavcodec/dv_profile.h" -#include "libavcodec/dvdata.h" +#include "libavcodec/dv.h" #include "libavutil/channel_layout.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" @@ -65,7 +65,7 @@ static inline uint16_t dv_audio_12to16(uint16_t sample) shift--; result = (sample - (256 * shift)) << shift; } else { - shift = 0xe - shift; + shift = 0xe - shift; result = ((sample + ((256 * shift) + 1)) << shift) - 1; } @@ -77,19 +77,19 @@ static inline uint16_t dv_audio_12to16(uint16_t sample) * a fixed offset and if pack isn't there -- fails. We might want * to have a fallback mechanism for complete search of missing packs. */ -static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t) +static const uint8_t *dv_extract_pack(uint8_t *frame, enum dv_pack_type t) { int offs; switch (t) { case dv_audio_source: - offs = (80*6 + 80*16*3 + 3); + offs = (80 * 6 + 80 * 16 * 3 + 3); break; case dv_audio_control: - offs = (80*6 + 80*16*4 + 3); + offs = (80 * 6 + 80 * 16 * 4 + 3); break; case dv_video_control: - offs = (80*5 + 48 + 5); + offs = (80 * 5 + 48 + 5); break; case dv_timecode: offs = (80*1 + 3 + 3); @@ -113,29 +113,29 @@ static const int dv_audio_frequency[3] = { * 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples * are converted into 16bit linear ones. */ -static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4], +static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm, const DVprofile *sys) { int size, chan, i, j, d, of, smpls, freq, quant, half_ch; uint16_t lc, rc; - const uint8_t* as_pack; + const uint8_t *as_pack; uint8_t *pcm, ipcm; as_pack = dv_extract_pack(frame, dv_audio_source); if (!as_pack) /* No audio ? */ return 0; - smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */ - freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */ - quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ + smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */ + freq = as_pack[4] >> 3 & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */ + quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ if (quant > 1) - return -1; /* unsupported quantization */ + return -1; /* unsupported quantization */ if (freq >= FF_ARRAY_ELEMS(dv_audio_frequency)) return AVERROR_INVALIDDATA; - size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */ + size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */ half_ch = sys->difseg_size / 2; /* We work with 720p frames split in half, thus even frames have @@ -169,32 +169,41 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4], for (j = 0; j < 9; j++) { for (d = 8; d < 80; d += 2) { if (quant == 0) { /* 16bit quantization */ - of = sys->audio_shuffle[i][j] + (d - 8) / 2 * sys->audio_stride; - if (of*2 >= size) + of = sys->audio_shuffle[i][j] + + (d - 8) / 2 * sys->audio_stride; + if (of * 2 >= size) continue; - pcm[of*2] = frame[d+1]; // FIXME: maybe we have to admit - pcm[of*2+1] = frame[d]; // that DV is a big-endian PCM - if (pcm[of*2+1] == 0x80 && pcm[of*2] == 0x00) - pcm[of*2+1] = 0; + /* FIXME: maybe we have to admit that DV is a + * big-endian PCM */ + pcm[of * 2] = frame[d + 1]; + pcm[of * 2 + 1] = frame[d]; + + if (pcm[of * 2 + 1] == 0x80 && pcm[of * 2] == 0x00) + pcm[of * 2 + 1] = 0; } else { /* 12bit quantization */ - lc = ((uint16_t)frame[d] << 4) | - ((uint16_t)frame[d+2] >> 4); - rc = ((uint16_t)frame[d+1] << 4) | - ((uint16_t)frame[d+2] & 0x0f); + lc = ((uint16_t)frame[d] << 4) | + ((uint16_t)frame[d + 2] >> 4); + rc = ((uint16_t)frame[d + 1] << 4) | + ((uint16_t)frame[d + 2] & 0x0f); lc = (lc == 0x800 ? 0 : dv_audio_12to16(lc)); rc = (rc == 0x800 ? 0 : dv_audio_12to16(rc)); - of = sys->audio_shuffle[i%half_ch][j] + (d - 8) / 3 * sys->audio_stride; - if (of*2 >= size) + of = sys->audio_shuffle[i % half_ch][j] + + (d - 8) / 3 * sys->audio_stride; + if (of * 2 >= size) continue; - pcm[of*2] = lc & 0xff; // FIXME: maybe we have to admit - pcm[of*2+1] = lc >> 8; // that DV is a big-endian PCM - of = sys->audio_shuffle[i%half_ch+half_ch][j] + - (d - 8) / 3 * sys->audio_stride; - pcm[of*2] = rc & 0xff; // FIXME: maybe we have to admit - pcm[of*2+1] = rc >> 8; // that DV is a big-endian PCM + /* FIXME: maybe we have to admit that DV is a + * big-endian PCM */ + pcm[of * 2] = lc & 0xff; + pcm[of * 2 + 1] = lc >> 8; + of = sys->audio_shuffle[i % half_ch + half_ch][j] + + (d - 8) / 3 * sys->audio_stride; + /* FIXME: maybe we have to admit that DV is a + * big-endian PCM */ + pcm[of * 2] = rc & 0xff; + pcm[of * 2 + 1] = rc >> 8; ++d; } } @@ -207,9 +216,9 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4], return size; } -static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame) +static int dv_extract_audio_info(DVDemuxContext *c, uint8_t *frame) { - const uint8_t* as_pack; + const uint8_t *as_pack; int freq, stype, smpls, quant, i, ach; as_pack = dv_extract_pack(frame, dv_audio_source); @@ -218,10 +227,10 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame) return 0; } - smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */ - freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */ - stype = (as_pack[3] & 0x1f); /* 0 - 2CH, 2 - 4CH, 3 - 8CH */ - quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ + smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */ + freq = as_pack[4] >> 3 & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */ + stype = as_pack[3] & 0x1f; /* 0 - 2CH, 2 - 4CH, 3 - 8CH */ + quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ if (freq >= FF_ARRAY_ELEMS(dv_audio_frequency)) { av_log(c->fctx, AV_LOG_ERROR, @@ -236,7 +245,7 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame) } /* note: ach counts PAIRS of channels (i.e. stereo channels) */ - ach = ((int[4]){ 1, 0, 2, 4})[stype]; + ach = ((int[4]) { 1, 0, 2, 4 })[stype]; if (ach == 1 && quant && freq == 2) ach = 2; @@ -256,21 +265,21 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame) c->audio_pkt[i].stream_index = c->ast[i]->index; c->audio_pkt[i].flags |= AV_PKT_FLAG_KEY; } - c->ast[i]->codec->sample_rate = dv_audio_frequency[freq]; - c->ast[i]->codec->channels = 2; + c->ast[i]->codec->sample_rate = dv_audio_frequency[freq]; + c->ast[i]->codec->channels = 2; c->ast[i]->codec->channel_layout = AV_CH_LAYOUT_STEREO; - c->ast[i]->codec->bit_rate = 2 * dv_audio_frequency[freq] * 16; - c->ast[i]->start_time = 0; + c->ast[i]->codec->bit_rate = 2 * dv_audio_frequency[freq] * 16; + c->ast[i]->start_time = 0; } c->ach = i; - return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */; + return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */ } -static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame) +static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame) { - const uint8_t* vsc_pack; - AVCodecContext* avctx; + const uint8_t *vsc_pack; + AVCodecContext *avctx; int apt, is16_9; int size = 0; @@ -279,7 +288,7 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame) avpriv_set_pts_info(c->vst, 64, c->sys->time_base.num, c->sys->time_base.den); - avctx->time_base= c->sys->time_base; + avctx->time_base = c->sys->time_base; /* finding out SAR is a little bit messy */ vsc_pack = dv_extract_pack(frame, dv_video_control); @@ -287,7 +296,8 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame) is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 || (!apt && (vsc_pack[2] & 0x07) == 0x07))); c->vst->sample_aspect_ratio = c->sys->sar[is16_9]; - avctx->bit_rate = av_rescale_q(c->sys->frame_size, (AVRational){8,1}, + avctx->bit_rate = av_rescale_q(c->sys->frame_size, + (AVRational) { 8, 1 }, c->sys->time_base); size = c->sys->frame_size; } @@ -310,11 +320,9 @@ static int dv_extract_timecode(DVDemuxContext* c, uint8_t* frame, char *tc) return 1; } -/* - * The following 3 functions constitute our interface to the world - */ +/* The following 3 functions constitute our interface to the world */ -DVDemuxContext* avpriv_dv_init_demux(AVFormatContext *s) +DVDemuxContext *avpriv_dv_init_demux(AVFormatContext *s) { DVDemuxContext *c; @@ -344,9 +352,9 @@ int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt) for (i = 0; i < c->ach; i++) { if (c->ast[i] && c->audio_pkt[i].size) { - *pkt = c->audio_pkt[i]; + *pkt = c->audio_pkt[i]; c->audio_pkt[i].size = 0; - size = pkt->size; + size = pkt->size; break; } } @@ -355,10 +363,10 @@ int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt) } int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, - uint8_t* buf, int buf_size, int64_t pos) + uint8_t *buf, int buf_size, int64_t pos) { int size, i; - uint8_t *ppcm[4] = {0}; + uint8_t *ppcm[5] = { 0 }; if (buf_size < DV_PROFILE_BYTES || !(c->sys = avpriv_dv_frame_profile(c->sys, buf, buf_size)) || @@ -372,7 +380,8 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, for (i = 0; i < c->ach; i++) { c->audio_pkt[i].pos = pos; c->audio_pkt[i].size = size; - c->audio_pkt[i].pts = c->abytes * 30000 * 8 / c->ast[i]->codec->bit_rate; + c->audio_pkt[i].pts = c->abytes * 30000 * 8 / + c->ast[i]->codec->bit_rate; ppcm[i] = c->audio_buf[i]; } if (c->ach) @@ -385,7 +394,7 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, c->audio_pkt[2].size = c->audio_pkt[3].size = 0; } else { c->audio_pkt[0].size = c->audio_pkt[1].size = 0; - c->abytes += size; + c->abytes += size; } } else { c->abytes += size; @@ -407,30 +416,32 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, } static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c, - int64_t timestamp, int flags) + int64_t timestamp, int flags) { // FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk) - const DVprofile* sys = avpriv_dv_codec_profile(c->vst->codec); + const DVprofile *sys = avpriv_dv_codec_profile(c->vst->codec); int64_t offset; - int64_t size = avio_size(s->pb) - s->data_offset; - int64_t max_offset = ((size-1) / sys->frame_size) * sys->frame_size; + int64_t size = avio_size(s->pb) - s->data_offset; + int64_t max_offset = ((size - 1) / sys->frame_size) * sys->frame_size; offset = sys->frame_size * timestamp; - if (size >= 0 && offset > max_offset) offset = max_offset; - else if (offset < 0) offset = 0; + if (size >= 0 && offset > max_offset) + offset = max_offset; + else if (offset < 0) + offset = 0; return offset + s->data_offset; } void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset) { - c->frames= frame_offset; + c->frames = frame_offset; if (c->ach) { if (c->sys) { - c->abytes= av_rescale_q(c->frames, c->sys->time_base, - (AVRational){8, c->ast[0]->codec->bit_rate}); - }else + c->abytes = av_rescale_q(c->frames, c->sys->time_base, + (AVRational) { 8, c->ast[0]->codec->bit_rate }); + } else av_log(c->fctx, AV_LOG_ERROR, "cannot adjust audio bytes\n"); } c->audio_pkt[0].size = c->audio_pkt[1].size = 0; @@ -442,7 +453,7 @@ void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset) ************************************************************/ typedef struct RawDVContext { - DVDemuxContext* dv_demux; + DVDemuxContext *dv_demux; uint8_t buf[DV_MAX_FRAME_SIZE]; } RawDVContext; @@ -508,13 +519,17 @@ static int dv_read_header(AVFormatContext *s) avio_seek(s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0) return AVERROR(EIO); - c->dv_demux->sys = avpriv_dv_frame_profile(c->dv_demux->sys, c->buf, DV_PROFILE_BYTES); + c->dv_demux->sys = avpriv_dv_frame_profile(c->dv_demux->sys, + c->buf, + DV_PROFILE_BYTES); if (!c->dv_demux->sys) { - av_log(s, AV_LOG_ERROR, "Can't determine profile of DV input stream.\n"); + av_log(s, AV_LOG_ERROR, + "Can't determine profile of DV input stream.\n"); return -1; } - s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size, (AVRational){8,1}, + s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size, + (AVRational) { 8, 1 }, c->dv_demux->sys->time_base); if (s->pb->seekable) @@ -523,7 +538,6 @@ static int dv_read_header(AVFormatContext *s) return 0; } - static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) { int size; @@ -546,7 +560,7 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) } static int dv_read_seek(AVFormatContext *s, int stream_index, - int64_t timestamp, int flags) + int64_t timestamp, int flags) { RawDVContext *r = s->priv_data; DVDemuxContext *c = r->dv_demux; @@ -568,33 +582,42 @@ static int dv_read_close(AVFormatContext *s) static int dv_probe(AVProbeData *p) { - unsigned state, marker_pos = 0; + unsigned marker_pos = 0; int i; - int matches = 0; + int matches = 0; + int firstmatch = 0; int secondary_matches = 0; if (p->buf_size < 5) return 0; - state = AV_RB32(p->buf); - for (i = 4; i < p->buf_size; i++) { - if ((state & 0xffffff7f) == 0x1f07003f) - matches++; - // any section header, also with seq/chan num != 0, - // should appear around every 12000 bytes, at least 10 per frame - if ((state & 0xff07ff7f) == 0x1f07003f) - secondary_matches++; - if (state == 0x003f0700 || state == 0xff3f0700) - marker_pos = i; - if (state == 0xff3f0701 && i - marker_pos == 80) - matches++; - state = (state << 8) | p->buf[i]; + for (i = 0; i < p->buf_size-4; i++) { + unsigned state = AV_RB32(p->buf+i); + if ((state & 0x0007f840) == 0x00070000) { + // any section header, also with seq/chan num != 0, + // should appear around every 12000 bytes, at least 10 per frame + if ((state & 0xff07ff7f) == 0x1f07003f) { + secondary_matches++; + if ((state & 0xffffff7f) == 0x1f07003f) { + matches++; + if (!i) + firstmatch = 1; + } + } + if (state == 0x003f0700 || state == 0xff3f0700) + marker_pos = i; + if (state == 0xff3f0701 && i - marker_pos == 80) + matches++; + } } - if (matches && p->buf_size / matches < 1024*1024) { - if (matches > 4 || (secondary_matches >= 10 && p->buf_size / secondary_matches < 24000)) - return AVPROBE_SCORE_MAX*3/4; // not max to avoid dv in mov to match - return AVPROBE_SCORE_MAX/4; + if (matches && p->buf_size / matches < 1024 * 1024) { + if (matches > 4 || firstmatch || + (secondary_matches >= 10 && + p->buf_size / secondary_matches < 24000)) + // not max to avoid dv in mov to match + return AVPROBE_SCORE_MAX * 3 / 4; + return AVPROBE_SCORE_MAX / 4; } return 0; } diff --git a/ffmpeg/libavformat/dvenc.c b/ffmpeg/libavformat/dvenc.c index 0b3811e..43f65c3 100644 --- a/ffmpeg/libavformat/dvenc.c +++ b/ffmpeg/libavformat/dvenc.c @@ -33,7 +33,7 @@ #include "avformat.h" #include "internal.h" #include "libavcodec/dv_profile.h" -#include "libavcodec/dvdata.h" +#include "libavcodec/dv.h" #include "dv.h" #include "libavutil/fifo.h" #include "libavutil/mathematics.h" @@ -390,7 +390,6 @@ static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt) pkt->data, pkt->size, &frame); if (fsize > 0) { avio_write(s->pb, frame, fsize); - avio_flush(s->pb); } return 0; } diff --git a/ffmpeg/libavformat/dxa.c b/ffmpeg/libavformat/dxa.c index 22ee2a9..5b2d7c0 100644 --- a/ffmpeg/libavformat/dxa.c +++ b/ffmpeg/libavformat/dxa.c @@ -169,7 +169,10 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) } avio_seek(s->pb, c->vidpos, SEEK_SET); while(!url_feof(s->pb) && c->frames){ - avio_read(s->pb, buf, 4); + if ((ret = avio_read(s->pb, buf, 4)) != 4) { + av_log(s, AV_LOG_ERROR, "failed reading chunk type\n"); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } switch(AV_RL32(buf)){ case MKTAG('N', 'U', 'L', 'L'): if(av_new_packet(pkt, 4 + pal_size) < 0) @@ -187,7 +190,10 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) avio_read(s->pb, pal + 4, 768); break; case MKTAG('F', 'R', 'A', 'M'): - avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4); + if ((ret = avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4)) != DXA_EXTRA_SIZE - 4) { + av_log(s, AV_LOG_ERROR, "failed reading dxa_extra\n"); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } size = AV_RB32(buf + 5); if(size > 0xFFFFFF){ av_log(s, AV_LOG_ERROR, "Frame size is too big: %d\n", size); diff --git a/ffmpeg/libavformat/electronicarts.c b/ffmpeg/libavformat/electronicarts.c index cf7a271..4ba0fa0 100644 --- a/ffmpeg/libavformat/electronicarts.c +++ b/ffmpeg/libavformat/electronicarts.c @@ -30,35 +30,35 @@ #include "internal.h" #define SCHl_TAG MKTAG('S', 'C', 'H', 'l') -#define SEAD_TAG MKTAG('S', 'E', 'A', 'D') /* Sxxx header */ -#define SNDC_TAG MKTAG('S', 'N', 'D', 'C') /* Sxxx data */ -#define SEND_TAG MKTAG('S', 'E', 'N', 'D') /* Sxxx end */ -#define SHEN_TAG MKTAG('S', 'H', 'E', 'N') /* SxEN header */ -#define SDEN_TAG MKTAG('S', 'D', 'E', 'N') /* SxEN data */ -#define SEEN_TAG MKTAG('S', 'E', 'E', 'N') /* SxEN end */ -#define ISNh_TAG MKTAG('1', 'S', 'N', 'h') /* 1SNx header */ +#define SEAD_TAG MKTAG('S', 'E', 'A', 'D') /* Sxxx header */ +#define SNDC_TAG MKTAG('S', 'N', 'D', 'C') /* Sxxx data */ +#define SEND_TAG MKTAG('S', 'E', 'N', 'D') /* Sxxx end */ +#define SHEN_TAG MKTAG('S', 'H', 'E', 'N') /* SxEN header */ +#define SDEN_TAG MKTAG('S', 'D', 'E', 'N') /* SxEN data */ +#define SEEN_TAG MKTAG('S', 'E', 'E', 'N') /* SxEN end */ +#define ISNh_TAG MKTAG('1', 'S', 'N', 'h') /* 1SNx header */ #define EACS_TAG MKTAG('E', 'A', 'C', 'S') -#define ISNd_TAG MKTAG('1', 'S', 'N', 'd') /* 1SNx data */ -#define ISNe_TAG MKTAG('1', 'S', 'N', 'e') /* 1SNx end */ +#define ISNd_TAG MKTAG('1', 'S', 'N', 'd') /* 1SNx data */ +#define ISNe_TAG MKTAG('1', 'S', 'N', 'e') /* 1SNx end */ #define PT00_TAG MKTAG('P', 'T', 0x0, 0x0) #define GSTR_TAG MKTAG('G', 'S', 'T', 'R') #define SCDl_TAG MKTAG('S', 'C', 'D', 'l') #define SCEl_TAG MKTAG('S', 'C', 'E', 'l') -#define kVGT_TAG MKTAG('k', 'V', 'G', 'T') /* TGV i-frame */ -#define fVGT_TAG MKTAG('f', 'V', 'G', 'T') /* TGV p-frame */ -#define mTCD_TAG MKTAG('m', 'T', 'C', 'D') /* MDEC */ -#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD i-frame */ -#define MADm_TAG MKTAG('M', 'A', 'D', 'm') /* MAD p-frame */ -#define MADe_TAG MKTAG('M', 'A', 'D', 'e') /* MAD lqp-frame */ -#define MPCh_TAG MKTAG('M', 'P', 'C', 'h') /* MPEG2 */ -#define TGQs_TAG MKTAG('T', 'G', 'Q', 's') /* TGQ i-frame (appears in .TGQ files) */ -#define pQGT_TAG MKTAG('p', 'Q', 'G', 'T') /* TGQ i-frame (appears in .UV files) */ -#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T') /* TQI/UV2 i-frame (.UV2/.WVE) */ +#define kVGT_TAG MKTAG('k', 'V', 'G', 'T') /* TGV I-frame */ +#define fVGT_TAG MKTAG('f', 'V', 'G', 'T') /* TGV P-frame */ +#define mTCD_TAG MKTAG('m', 'T', 'C', 'D') /* MDEC */ +#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD I-frame */ +#define MADm_TAG MKTAG('M', 'A', 'D', 'm') /* MAD P-frame */ +#define MADe_TAG MKTAG('M', 'A', 'D', 'e') /* MAD lqp-frame */ +#define MPCh_TAG MKTAG('M', 'P', 'C', 'h') /* MPEG-2 */ +#define TGQs_TAG MKTAG('T', 'G', 'Q', 's') /* TGQ I-frame (appears in .TGQ files) */ +#define pQGT_TAG MKTAG('p', 'Q', 'G', 'T') /* TGQ I-frame (appears in .UV files) */ +#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T') /* TQI/UV2 I-frame (.UV2/.WVE) */ #define MVhd_TAG MKTAG('M', 'V', 'h', 'd') #define MV0K_TAG MKTAG('M', 'V', '0', 'K') #define MV0F_TAG MKTAG('M', 'V', '0', 'F') -#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */ -#define MVIf_TAG MKTAG('M', 'V', 'I', 'f') /* CMV i-frame */ +#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */ +#define MVIf_TAG MKTAG('M', 'V', 'I', 'f') /* CMV I-frame */ typedef struct EaDemuxContext { int big_endian; @@ -78,7 +78,8 @@ typedef struct EaDemuxContext { int num_samples; } EaDemuxContext; -static uint32_t read_arbitary(AVIOContext *pb) { +static uint32_t read_arbitrary(AVIOContext *pb) +{ uint8_t size, byte; int i; uint32_t word; @@ -87,108 +88,135 @@ static uint32_t read_arbitary(AVIOContext *pb) { word = 0; for (i = 0; i < size; i++) { - byte = avio_r8(pb); + byte = avio_r8(pb); word <<= 8; - word |= byte; + word |= byte; } return word; } -/* - * Process PT/GSTR sound header - * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx - */ static int process_audio_header_elements(AVFormatContext *s) { - int inHeader = 1; EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; + int in_header = 1; int compression_type = -1, revision = -1, revision2 = -1; - ea->bytes = 2; - ea->sample_rate = -1; + ea->bytes = 2; + ea->sample_rate = -1; ea->num_channels = 1; - while (!url_feof(pb) && inHeader) { - int inSubheader; + while (!url_feof(pb) && in_header) { + int in_subheader; uint8_t byte; byte = avio_r8(pb); switch (byte) { case 0xFD: - av_log (s, AV_LOG_DEBUG, "entered audio subheader\n"); - inSubheader = 1; - while (!url_feof(pb) && inSubheader) { + av_log(s, AV_LOG_DEBUG, "entered audio subheader\n"); + in_subheader = 1; + while (!url_feof(pb) && in_subheader) { uint8_t subbyte; subbyte = avio_r8(pb); switch (subbyte) { case 0x80: - revision = read_arbitary(pb); - av_log (s, AV_LOG_DEBUG, "revision (element 0x80) set to 0x%08x\n", revision); + revision = read_arbitrary(pb); + av_log(s, AV_LOG_DEBUG, + "revision (element 0x80) set to 0x%08x\n", revision); break; case 0x82: - ea->num_channels = read_arbitary(pb); - av_log (s, AV_LOG_DEBUG, "num_channels (element 0x82) set to 0x%08x\n", ea->num_channels); + ea->num_channels = read_arbitrary(pb); + av_log(s, AV_LOG_DEBUG, + "num_channels (element 0x82) set to 0x%08x\n", + ea->num_channels); break; case 0x83: - compression_type = read_arbitary(pb); - av_log (s, AV_LOG_DEBUG, "compression_type (element 0x83) set to 0x%08x\n", compression_type); + compression_type = read_arbitrary(pb); + av_log(s, AV_LOG_DEBUG, + "compression_type (element 0x83) set to 0x%08x\n", + compression_type); break; case 0x84: - ea->sample_rate = read_arbitary(pb); - av_log (s, AV_LOG_DEBUG, "sample_rate (element 0x84) set to %i\n", ea->sample_rate); + ea->sample_rate = read_arbitrary(pb); + av_log(s, AV_LOG_DEBUG, + "sample_rate (element 0x84) set to %i\n", + ea->sample_rate); break; case 0x85: - ea->num_samples = read_arbitary(pb); - av_log (s, AV_LOG_DEBUG, "num_samples (element 0x85) set to 0x%08x\n", ea->num_samples); + ea->num_samples = read_arbitrary(pb); + av_log(s, AV_LOG_DEBUG, + "num_samples (element 0x85) set to 0x%08x\n", + ea->num_samples); break; case 0x8A: - av_log (s, AV_LOG_DEBUG, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb)); - av_log (s, AV_LOG_DEBUG, "exited audio subheader\n"); - inSubheader = 0; + av_log(s, AV_LOG_DEBUG, + "element 0x%02x set to 0x%08x\n", + subbyte, read_arbitrary(pb)); + av_log(s, AV_LOG_DEBUG, "exited audio subheader\n"); + in_subheader = 0; break; case 0xA0: - revision2 = read_arbitary(pb); - av_log (s, AV_LOG_DEBUG, "revision2 (element 0xA0) set to 0x%08x\n", revision2); + revision2 = read_arbitrary(pb); + av_log(s, AV_LOG_DEBUG, + "revision2 (element 0xA0) set to 0x%08x\n", + revision2); break; case 0xFF: - av_log (s, AV_LOG_DEBUG, "end of header block reached (within audio subheader)\n"); - inSubheader = 0; - inHeader = 0; + av_log(s, AV_LOG_DEBUG, + "end of header block reached (within audio subheader)\n"); + in_subheader = 0; + in_header = 0; break; default: - av_log (s, AV_LOG_DEBUG, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb)); + av_log(s, AV_LOG_DEBUG, + "element 0x%02x set to 0x%08x\n", + subbyte, read_arbitrary(pb)); break; } } break; case 0xFF: - av_log (s, AV_LOG_DEBUG, "end of header block reached\n"); - inHeader = 0; + av_log(s, AV_LOG_DEBUG, "end of header block reached\n"); + in_header = 0; break; default: - av_log (s, AV_LOG_DEBUG, "header element 0x%02x set to 0x%08x\n", byte, read_arbitary(pb)); + av_log(s, AV_LOG_DEBUG, + "header element 0x%02x set to 0x%08x\n", + byte, read_arbitrary(pb)); break; } } switch (compression_type) { - case 0: ea->audio_codec = AV_CODEC_ID_PCM_S16LE; break; - case 7: ea->audio_codec = AV_CODEC_ID_ADPCM_EA; break; + case 0: + ea->audio_codec = AV_CODEC_ID_PCM_S16LE; + break; + case 7: + ea->audio_codec = AV_CODEC_ID_ADPCM_EA; + break; case -1: switch (revision) { - case 1: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1; break; - case 2: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2; break; - case 3: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R3; break; - case -1: break; + case 1: + ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1; + break; + case 2: + ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2; + break; + case 3: + ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R3; + break; + case -1: + break; default: avpriv_request_sample(s, "stream type; revision=%i", revision); return 0; } switch (revision2) { - case 8: ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR; break; + case 8: + ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR; + break; case 10: switch (revision) { case -1: @@ -199,8 +227,11 @@ static int process_audio_header_elements(AVFormatContext *s) return 0; } break; - case 16: ea->audio_codec = AV_CODEC_ID_MP3; break; - case -1: break; + case 16: + ea->audio_codec = AV_CODEC_ID_MP3; + break; + case -1: + break; default: ea->audio_codec = AV_CODEC_ID_NONE; avpriv_request_sample(s, "stream type; revision2=%i", revision2); @@ -208,24 +239,22 @@ static int process_audio_header_elements(AVFormatContext *s) } break; default: - avpriv_request_sample(s, "stream type; compression_type=%i", compression_type); + avpriv_request_sample(s, + "stream type; compression_type=%i", + compression_type); return 0; } if (ea->sample_rate == -1) - ea->sample_rate = revision==3 ? 48000 : 22050; + ea->sample_rate = revision == 3 ? 48000 : 22050; return 1; } -/* - * Process EACS sound header - * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx - */ -static int process_audio_header_eacs(AVFormatContext *s) +static void process_audio_header_eacs(AVFormatContext *s) { EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; int compression_type; ea->sample_rate = ea->big_endian ? avio_rb32(pb) : avio_rl32(pb); @@ -237,64 +266,70 @@ static int process_audio_header_eacs(AVFormatContext *s) switch (compression_type) { case 0: switch (ea->bytes) { - case 1: ea->audio_codec = AV_CODEC_ID_PCM_S8; break; - case 2: ea->audio_codec = AV_CODEC_ID_PCM_S16LE; break; + case 1: + ea->audio_codec = AV_CODEC_ID_PCM_S8; + break; + case 2: + ea->audio_codec = AV_CODEC_ID_PCM_S16LE; + break; } break; - case 1: ea->audio_codec = AV_CODEC_ID_PCM_MULAW; ea->bytes = 1; break; - case 2: ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_EACS; break; + case 1: + ea->audio_codec = AV_CODEC_ID_PCM_MULAW; + ea->bytes = 1; + break; + case 2: + ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_EACS; + break; default: - avpriv_request_sample(s, "stream type; audio compression_type=%i", compression_type); + avpriv_request_sample(s, + "stream type; audio compression_type=%i", + compression_type); } - - return 1; } -/* - * Process SEAD sound header - * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx - */ -static int process_audio_header_sead(AVFormatContext *s) +static void process_audio_header_sead(AVFormatContext *s) { EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; ea->sample_rate = avio_rl32(pb); ea->bytes = avio_rl32(pb); /* 1=8-bit, 2=16-bit */ ea->num_channels = avio_rl32(pb); ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_SEAD; - - return 1; } -static int process_video_header_mdec(AVFormatContext *s) +static void process_video_header_mdec(AVFormatContext *s) { EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; avio_skip(pb, 4); - ea->width = avio_rl16(pb); - ea->height = avio_rl16(pb); - ea->time_base = (AVRational){1,15}; + ea->width = avio_rl16(pb); + ea->height = avio_rl16(pb); + ea->time_base = (AVRational) { 1, 15 }; ea->video_codec = AV_CODEC_ID_MDEC; - return 1; } static int process_video_header_vp6(AVFormatContext *s) { EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; avio_skip(pb, 8); ea->nb_frames = avio_rl32(pb); avio_skip(pb, 4); ea->time_base.den = avio_rl32(pb); ea->time_base.num = avio_rl32(pb); - ea->video_codec = AV_CODEC_ID_VP6; + if (ea->time_base.den <= 0 || ea->time_base.num <= 0) { + av_log(s, AV_LOG_ERROR, "Timebase is invalid\n"); + return AVERROR_INVALIDDATA; + } + ea->video_codec = AV_CODEC_ID_VP6; return 1; } -static int process_video_header_cmv(AVFormatContext *s) +static void process_video_header_cmv(AVFormatContext *s) { EaDemuxContext *ea = s->priv_data; int fps; @@ -302,90 +337,92 @@ static int process_video_header_cmv(AVFormatContext *s) avio_skip(s->pb, 10); fps = avio_rl16(s->pb); if (fps) - ea->time_base = (AVRational){1, fps}; + ea->time_base = (AVRational) { 1, fps }; ea->video_codec = AV_CODEC_ID_CMV; - - return 0; } -/* - * Process EA file header - * Returns 1 if the EA file is valid and successfully opened, 0 otherwise - */ -static int process_ea_header(AVFormatContext *s) { +/* Process EA file header. + * Return 1 if the EA file is valid and successfully opened, 0 otherwise. */ +static int process_ea_header(AVFormatContext *s) +{ uint32_t blockid, size = 0; EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; + AVIOContext *pb = s->pb; int i; - for (i=0; i<5 && (!ea->audio_codec || !ea->video_codec); i++) { - unsigned int startpos = avio_tell(pb); - int err = 0; + for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) { + uint64_t startpos = avio_tell(pb); + int err = 0; blockid = avio_rl32(pb); - size = avio_rl32(pb); + size = avio_rl32(pb); if (i == 0) - ea->big_endian = size > 0x000FFFFF; + ea->big_endian = size > av_bswap32(size); if (ea->big_endian) size = av_bswap32(size); + if (size < 8) { + av_log(s, AV_LOG_ERROR, "chunk size too small\n"); + return AVERROR_INVALIDDATA; + } + switch (blockid) { - case ISNh_TAG: - if (avio_rl32(pb) != EACS_TAG) { - avpriv_request_sample(s, "unknown 1SNh headerid"); - return 0; - } - err = process_audio_header_eacs(s); - break; + case ISNh_TAG: + if (avio_rl32(pb) != EACS_TAG) { + avpriv_request_sample(s, "unknown 1SNh headerid"); + return 0; + } + process_audio_header_eacs(s); + break; - case SCHl_TAG : - case SHEN_TAG : - blockid = avio_rl32(pb); - if (blockid == GSTR_TAG) { - avio_skip(pb, 4); - } else if ((blockid & 0xFFFF)!=PT00_TAG) { - avpriv_request_sample(s, "unknown SCHl headerid"); - return 0; - } - err = process_audio_header_elements(s); - break; + case SCHl_TAG: + case SHEN_TAG: + blockid = avio_rl32(pb); + if (blockid == GSTR_TAG) { + avio_skip(pb, 4); + } else if ((blockid & 0xFFFF) != PT00_TAG) { + avpriv_request_sample(s, "unknown SCHl headerid"); + return 0; + } + err = process_audio_header_elements(s); + break; - case SEAD_TAG: - err = process_audio_header_sead(s); - break; + case SEAD_TAG: + process_audio_header_sead(s); + break; - case MVIh_TAG : - err = process_video_header_cmv(s); - break; + case MVIh_TAG: + process_video_header_cmv(s); + break; - case kVGT_TAG: - ea->video_codec = AV_CODEC_ID_TGV; - break; + case kVGT_TAG: + ea->video_codec = AV_CODEC_ID_TGV; + break; - case mTCD_TAG : - err = process_video_header_mdec(s); - break; + case mTCD_TAG: + process_video_header_mdec(s); + break; - case MPCh_TAG: - ea->video_codec = AV_CODEC_ID_MPEG2VIDEO; - break; + case MPCh_TAG: + ea->video_codec = AV_CODEC_ID_MPEG2VIDEO; + break; - case pQGT_TAG: - case TGQs_TAG: - ea->video_codec = AV_CODEC_ID_TGQ; - break; + case pQGT_TAG: + case TGQs_TAG: + ea->video_codec = AV_CODEC_ID_TGQ; + break; - case pIQT_TAG: - ea->video_codec = AV_CODEC_ID_TQI; - break; + case pIQT_TAG: + ea->video_codec = AV_CODEC_ID_TQI; + break; - case MADk_TAG : - ea->video_codec = AV_CODEC_ID_MAD; - break; + case MADk_TAG: + ea->video_codec = AV_CODEC_ID_MAD; + break; - case MVhd_TAG : - err = process_video_header_vp6(s); - break; + case MVhd_TAG: + err = process_video_header_vp6(s); + break; } if (err < 0) { @@ -401,9 +438,10 @@ static int process_ea_header(AVFormatContext *s) { return 1; } - static int ea_probe(AVProbeData *p) { + unsigned big_endian, size; + switch (AV_RL32(&p->buf[0])) { case ISNh_TAG: case SCHl_TAG: @@ -418,8 +456,13 @@ static int ea_probe(AVProbeData *p) default: return 0; } - if (AV_RL32(&p->buf[4]) > 0xfffff && AV_RB32(&p->buf[4]) > 0xfffff) + size = AV_RL32(&p->buf[4]); + big_endian = size > 0x000FFFFF; + if (big_endian) + size = av_bswap32(size); + if (size > 0xfffff || size < 8) return 0; + return AVPROBE_SCORE_MAX; } @@ -437,34 +480,37 @@ static int ea_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); ea->video_stream_index = st->index; - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = ea->video_codec; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = ea->video_codec; // parsing is necessary to make FFmpeg generate correct timestamps if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) st->need_parsing = AVSTREAM_PARSE_HEADERS; - st->codec->codec_tag = 0; /* no fourcc */ - st->codec->width = ea->width; - st->codec->height = ea->height; - st->duration = st->nb_frames = ea->nb_frames; + st->codec->codec_tag = 0; /* no fourcc */ + st->codec->width = ea->width; + st->codec->height = ea->height; + st->duration = st->nb_frames = ea->nb_frames; if (ea->time_base.num) avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den); - st->r_frame_rate = - st->avg_frame_rate = av_inv_q(ea->time_base); + st->r_frame_rate = + st->avg_frame_rate = av_inv_q(ea->time_base); } if (ea->audio_codec) { - if (ea->num_channels <= 0) { - av_log(s, AV_LOG_WARNING, "Unsupported number of channels: %d\n", ea->num_channels); + if (ea->num_channels <= 0 || ea->num_channels > 2) { + av_log(s, AV_LOG_WARNING, + "Unsupported number of channels: %d\n", ea->num_channels); ea->audio_codec = 0; return 1; } if (ea->sample_rate <= 0) { - av_log(s, AV_LOG_ERROR, "Unsupported sample rate: %d\n", ea->sample_rate); + av_log(s, AV_LOG_ERROR, + "Unsupported sample rate: %d\n", ea->sample_rate); ea->audio_codec = 0; return 1; } if (ea->bytes <= 0) { - av_log(s, AV_LOG_ERROR, "Invalid number of bytes per sample: %d\n", ea->bytes); + av_log(s, AV_LOG_ERROR, + "Invalid number of bytes per sample: %d\n", ea->bytes); ea->audio_codec = AV_CODEC_ID_NONE; return 1; } @@ -474,32 +520,31 @@ static int ea_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 33, 1, ea->sample_rate); - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = ea->audio_codec; - st->codec->codec_tag = 0; /* no tag */ - st->codec->channels = ea->num_channels; - st->codec->sample_rate = ea->sample_rate; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = ea->audio_codec; + st->codec->codec_tag = 0; /* no tag */ + st->codec->channels = ea->num_channels; + st->codec->sample_rate = ea->sample_rate; st->codec->bits_per_coded_sample = ea->bytes * 8; - st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * - st->codec->bits_per_coded_sample / 4; - st->codec->block_align = st->codec->channels*st->codec->bits_per_coded_sample; - ea->audio_stream_index = st->index; - st->start_time = 0; + st->codec->bit_rate = st->codec->channels * + st->codec->sample_rate * + st->codec->bits_per_coded_sample / 4; + st->codec->block_align = st->codec->channels * + st->codec->bits_per_coded_sample; + ea->audio_stream_index = st->index; + st->start_time = 0; } return 1; } -static int ea_read_packet(AVFormatContext *s, - AVPacket *pkt) +static int ea_read_packet(AVFormatContext *s, AVPacket *pkt) { EaDemuxContext *ea = s->priv_data; - AVIOContext *pb = s->pb; - int ret = 0; - int packet_read = 0; + AVIOContext *pb = s->pb; int partial_packet = 0; unsigned int chunk_type, chunk_size; - int key = 0; + int ret = 0, packet_read = 0, key = 0; int av_uninit(num_samples); while (!packet_read || partial_packet) { @@ -512,7 +557,7 @@ static int ea_read_packet(AVFormatContext *s, switch (chunk_type) { /* audio data */ case ISNh_TAG: - /* header chunk also contains data; skip over the header portion*/ + /* header chunk also contains data; skip over the header portion */ if (chunk_size < 32) return AVERROR_INVALIDDATA; avio_skip(pb, 32); @@ -545,12 +590,16 @@ static int ea_read_packet(AVFormatContext *s, case AV_CODEC_ID_ADPCM_EA_R1: case AV_CODEC_ID_ADPCM_EA_R2: case AV_CODEC_ID_ADPCM_IMA_EA_EACS: - if (pkt->size >= 4) - pkt->duration = AV_RL32(pkt->data); - break; case AV_CODEC_ID_ADPCM_EA_R3: - if (pkt->size >= 4) + if (pkt->size < 4) { + av_log(s, AV_LOG_ERROR, "Packet is too short\n"); + av_free_packet(pkt); + return AVERROR_INVALIDDATA; + } + if (ea->audio_codec == AV_CODEC_ID_ADPCM_EA_R3) pkt->duration = AV_RB32(pkt->data); + else + pkt->duration = AV_RL32(pkt->data); break; case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: pkt->duration = ret * 2 / ea->num_channels; @@ -572,7 +621,7 @@ static int ea_read_packet(AVFormatContext *s, case SCEl_TAG: case SEND_TAG: case SEEN_TAG: - ret = AVERROR(EIO); + ret = AVERROR(EIO); packet_read = 1; break; @@ -586,12 +635,12 @@ static int ea_read_packet(AVFormatContext *s, case fVGT_TAG: case MADm_TAG: case MADe_TAG: - avio_seek(pb, -8, SEEK_CUR); // include chunk preamble + avio_seek(pb, -8, SEEK_CUR); // include chunk preamble chunk_size += 8; goto get_video_packet; case mTCD_TAG: - avio_skip(pb, 8); // skip ea dct header + avio_skip(pb, 8); // skip ea DCT header chunk_size -= 8; goto get_video_packet; @@ -611,8 +660,8 @@ get_video_packet: } partial_packet = chunk_type == MVIh_TAG; pkt->stream_index = ea->video_stream_index; - pkt->flags |= key; - packet_read = 1; + pkt->flags |= key; + packet_read = 1; break; default: diff --git a/ffmpeg/libavformat/ffmdec.c b/ffmpeg/libavformat/ffmdec.c index 02cf790..9d89b16 100644 --- a/ffmpeg/libavformat/ffmdec.c +++ b/ffmpeg/libavformat/ffmdec.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "avformat.h" @@ -278,11 +280,8 @@ static int ffm2_read_header(AVFormatContext *s) codec->flags2 = avio_rb32(pb); codec->debug = avio_rb32(pb); if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { - codec->extradata_size = avio_rb32(pb); - codec->extradata = av_malloc(codec->extradata_size); - if (!codec->extradata) + if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0) return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); } avio_seek(pb, next, SEEK_SET); id = avio_rb32(pb); @@ -468,11 +467,8 @@ static int ffm_read_header(AVFormatContext *s) goto fail; } if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { - codec->extradata_size = avio_rb32(pb); - codec->extradata = av_malloc(codec->extradata_size); - if (!codec->extradata) + if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0) return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); } } diff --git a/ffmpeg/libavformat/ffmenc.c b/ffmpeg/libavformat/ffmenc.c index 522945e..eb809eb 100644 --- a/ffmpeg/libavformat/ffmenc.c +++ b/ffmpeg/libavformat/ffmenc.c @@ -277,4 +277,5 @@ AVOutputFormat ff_ffm_muxer = { .write_header = ffm_write_header, .write_packet = ffm_write_packet, .write_trailer = ffm_write_trailer, + .flags = AVFMT_TS_NEGATIVE, }; diff --git a/ffmpeg/libavformat/ffmetadec.c b/ffmpeg/libavformat/ffmetadec.c index 4bdc98a..19c14e4 100644 --- a/ffmpeg/libavformat/ffmetadec.c +++ b/ffmpeg/libavformat/ffmetadec.c @@ -135,7 +135,7 @@ static int read_header(AVFormatContext *s) AVStream *st = avformat_new_stream(s, NULL); if (!st) - return -1; + return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_DATA; st->codec->codec_id = AV_CODEC_ID_FFMETADATA; @@ -145,7 +145,7 @@ static int read_header(AVFormatContext *s) AVChapter *ch = read_chapter(s); if (!ch) - return -1; + return AVERROR(ENOMEM); m = &ch->metadata; } else diff --git a/ffmpeg/libavformat/file.c b/ffmpeg/libavformat/file.c index e09a64b..2defc75 100644 --- a/ffmpeg/libavformat/file.c +++ b/ffmpeg/libavformat/file.c @@ -20,6 +20,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/internal.h" #include "libavutil/opt.h" #include "avformat.h" #include <fcntl.h> @@ -49,10 +50,17 @@ typedef struct FileContext { const AVClass *class; int fd; int trunc; + int blocksize; } FileContext; static const AVOption file_options[] = { { "truncate", "Truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { NULL } +}; + +static const AVOption pipe_options[] = { + { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL } }; @@ -63,17 +71,28 @@ static const AVClass file_class = { .version = LIBAVUTIL_VERSION_INT, }; +static const AVClass pipe_class = { + .class_name = "pipe", + .item_name = av_default_item_name, + .option = pipe_options, + .version = LIBAVUTIL_VERSION_INT, +}; + static int file_read(URLContext *h, unsigned char *buf, int size) { FileContext *c = h->priv_data; - int r = read(c->fd, buf, size); + int r; + size = FFMIN(size, c->blocksize); + r = read(c->fd, buf, size); return (-1 == r)?AVERROR(errno):r; } static int file_write(URLContext *h, const unsigned char *buf, int size) { FileContext *c = h->priv_data; - int r = write(c->fd, buf, size); + int r; + size = FFMIN(size, c->blocksize); + r = write(c->fd, buf, size); return (-1 == r)?AVERROR(errno):r; } @@ -132,7 +151,7 @@ static int file_open(URLContext *h, const char *filename, int flags) #ifdef O_BINARY access |= O_BINARY; #endif - fd = open(filename, access, 0666); + fd = avpriv_open(filename, access, 0666); if (fd == -1) return AVERROR(errno); c->fd = fd; @@ -213,6 +232,7 @@ URLProtocol ff_pipe_protocol = { .url_get_file_handle = file_get_handle, .url_check = file_check, .priv_data_size = sizeof(FileContext), + .priv_data_class = &pipe_class, }; #endif /* CONFIG_PIPE_PROTOCOL */ diff --git a/ffmpeg/libavformat/flacdec.c b/ffmpeg/libavformat/flacdec.c index d5aacfd..29310b8 100644 --- a/ffmpeg/libavformat/flacdec.c +++ b/ffmpeg/libavformat/flacdec.c @@ -21,139 +21,13 @@ #include "libavcodec/flac.h" #include "avformat.h" -#include "id3v2.h" +#include "flac_picture.h" #include "internal.h" #include "rawdec.h" #include "oggdec.h" #include "vorbiscomment.h" #include "libavcodec/bytestream.h" -#define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0) - -static int parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) -{ - const CodecMime *mime = ff_id3v2_mime_tags; - enum AVCodecID id = AV_CODEC_ID_NONE; - AVBufferRef *data = NULL; - uint8_t mimetype[64], *desc = NULL; - AVIOContext *pb = NULL; - AVStream *st; - int type, width, height; - int len, ret = 0; - - pb = avio_alloc_context(buf, buf_size, 0, NULL, NULL, NULL, NULL); - if (!pb) - return AVERROR(ENOMEM); - - /* read the picture type */ - type = avio_rb32(pb); - if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) { - av_log(s, AV_LOG_ERROR, "Invalid picture type: %d.\n", type); - if (s->error_recognition & AV_EF_EXPLODE) { - RETURN_ERROR(AVERROR_INVALIDDATA); - } - type = 0; - } - - /* picture mimetype */ - len = avio_rb32(pb); - if (len <= 0 || - avio_read(pb, mimetype, FFMIN(len, sizeof(mimetype) - 1)) != len) { - av_log(s, AV_LOG_ERROR, "Could not read mimetype from an attached " - "picture.\n"); - if (s->error_recognition & AV_EF_EXPLODE) - ret = AVERROR_INVALIDDATA; - goto fail; - } - mimetype[len] = 0; - - while (mime->id != AV_CODEC_ID_NONE) { - if (!strncmp(mime->str, mimetype, sizeof(mimetype))) { - id = mime->id; - break; - } - mime++; - } - if (id == AV_CODEC_ID_NONE) { - av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n", - mimetype); - if (s->error_recognition & AV_EF_EXPLODE) - ret = AVERROR_INVALIDDATA; - goto fail; - } - - /* picture description */ - len = avio_rb32(pb); - if (len > 0) { - if (!(desc = av_malloc(len + 1))) { - RETURN_ERROR(AVERROR(ENOMEM)); - } - - if (avio_read(pb, desc, len) != len) { - av_log(s, AV_LOG_ERROR, "Error reading attached picture description.\n"); - if (s->error_recognition & AV_EF_EXPLODE) - ret = AVERROR(EIO); - goto fail; - } - desc[len] = 0; - } - - /* picture metadata */ - width = avio_rb32(pb); - height = avio_rb32(pb); - avio_skip(pb, 8); - - /* picture data */ - len = avio_rb32(pb); - if (len <= 0) { - av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len); - if (s->error_recognition & AV_EF_EXPLODE) - ret = AVERROR_INVALIDDATA; - goto fail; - } - if (!(data = av_buffer_alloc(len))) { - RETURN_ERROR(AVERROR(ENOMEM)); - } - if (avio_read(pb, data->data, len) != len) { - av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n"); - if (s->error_recognition & AV_EF_EXPLODE) - ret = AVERROR(EIO); - goto fail; - } - - st = avformat_new_stream(s, NULL); - if (!st) { - RETURN_ERROR(AVERROR(ENOMEM)); - } - - av_init_packet(&st->attached_pic); - st->attached_pic.buf = data; - st->attached_pic.data = data->data; - st->attached_pic.size = len; - st->attached_pic.stream_index = st->index; - st->attached_pic.flags |= AV_PKT_FLAG_KEY; - - st->disposition |= AV_DISPOSITION_ATTACHED_PIC; - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = id; - st->codec->width = width; - st->codec->height = height; - av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0); - if (desc) - av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL); - - av_freep(&pb); - - return 0; - -fail: - av_buffer_unref(&data); - av_freep(&desc); - av_freep(&pb); - return ret; - -} - static int flac_read_header(AVFormatContext *s) { int ret, metadata_last=0, metadata_type, metadata_size, found_streaminfo=0; @@ -248,7 +122,7 @@ static int flac_read_header(AVFormatContext *s) } av_freep(&buffer); } else if (metadata_type == FLAC_METADATA_TYPE_PICTURE) { - ret = parse_picture(s, buffer, metadata_size); + ret = ff_flac_parse_picture(s, buffer, metadata_size); av_freep(&buffer); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Error parsing attached picture.\n"); @@ -280,7 +154,7 @@ static int flac_probe(AVProbeData *p) { if (p->buf_size < 4 || memcmp(p->buf, "fLaC", 4)) return 0; - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; } AVInputFormat ff_flac_demuxer = { diff --git a/ffmpeg/libavformat/flacenc.c b/ffmpeg/libavformat/flacenc.c index b625278..87e9362 100644 --- a/ffmpeg/libavformat/flacenc.c +++ b/ffmpeg/libavformat/flacenc.c @@ -21,6 +21,7 @@ #include "libavcodec/flac.h" #include "avformat.h" +#include "avio_internal.h" #include "flacenc.h" #include "vorbiscomment.h" #include "libavcodec/bytestream.h" @@ -31,10 +32,7 @@ static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_byte { avio_w8(pb, last_block ? 0x81 : 0x01); avio_wb24(pb, n_padding_bytes); - while (n_padding_bytes > 0) { - avio_w8(pb, 0); - n_padding_bytes--; - } + ffio_fill(pb, 0, n_padding_bytes); return 0; } @@ -122,7 +120,6 @@ static int flac_write_trailer(struct AVFormatContext *s) static int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt) { avio_write(s->pb, pkt->data, pkt->size); - avio_flush(s->pb); return 0; } diff --git a/ffmpeg/libavformat/flic.c b/ffmpeg/libavformat/flic.c index 8d49116..7235f2e 100644 --- a/ffmpeg/libavformat/flic.c +++ b/ffmpeg/libavformat/flic.c @@ -80,7 +80,7 @@ static int flic_probe(AVProbeData *p) return 0; - return AVPROBE_SCORE_MAX; + return AVPROBE_SCORE_MAX - 1; } static int flic_read_header(AVFormatContext *s) @@ -125,8 +125,8 @@ static int flic_read_header(AVFormatContext *s) } /* send over the whole 128-byte FLIC header */ - st->codec->extradata_size = FLIC_HEADER_SIZE; - st->codec->extradata = av_malloc(FLIC_HEADER_SIZE); + if (ff_alloc_extradata(st->codec, FLIC_HEADER_SIZE)) + return AVERROR(ENOMEM); memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE); /* peek at the preamble to detect TFTD videos - they seem to always start with an audio chunk */ @@ -176,8 +176,8 @@ static int flic_read_header(AVFormatContext *s) /* send over abbreviated FLIC header chunk */ av_free(st->codec->extradata); - st->codec->extradata_size = 12; - st->codec->extradata = av_malloc(12); + if (ff_alloc_extradata(st->codec, 12)) + return AVERROR(ENOMEM); memcpy(st->codec->extradata, header, 12); } else if (magic_number == FLIC_FILE_MAGIC_1) { diff --git a/ffmpeg/libavformat/flvdec.c b/ffmpeg/libavformat/flvdec.c index d0511f1..5683ed5 100644 --- a/ffmpeg/libavformat/flvdec.c +++ b/ffmpeg/libavformat/flvdec.c @@ -41,12 +41,12 @@ typedef struct { const AVClass *class; ///< Class for private options. - int trust_metadata; ///< configure streams according onMetaData - int wrong_dts; ///< wrong dts due to negative cts + int trust_metadata; ///< configure streams according onMetaData + int wrong_dts; ///< wrong dts due to negative cts uint8_t *new_extradata[FLV_STREAM_TYPE_NB]; - int new_extradata_size[FLV_STREAM_TYPE_NB]; - int last_sample_rate; - int last_channels; + int new_extradata_size[FLV_STREAM_TYPE_NB]; + int last_sample_rate; + int last_channels; struct { int64_t dts; int64_t pos; @@ -61,7 +61,11 @@ static int flv_probe(AVProbeData *p) const uint8_t *d; d = p->buf; - if (d[0] == 'F' && d[1] == 'L' && d[2] == 'V' && d[3] < 5 && d[5]==0 && AV_RB32(d+5)>8) { + if (d[0] == 'F' && + d[1] == 'L' && + d[2] == 'V' && + d[3] < 5 && d[5] == 0 && + AV_RB32(d + 5) > 8) { return AVPROBE_SCORE_MAX; } return 0; @@ -73,7 +77,7 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type) if (!st) return NULL; st->codec->codec_type = codec_type; - if(s->nb_streams>=3 ||( s->nb_streams==2 + if (s->nb_streams>=3 ||( s->nb_streams==2 && s->streams[0]->codec->codec_type != AVMEDIA_TYPE_DATA && s->streams[1]->codec->codec_type != AVMEDIA_TYPE_DATA)) s->ctx_flags &= ~AVFMTCTX_NOHEADER; @@ -81,10 +85,11 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type) avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */ return st; } + static int flv_same_audio_codec(AVCodecContext *acodec, int flags) { int bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8; - int flv_codecid = flags & FLV_AUDIO_CODECID_MASK; + int flv_codecid = flags & FLV_AUDIO_CODECID_MASK; int codec_id; if (!acodec->codec_id && !acodec->codec_tag) @@ -93,18 +98,21 @@ static int flv_same_audio_codec(AVCodecContext *acodec, int flags) if (acodec->bits_per_coded_sample != bits_per_coded_sample) return 0; - switch(flv_codecid) { - //no distinction between S16 and S8 PCM codec flags + switch (flv_codecid) { + // no distinction between S16 and S8 PCM codec flags case FLV_CODECID_PCM: - codec_id = bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 : + codec_id = bits_per_coded_sample == 8 + ? AV_CODEC_ID_PCM_U8 #if HAVE_BIGENDIAN - AV_CODEC_ID_PCM_S16BE; + : AV_CODEC_ID_PCM_S16BE; #else - AV_CODEC_ID_PCM_S16LE; + : AV_CODEC_ID_PCM_S16LE; #endif return codec_id == acodec->codec_id; case FLV_CODECID_PCM_LE: - codec_id = bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 : AV_CODEC_ID_PCM_S16LE; + codec_id = bits_per_coded_sample == 8 + ? AV_CODEC_ID_PCM_U8 + : AV_CODEC_ID_PCM_S16LE; return codec_id == acodec->codec_id; case FLV_CODECID_AAC: return acodec->codec_id == AV_CODEC_ID_AAC; @@ -120,57 +128,72 @@ static int flv_same_audio_codec(AVCodecContext *acodec, int flags) return acodec->codec_id == AV_CODEC_ID_NELLYMOSER; case FLV_CODECID_PCM_MULAW: return acodec->sample_rate == 8000 && - acodec->codec_id == AV_CODEC_ID_PCM_MULAW; + acodec->codec_id == AV_CODEC_ID_PCM_MULAW; case FLV_CODECID_PCM_ALAW: - return acodec->sample_rate = 8000 && - acodec->codec_id == AV_CODEC_ID_PCM_ALAW; + return acodec->sample_rate == 8000 && + acodec->codec_id == AV_CODEC_ID_PCM_ALAW; default: return acodec->codec_tag == (flv_codecid >> FLV_AUDIO_CODECID_OFFSET); } } -static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, AVCodecContext *acodec, int flv_codecid) { - switch(flv_codecid) { - //no distinction between S16 and S8 PCM codec flags - case FLV_CODECID_PCM: - acodec->codec_id = acodec->bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 : +static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, + AVCodecContext *acodec, int flv_codecid) +{ + switch (flv_codecid) { + // no distinction between S16 and S8 PCM codec flags + case FLV_CODECID_PCM: + acodec->codec_id = acodec->bits_per_coded_sample == 8 + ? AV_CODEC_ID_PCM_U8 #if HAVE_BIGENDIAN - AV_CODEC_ID_PCM_S16BE; + : AV_CODEC_ID_PCM_S16BE; #else - AV_CODEC_ID_PCM_S16LE; + : AV_CODEC_ID_PCM_S16LE; #endif - break; - case FLV_CODECID_PCM_LE: - acodec->codec_id = acodec->bits_per_coded_sample == 8 ? AV_CODEC_ID_PCM_U8 : AV_CODEC_ID_PCM_S16LE; break; - case FLV_CODECID_AAC : acodec->codec_id = AV_CODEC_ID_AAC; break; - case FLV_CODECID_ADPCM: acodec->codec_id = AV_CODEC_ID_ADPCM_SWF; break; - case FLV_CODECID_SPEEX: - acodec->codec_id = AV_CODEC_ID_SPEEX; - acodec->sample_rate = 16000; - break; - case FLV_CODECID_MP3 : acodec->codec_id = AV_CODEC_ID_MP3 ; astream->need_parsing = AVSTREAM_PARSE_FULL; break; - case FLV_CODECID_NELLYMOSER_8KHZ_MONO: - acodec->sample_rate = 8000; //in case metadata does not otherwise declare samplerate - acodec->codec_id = AV_CODEC_ID_NELLYMOSER; - break; - case FLV_CODECID_NELLYMOSER_16KHZ_MONO: - acodec->sample_rate = 16000; - acodec->codec_id = AV_CODEC_ID_NELLYMOSER; - break; - case FLV_CODECID_NELLYMOSER: - acodec->codec_id = AV_CODEC_ID_NELLYMOSER; - break; - case FLV_CODECID_PCM_MULAW: - acodec->sample_rate = 8000; - acodec->codec_id = AV_CODEC_ID_PCM_MULAW; - break; - case FLV_CODECID_PCM_ALAW: - acodec->sample_rate = 8000; - acodec->codec_id = AV_CODEC_ID_PCM_ALAW; - break; - default: - av_log(s, AV_LOG_INFO, "Unsupported audio codec (%x)\n", flv_codecid >> FLV_AUDIO_CODECID_OFFSET); - acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET; + break; + case FLV_CODECID_PCM_LE: + acodec->codec_id = acodec->bits_per_coded_sample == 8 + ? AV_CODEC_ID_PCM_U8 + : AV_CODEC_ID_PCM_S16LE; + break; + case FLV_CODECID_AAC: + acodec->codec_id = AV_CODEC_ID_AAC; + break; + case FLV_CODECID_ADPCM: + acodec->codec_id = AV_CODEC_ID_ADPCM_SWF; + break; + case FLV_CODECID_SPEEX: + acodec->codec_id = AV_CODEC_ID_SPEEX; + acodec->sample_rate = 16000; + break; + case FLV_CODECID_MP3: + acodec->codec_id = AV_CODEC_ID_MP3; + astream->need_parsing = AVSTREAM_PARSE_FULL; + break; + case FLV_CODECID_NELLYMOSER_8KHZ_MONO: + // in case metadata does not otherwise declare samplerate + acodec->sample_rate = 8000; + acodec->codec_id = AV_CODEC_ID_NELLYMOSER; + break; + case FLV_CODECID_NELLYMOSER_16KHZ_MONO: + acodec->sample_rate = 16000; + acodec->codec_id = AV_CODEC_ID_NELLYMOSER; + break; + case FLV_CODECID_NELLYMOSER: + acodec->codec_id = AV_CODEC_ID_NELLYMOSER; + break; + case FLV_CODECID_PCM_MULAW: + acodec->sample_rate = 8000; + acodec->codec_id = AV_CODEC_ID_PCM_MULAW; + break; + case FLV_CODECID_PCM_ALAW: + acodec->sample_rate = 8000; + acodec->codec_id = AV_CODEC_ID_PCM_ALAW; + break; + default: + avpriv_request_sample(s, "Audio codec (%x)", + flv_codecid >> FLV_AUDIO_CODECID_OFFSET); + acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET; } } @@ -182,63 +205,74 @@ static int flv_same_video_codec(AVCodecContext *vcodec, int flags) return 1; switch (flv_codecid) { - case FLV_CODECID_H263: - return vcodec->codec_id == AV_CODEC_ID_FLV1; - case FLV_CODECID_SCREEN: - return vcodec->codec_id == AV_CODEC_ID_FLASHSV; - case FLV_CODECID_SCREEN2: - return vcodec->codec_id == AV_CODEC_ID_FLASHSV2; - case FLV_CODECID_VP6: - return vcodec->codec_id == AV_CODEC_ID_VP6F; - case FLV_CODECID_VP6A: - return vcodec->codec_id == AV_CODEC_ID_VP6A; - case FLV_CODECID_H264: - return vcodec->codec_id == AV_CODEC_ID_H264; - default: - return vcodec->codec_tag == flv_codecid; + case FLV_CODECID_H263: + return vcodec->codec_id == AV_CODEC_ID_FLV1; + case FLV_CODECID_SCREEN: + return vcodec->codec_id == AV_CODEC_ID_FLASHSV; + case FLV_CODECID_SCREEN2: + return vcodec->codec_id == AV_CODEC_ID_FLASHSV2; + case FLV_CODECID_VP6: + return vcodec->codec_id == AV_CODEC_ID_VP6F; + case FLV_CODECID_VP6A: + return vcodec->codec_id == AV_CODEC_ID_VP6A; + case FLV_CODECID_H264: + return vcodec->codec_id == AV_CODEC_ID_H264; + default: + return vcodec->codec_tag == flv_codecid; } } -static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_codecid, int read) { +static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, + int flv_codecid, int read) +{ AVCodecContext *vcodec = vstream->codec; - switch(flv_codecid) { - case FLV_CODECID_H263 : vcodec->codec_id = AV_CODEC_ID_FLV1 ; break; - case FLV_CODECID_REALH263: vcodec->codec_id = AV_CODEC_ID_H263 ; break; // Really mean it this time - case FLV_CODECID_SCREEN: vcodec->codec_id = AV_CODEC_ID_FLASHSV; break; - case FLV_CODECID_SCREEN2: vcodec->codec_id = AV_CODEC_ID_FLASHSV2; break; - case FLV_CODECID_VP6 : vcodec->codec_id = AV_CODEC_ID_VP6F ; - case FLV_CODECID_VP6A : - if(flv_codecid == FLV_CODECID_VP6A) - vcodec->codec_id = AV_CODEC_ID_VP6A; - if (read) { - if (vcodec->extradata_size != 1) { - vcodec->extradata = av_malloc(1 + FF_INPUT_BUFFER_PADDING_SIZE); - if (vcodec->extradata) - vcodec->extradata_size = 1; - } - if (vcodec->extradata) - vcodec->extradata[0] = avio_r8(s->pb); - else - avio_skip(s->pb, 1); + switch (flv_codecid) { + case FLV_CODECID_H263: + vcodec->codec_id = AV_CODEC_ID_FLV1; + break; + case FLV_CODECID_REALH263: + vcodec->codec_id = AV_CODEC_ID_H263; + break; // Really mean it this time + case FLV_CODECID_SCREEN: + vcodec->codec_id = AV_CODEC_ID_FLASHSV; + break; + case FLV_CODECID_SCREEN2: + vcodec->codec_id = AV_CODEC_ID_FLASHSV2; + break; + case FLV_CODECID_VP6: + vcodec->codec_id = AV_CODEC_ID_VP6F; + case FLV_CODECID_VP6A: + if (flv_codecid == FLV_CODECID_VP6A) + vcodec->codec_id = AV_CODEC_ID_VP6A; + if (read) { + if (vcodec->extradata_size != 1) { + ff_alloc_extradata(vcodec, 1); } - return 1; // 1 byte body size adjustment for flv_read_packet() - case FLV_CODECID_H264: - vcodec->codec_id = AV_CODEC_ID_H264; - return 3; // not 4, reading packet type will consume one byte - case FLV_CODECID_MPEG4: - vcodec->codec_id = AV_CODEC_ID_MPEG4; - return 3; - default: - av_log(s, AV_LOG_INFO, "Unsupported video codec (%x)\n", flv_codecid); - vcodec->codec_tag = flv_codecid; + if (vcodec->extradata) + vcodec->extradata[0] = avio_r8(s->pb); + else + avio_skip(s->pb, 1); + } + return 1; // 1 byte body size adjustment for flv_read_packet() + case FLV_CODECID_H264: + vcodec->codec_id = AV_CODEC_ID_H264; + vstream->need_parsing = AVSTREAM_PARSE_HEADERS; + return 3; // not 4, reading packet type will consume one byte + case FLV_CODECID_MPEG4: + vcodec->codec_id = AV_CODEC_ID_MPEG4; + return 3; + default: + avpriv_request_sample(s, "Video codec (%x)", flv_codecid); + vcodec->codec_tag = flv_codecid; } return 0; } -static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) { +static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) +{ int length = avio_rb16(ioc); - if(length >= buffsize) { + if (length >= buffsize) { avio_skip(ioc, length); return -1; } @@ -250,16 +284,18 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) { return length; } -static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream *vstream, int64_t max_pos) { - FLVContext *flv = s->priv_data; +static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, + AVStream *vstream, int64_t max_pos) +{ + FLVContext *flv = s->priv_data; unsigned int timeslen = 0, fileposlen = 0, i; char str_val[256]; - int64_t *times = NULL; + int64_t *times = NULL; int64_t *filepositions = NULL; - int ret = AVERROR(ENOSYS); - int64_t initial_pos = avio_tell(ioc); + int ret = AVERROR(ENOSYS); + int64_t initial_pos = avio_tell(ioc); - if(vstream->nb_index_entries>0){ + if (vstream->nb_index_entries>0) { av_log(s, AV_LOG_WARNING, "Skiping duplicate index\n"); return 0; } @@ -267,8 +303,9 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream if (s->flags & AVFMT_FLAG_IGNIDX) return 0; - while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) { - int64_t** current_array; + while (avio_tell(ioc) < max_pos - 2 && + amf_get_string(ioc, str_val, sizeof(str_val)) > 0) { + int64_t **current_array; unsigned int arraylen; // Expect array object in context @@ -276,16 +313,19 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream break; arraylen = avio_rb32(ioc); - if(arraylen>>28) + if (arraylen>>28) break; - if (!strcmp(KEYFRAMES_TIMESTAMP_TAG , str_val) && !times){ - current_array= × - timeslen= arraylen; - }else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && !filepositions){ - current_array= &filepositions; - fileposlen= arraylen; - }else // unexpected metatag inside keyframes, will not use such metadata for indexing + if (!strcmp(KEYFRAMES_TIMESTAMP_TAG , str_val) && !times) { + current_array = × + timeslen = arraylen; + } else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && + !filepositions) { + current_array = &filepositions; + fileposlen = arraylen; + } else + // unexpected metatag inside keyframes, will not use such + // metadata for indexing break; if (!(*current_array = av_mallocz(sizeof(**current_array) * arraylen))) { @@ -308,12 +348,12 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) { for (i = 0; i < fileposlen; i++) { - av_add_index_entry(vstream, filepositions[i], times[i]*1000, + av_add_index_entry(vstream, filepositions[i], times[i] * 1000, 0, 0, AVINDEX_KEYFRAME); if (i < 2) { flv->validate_index[i].pos = filepositions[i]; flv->validate_index[i].dts = times[i] * 1000; - flv->validate_count = i + 1; + flv->validate_count = i + 1; } } } else { @@ -328,7 +368,10 @@ finish: return ret; } -static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vstream, const char *key, int64_t max_pos, int depth) { +static int amf_parse_object(AVFormatContext *s, AVStream *astream, + AVStream *vstream, const char *key, + int64_t max_pos, int depth) +{ AVCodecContext *acodec, *vcodec; FLVContext *flv = s->priv_data; AVIOContext *ioc; @@ -336,74 +379,85 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst char str_val[256]; double num_val; - num_val = 0; - ioc = s->pb; - + num_val = 0; + ioc = s->pb; amf_type = avio_r8(ioc); - switch(amf_type) { - case AMF_DATA_TYPE_NUMBER: - num_val = av_int2double(avio_rb64(ioc)); break; - case AMF_DATA_TYPE_BOOL: - num_val = avio_r8(ioc); break; - case AMF_DATA_TYPE_STRING: - if(amf_get_string(ioc, str_val, sizeof(str_val)) < 0) - return -1; - break; - case AMF_DATA_TYPE_OBJECT: - if ((vstream || astream) && ioc->seekable && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1) - if (parse_keyframes_index(s, ioc, vstream ? vstream : astream, - max_pos) < 0) - av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); - - while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) { - if (amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0) - return -1; //if we couldn't skip, bomb out. - } - if(avio_r8(ioc) != AMF_END_OF_OBJECT) - return -1; - break; - case AMF_DATA_TYPE_NULL: - case AMF_DATA_TYPE_UNDEFINED: - case AMF_DATA_TYPE_UNSUPPORTED: - break; //these take up no additional space - case AMF_DATA_TYPE_MIXEDARRAY: - avio_skip(ioc, 4); //skip 32-bit max array index - while(avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) { - //this is the only case in which we would want a nested parse to not skip over the object - if(amf_parse_object(s, astream, vstream, str_val, max_pos, depth + 1) < 0) - return -1; - } - if(avio_r8(ioc) != AMF_END_OF_OBJECT) + switch (amf_type) { + case AMF_DATA_TYPE_NUMBER: + num_val = av_int2double(avio_rb64(ioc)); + break; + case AMF_DATA_TYPE_BOOL: + num_val = avio_r8(ioc); + break; + case AMF_DATA_TYPE_STRING: + if (amf_get_string(ioc, str_val, sizeof(str_val)) < 0) + return -1; + break; + case AMF_DATA_TYPE_OBJECT: + if ((vstream || astream) && key && + ioc->seekable && + !strcmp(KEYFRAMES_TAG, key) && depth == 1) + if (parse_keyframes_index(s, ioc, vstream ? vstream : astream, + max_pos) < 0) + av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); + + while (avio_tell(ioc) < max_pos - 2 && + amf_get_string(ioc, str_val, sizeof(str_val)) > 0) + if (amf_parse_object(s, astream, vstream, str_val, max_pos, + depth + 1) < 0) + return -1; // if we couldn't skip, bomb out. + if (avio_r8(ioc) != AMF_END_OF_OBJECT) + return -1; + break; + case AMF_DATA_TYPE_NULL: + case AMF_DATA_TYPE_UNDEFINED: + case AMF_DATA_TYPE_UNSUPPORTED: + break; // these take up no additional space + case AMF_DATA_TYPE_MIXEDARRAY: + avio_skip(ioc, 4); // skip 32-bit max array index + while (avio_tell(ioc) < max_pos - 2 && + amf_get_string(ioc, str_val, sizeof(str_val)) > 0) + // this is the only case in which we would want a nested + // parse to not skip over the object + if (amf_parse_object(s, astream, vstream, str_val, max_pos, + depth + 1) < 0) return -1; - break; - case AMF_DATA_TYPE_ARRAY: { - unsigned int arraylen, i; - - arraylen = avio_rb32(ioc); - for(i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) { - if(amf_parse_object(s, NULL, NULL, NULL, max_pos, depth + 1) < 0) - return -1; //if we couldn't skip, bomb out. - } - } - break; - case AMF_DATA_TYPE_DATE: - avio_skip(ioc, 8 + 2); //timestamp (double) and UTC offset (int16) - break; - default: //unsupported type, we couldn't skip + if (avio_r8(ioc) != AMF_END_OF_OBJECT) return -1; + break; + case AMF_DATA_TYPE_ARRAY: + { + unsigned int arraylen, i; + + arraylen = avio_rb32(ioc); + for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) + if (amf_parse_object(s, NULL, NULL, NULL, max_pos, + depth + 1) < 0) + return -1; // if we couldn't skip, bomb out. + } + break; + case AMF_DATA_TYPE_DATE: + avio_skip(ioc, 8 + 2); // timestamp (double) and UTC offset (int16) + break; + default: // unsupported type, we couldn't skip + return -1; } - if(depth == 1 && key) { //only look for metadata values when we are not nested and key != NULL + // only look for metadata values when we are not nested and key != NULL + if (depth == 1 && key) { acodec = astream ? astream->codec : NULL; vcodec = vstream ? vstream->codec : NULL; - if (amf_type == AMF_DATA_TYPE_NUMBER) { + if (amf_type == AMF_DATA_TYPE_NUMBER || + amf_type == AMF_DATA_TYPE_BOOL) { if (!strcmp(key, "duration")) s->duration = num_val * AV_TIME_BASE; - else if (!strcmp(key, "videodatarate") && vcodec && 0 <= (int)(num_val * 1024.0)) + else if (!strcmp(key, "videodatarate") && vcodec && + 0 <= (int)(num_val * 1024.0)) vcodec->bit_rate = num_val * 1024.0; - else if (!strcmp(key, "audiodatarate") && acodec && 0 <= (int)(num_val * 1024.0)) + else if (!strcmp(key, "audiodatarate") && acodec && + 0 <= (int)(num_val * 1024.0)) acodec->bit_rate = num_val * 1024.0; else if (!strcmp(key, "datastream")) { AVStream *st = create_stream(s, AVMEDIA_TYPE_DATA); @@ -413,17 +467,21 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst } else if (flv->trust_metadata) { if (!strcmp(key, "videocodecid") && vcodec) { flv_set_video_codec(s, vstream, num_val, 0); - } else - if (!strcmp(key, "audiocodecid") && acodec) { - flv_set_audio_codec(s, astream, acodec, num_val); - } else - if (!strcmp(key, "audiosamplerate") && acodec) { + } else if (!strcmp(key, "audiocodecid") && acodec) { + int id = ((int)num_val) << FLV_AUDIO_CODECID_OFFSET; + flv_set_audio_codec(s, astream, acodec, id); + } else if (!strcmp(key, "audiosamplerate") && acodec) { acodec->sample_rate = num_val; - } else - if (!strcmp(key, "width") && vcodec) { + } else if (!strcmp(key, "audiosamplesize") && acodec) { + acodec->bits_per_coded_sample = num_val; + } else if (!strcmp(key, "stereo") && acodec) { + acodec->channels = num_val + 1; + acodec->channel_layout = acodec->channels == 2 ? + AV_CH_LAYOUT_STEREO : + AV_CH_LAYOUT_MONO; + } else if (!strcmp(key, "width") && vcodec) { vcodec->width = num_val; - } else - if (!strcmp(key, "height") && vcodec) { + } else if (!strcmp(key, "height") && vcodec) { vcodec->height = num_val; } } @@ -445,13 +503,15 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst !strcmp(key, "audiosamplerate") || !strcmp(key, "audiosamplesize") || !strcmp(key, "stereo") || - !strcmp(key, "audiocodecid")) + !strcmp(key, "audiocodecid") || + !strcmp(key, "datastream")) return 0; - if(amf_type == AMF_DATA_TYPE_BOOL) { - av_strlcpy(str_val, num_val > 0 ? "true" : "false", sizeof(str_val)); + if (amf_type == AMF_DATA_TYPE_BOOL) { + av_strlcpy(str_val, num_val > 0 ? "true" : "false", + sizeof(str_val)); av_dict_set(&s->metadata, key, str_val, 0); - } else if(amf_type == AMF_DATA_TYPE_NUMBER) { + } else if (amf_type == AMF_DATA_TYPE_NUMBER) { snprintf(str_val, sizeof(str_val), "%.f", num_val); av_dict_set(&s->metadata, key, str_val, 0); } else if (amf_type == AMF_DATA_TYPE_STRING) @@ -461,17 +521,23 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst return 0; } -static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { +static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) +{ AMFDataType type; - AVStream *stream, *astream, *vstream, *dstream; + AVStream *stream, *astream, *vstream; + AVStream av_unused *dstream; AVIOContext *ioc; int i; - char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want. + // only needs to hold the string "onMetaData". + // Anything longer is something we don't want. + char buffer[11]; - vstream = astream = dstream = NULL; - ioc = s->pb; + astream = NULL; + vstream = NULL; + dstream = NULL; + ioc = s->pb; - //first object needs to be "onMetaData" string + // first object needs to be "onMetaData" string type = avio_r8(ioc); if (type != AMF_DATA_TYPE_STRING || amf_get_string(ioc, buffer, sizeof(buffer)) < 0) @@ -483,16 +549,20 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { if (strcmp(buffer, "onMetaData")) return -1; - //find the streams now so that amf_parse_object doesn't need to do the lookup every time it is called. - for(i = 0; i < s->nb_streams; i++) { + // find the streams now so that amf_parse_object doesn't need to do + // the lookup every time it is called. + for (i = 0; i < s->nb_streams; i++) { stream = s->streams[i]; - if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) vstream = stream; - else if(stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) astream = stream; - else if(stream->codec->codec_type == AVMEDIA_TYPE_DATA) dstream = stream; + if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) + vstream = stream; + else if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) + astream = stream; + else if (stream->codec->codec_type == AVMEDIA_TYPE_DATA) + dstream = stream; } - //parse the second object (we want a mixed array) - if(amf_parse_object(s, astream, vstream, buffer, next_pos, 0) < 0) + // parse the second object (we want a mixed array) + if (amf_parse_object(s, astream, vstream, buffer, next_pos, 0) < 0) return -1; return 0; @@ -508,19 +578,19 @@ static int flv_read_header(AVFormatContext *s) /* FIXME: better fix needed */ if (!flags) { flags = FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO; - av_log(s, AV_LOG_WARNING, "Broken FLV file, which says no streams present, this might fail\n"); + av_log(s, AV_LOG_WARNING, + "Broken FLV file, which says no streams present, " + "this might fail\n"); } s->ctx_flags |= AVFMTCTX_NOHEADER; - if(flags & FLV_HEADER_FLAG_HASVIDEO){ - if(!create_stream(s, AVMEDIA_TYPE_VIDEO)) + if (flags & FLV_HEADER_FLAG_HASVIDEO) + if (!create_stream(s, AVMEDIA_TYPE_VIDEO)) return AVERROR(ENOMEM); - } - if(flags & FLV_HEADER_FLAG_HASAUDIO){ - if(!create_stream(s, AVMEDIA_TYPE_AUDIO)) + if (flags & FLV_HEADER_FLAG_HASAUDIO) + if (!create_stream(s, AVMEDIA_TYPE_AUDIO)) return AVERROR(ENOMEM); - } // Flag doesn't indicate whether or not there is script-data present. Must // create that stream if it's encountered. @@ -537,7 +607,7 @@ static int flv_read_close(AVFormatContext *s) { int i; FLVContext *flv = s->priv_data; - for(i=0; i<FLV_STREAM_TYPE_NB; i++) + for (i=0; i<FLV_STREAM_TYPE_NB; i++) av_freep(&flv->new_extradata[i]); return 0; } @@ -545,11 +615,8 @@ static int flv_read_close(AVFormatContext *s) static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size) { av_free(st->codec->extradata); - st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, s->pb, size) < 0) return AVERROR(ENOMEM); - st->codec->extradata_size = size; - avio_read(s->pb, st->codec->extradata, st->codec->extradata_size); return 0; } @@ -557,7 +624,8 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream, int size) { av_free(flv->new_extradata[stream]); - flv->new_extradata[stream] = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); + flv->new_extradata[stream] = av_mallocz(size + + FF_INPUT_BUFFER_PADDING_SIZE); if (!flv->new_extradata[stream]) return AVERROR(ENOMEM); flv->new_extradata_size[stream] = size; @@ -568,51 +636,96 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream, static void clear_index_entries(AVFormatContext *s, int64_t pos) { int i, j, out; - av_log(s, AV_LOG_WARNING, "Found invalid index entries, clearing the index.\n"); + av_log(s, AV_LOG_WARNING, + "Found invalid index entries, clearing the index.\n"); for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; /* Remove all index entries that point to >= pos */ out = 0; - for (j = 0; j < st->nb_index_entries; j++) { + for (j = 0; j < st->nb_index_entries; j++) if (st->index_entries[j].pos < pos) st->index_entries[out++] = st->index_entries[j]; - } st->nb_index_entries = out; } } +static int amf_skip_tag(AVIOContext *pb, AMFDataType type) +{ + int nb = -1, ret, parse_name = 1; + + switch (type) { + case AMF_DATA_TYPE_NUMBER: + avio_skip(pb, 8); + break; + case AMF_DATA_TYPE_BOOL: + avio_skip(pb, 1); + break; + case AMF_DATA_TYPE_STRING: + avio_skip(pb, avio_rb16(pb)); + break; + case AMF_DATA_TYPE_ARRAY: + parse_name = 0; + case AMF_DATA_TYPE_MIXEDARRAY: + nb = avio_rb32(pb); + case AMF_DATA_TYPE_OBJECT: + while(!pb->eof_reached && (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY)) { + if (parse_name) { + int size = avio_rb16(pb); + if (!size) { + avio_skip(pb, 1); + break; + } + avio_skip(pb, size); + } + if ((ret = amf_skip_tag(pb, avio_r8(pb))) < 0) + return ret; + } + break; + case AMF_DATA_TYPE_NULL: + case AMF_DATA_TYPE_OBJECT_END: + break; + default: + return AVERROR_INVALIDDATA; + } + return 0; +} static int flv_data_packet(AVFormatContext *s, AVPacket *pkt, int64_t dts, int64_t next) { - int ret = AVERROR_INVALIDDATA, i; AVIOContext *pb = s->pb; - AVStream *st = NULL; - AMFDataType type; + AVStream *st = NULL; char buf[20]; - int length; + int ret = AVERROR_INVALIDDATA; + int i, length = -1; - type = avio_r8(pb); - if (type == AMF_DATA_TYPE_MIXEDARRAY) + switch (avio_r8(pb)) { + case AMF_DATA_TYPE_MIXEDARRAY: avio_seek(pb, 4, SEEK_CUR); - else if (type != AMF_DATA_TYPE_OBJECT) - goto out; - - amf_get_string(pb, buf, sizeof(buf)); - if (strcmp(buf, "type") || avio_r8(pb) != AMF_DATA_TYPE_STRING) - goto out; - - amf_get_string(pb, buf, sizeof(buf)); - //FIXME parse it as codec_id - amf_get_string(pb, buf, sizeof(buf)); - if (strcmp(buf, "text") || avio_r8(pb) != AMF_DATA_TYPE_STRING) - goto out; - - length = avio_rb16(pb); - ret = av_get_packet(s->pb, pkt, length); - if (ret < 0) { - ret = AVERROR(EIO); - goto out; + case AMF_DATA_TYPE_OBJECT: + break; + default: + goto skip; + } + + while ((ret = amf_get_string(pb, buf, sizeof(buf))) > 0) { + AMFDataType type = avio_r8(pb); + if (type == AMF_DATA_TYPE_STRING && !strcmp(buf, "text")) { + length = avio_rb16(pb); + ret = av_get_packet(pb, pkt, length); + if (ret < 0) + goto skip; + else + break; + } else { + if ((ret = amf_skip_tag(pb, type)) < 0) + goto skip; + } + } + + if (length < 0) { + ret = AVERROR_INVALIDDATA; + goto skip; } for (i = 0; i < s->nb_streams; i++) { @@ -624,7 +737,7 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt, if (i == s->nb_streams) { st = create_stream(s, AVMEDIA_TYPE_DATA); if (!st) - goto out; + return AVERROR_INVALIDDATA; st->codec->codec_id = AV_CODEC_ID_TEXT; } @@ -633,10 +746,11 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt, pkt->size = ret; pkt->stream_index = st->index; - pkt->flags |= AV_PKT_FLAG_KEY; + pkt->flags |= AV_PKT_FLAG_KEY; +skip: avio_seek(s->pb, next + 4, SEEK_SET); -out: + return ret; } @@ -645,130 +759,131 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) FLVContext *flv = s->priv_data; int ret, i, type, size, flags; int stream_type=-1; - int64_t next, pos; + int64_t next, pos, meta_pos; int64_t dts, pts = AV_NOPTS_VALUE; int av_uninit(channels); int av_uninit(sample_rate); - AVStream *st = NULL; - - for(;;avio_skip(s->pb, 4)){ /* pkt size is repeated at end. skip it */ - pos = avio_tell(s->pb); - type = avio_r8(s->pb); - size = avio_rb24(s->pb); - dts = avio_rb24(s->pb); - dts |= avio_r8(s->pb) << 24; - av_dlog(s, "type:%d, size:%d, dts:%"PRId64"\n", type, size, dts); - if (url_feof(s->pb)) - return AVERROR_EOF; - avio_skip(s->pb, 3); /* stream id, always 0 */ - flags = 0; - - if (flv->validate_next < flv->validate_count) { - int64_t validate_pos = flv->validate_index[flv->validate_next].pos; - if (pos == validate_pos) { - if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <= - VALIDATE_INDEX_TS_THRESH) { - flv->validate_next++; - } else { + AVStream *st = NULL; + + /* pkt size is repeated at end. skip it */ + for (;; avio_skip(s->pb, 4)) { + pos = avio_tell(s->pb); + type = avio_r8(s->pb); + size = avio_rb24(s->pb); + dts = avio_rb24(s->pb); + dts |= avio_r8(s->pb) << 24; + av_dlog(s, "type:%d, size:%d, dts:%"PRId64"\n", type, size, dts); + if (url_feof(s->pb)) + return AVERROR_EOF; + avio_skip(s->pb, 3); /* stream id, always 0 */ + flags = 0; + + if (flv->validate_next < flv->validate_count) { + int64_t validate_pos = flv->validate_index[flv->validate_next].pos; + if (pos == validate_pos) { + if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <= + VALIDATE_INDEX_TS_THRESH) { + flv->validate_next++; + } else { + clear_index_entries(s, validate_pos); + flv->validate_count = 0; + } + } else if (pos > validate_pos) { clear_index_entries(s, validate_pos); flv->validate_count = 0; } - } else if (pos > validate_pos) { - clear_index_entries(s, validate_pos); - flv->validate_count = 0; } - } - - if(size == 0) - continue; - next= size + avio_tell(s->pb); - - if (type == FLV_TAG_TYPE_AUDIO) { - stream_type=FLV_STREAM_TYPE_AUDIO; - flags = avio_r8(s->pb); - size--; - } else if (type == FLV_TAG_TYPE_VIDEO) { - stream_type=FLV_STREAM_TYPE_VIDEO; - flags = avio_r8(s->pb); - size--; - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) - goto skip; - } else if (type == FLV_TAG_TYPE_META) { - if (size > 13+1+4 && dts == 0) { // Header-type metadata stuff - flv_read_metabody(s, next); - goto skip; - } else if (dts != 0) { // Script-data "special" metadata frames - don't skip + if (size == 0) + continue; + + next = size + avio_tell(s->pb); + + if (type == FLV_TAG_TYPE_AUDIO) { + stream_type = FLV_STREAM_TYPE_AUDIO; + flags = avio_r8(s->pb); + size--; + } else if (type == FLV_TAG_TYPE_VIDEO) { + stream_type = FLV_STREAM_TYPE_VIDEO; + flags = avio_r8(s->pb); + size--; + if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) + goto skip; + } else if (type == FLV_TAG_TYPE_META) { stream_type=FLV_STREAM_TYPE_DATA; + if (size > 13 + 1 + 4 && dts == 0) { // Header-type metadata stuff + meta_pos = avio_tell(s->pb); + if (flv_read_metabody(s, next) == 0) { + goto skip; + } + avio_seek(s->pb, meta_pos, SEEK_SET); + } } else { - goto skip; + av_log(s, AV_LOG_DEBUG, + "skipping flv packet: type %d, size %d, flags %d\n", + type, size, flags); +skip: + avio_seek(s->pb, next, SEEK_SET); + continue; } - } else { - av_log(s, AV_LOG_DEBUG, "skipping flv packet: type %d, size %d, flags %d\n", type, size, flags); - skip: - avio_seek(s->pb, next, SEEK_SET); - continue; - } - - /* skip empty data packets */ - if (!size) - continue; - /* now find stream */ - for(i=0;i<s->nb_streams;i++) { - st = s->streams[i]; - if (stream_type == FLV_STREAM_TYPE_AUDIO) { - if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && - (s->audio_codec_id || flv_same_audio_codec(st->codec, flags))) { - break; + /* skip empty data packets */ + if (!size) + continue; + + /* now find stream */ + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + if (stream_type == FLV_STREAM_TYPE_AUDIO) { + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && + (s->audio_codec_id || flv_same_audio_codec(st->codec, flags))) + break; + } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + (s->video_codec_id || flv_same_video_codec(st->codec, flags))) + break; + } else if (stream_type == FLV_STREAM_TYPE_DATA) { + if (st->codec->codec_type == AVMEDIA_TYPE_DATA) + break; } - } else - if (stream_type == FLV_STREAM_TYPE_VIDEO) { - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && - (s->video_codec_id || flv_same_video_codec(st->codec, flags))) { - break; - } - } else if (stream_type == FLV_STREAM_TYPE_DATA) { - if (st->codec->codec_type == AVMEDIA_TYPE_DATA) - break; } - } - if(i == s->nb_streams){ - av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n"); - st = create_stream(s, - (int[]){AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA}[stream_type]); - if (!st) - return AVERROR(ENOMEM); + if (i == s->nb_streams) { + static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA}; + av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n"); + st = create_stream(s, stream_types[stream_type]); + if (!st) + return AVERROR(ENOMEM); + } + av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard); + if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO))) + ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO))) + || st->discard >= AVDISCARD_ALL + ) { + avio_seek(s->pb, next, SEEK_SET); + continue; + } + if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || stream_type == FLV_STREAM_TYPE_AUDIO) + av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME); + break; } - av_dlog(s, "%d %X %d \n", stream_type, flags, st->discard); - if( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO))) - ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO))) - || st->discard >= AVDISCARD_ALL - ){ - avio_seek(s->pb, next, SEEK_SET); - continue; - } - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) - av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME); - break; - } - // if not streamed and no duration from metadata then seek to end to find the duration from the timestamps - if(s->pb->seekable && (!s->duration || s->duration==AV_NOPTS_VALUE) && !flv->searched_for_end){ + // if not streamed and no duration from metadata then seek to end to find + // the duration from the timestamps + if (s->pb->seekable && (!s->duration || s->duration == AV_NOPTS_VALUE) && !flv->searched_for_end) { int size; - const int64_t pos= avio_tell(s->pb); - int64_t fsize= avio_size(s->pb); + const int64_t pos = avio_tell(s->pb); + int64_t fsize = avio_size(s->pb); retry_duration: - avio_seek(s->pb, fsize-4, SEEK_SET); - size= avio_rb32(s->pb); - avio_seek(s->pb, fsize-3-size, SEEK_SET); - if(size == avio_rb24(s->pb) + 11){ + avio_seek(s->pb, fsize - 4, SEEK_SET); + size = avio_rb32(s->pb); + avio_seek(s->pb, fsize - 3 - size, SEEK_SET); + if (size == avio_rb24(s->pb) + 11) { uint32_t ts = avio_rb24(s->pb); - ts |= avio_r8(s->pb) << 24; - if(ts) + ts |= avio_r8(s->pb) << 24; + if (ts) s->duration = ts * (int64_t)AV_TIME_BASE / 1000; - else if (fsize >= 8 && fsize - 8 >= size){ + else if (fsize >= 8 && fsize - 8 >= size) { fsize -= size+4; goto retry_duration; } @@ -778,29 +893,35 @@ retry_duration: flv->searched_for_end = 1; } - if(stream_type == FLV_STREAM_TYPE_AUDIO){ + if (stream_type == FLV_STREAM_TYPE_AUDIO) { int bits_per_coded_sample; - channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1; - sample_rate = (44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >> FLV_AUDIO_SAMPLERATE_OFFSET) >> 3); + channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1; + sample_rate = 44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >> + FLV_AUDIO_SAMPLERATE_OFFSET) >> 3; bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8; - if(!st->codec->channels || !st->codec->sample_rate || !st->codec->bits_per_coded_sample) { + if (!st->codec->channels || !st->codec->sample_rate || + !st->codec->bits_per_coded_sample) { st->codec->channels = channels; - st->codec->channel_layout = channels == 1 ? AV_CH_LAYOUT_MONO : - AV_CH_LAYOUT_STEREO; + st->codec->channel_layout = channels == 1 + ? AV_CH_LAYOUT_MONO + : AV_CH_LAYOUT_STEREO; st->codec->sample_rate = sample_rate; st->codec->bits_per_coded_sample = bits_per_coded_sample; } - if(!st->codec->codec_id){ - flv_set_audio_codec(s, st, st->codec, flags & FLV_AUDIO_CODECID_MASK); - flv->last_sample_rate = sample_rate = st->codec->sample_rate; - flv->last_channels = channels = st->codec->channels; + if (!st->codec->codec_id) { + flv_set_audio_codec(s, st, st->codec, + flags & FLV_AUDIO_CODECID_MASK); + flv->last_sample_rate = + sample_rate = st->codec->sample_rate; + flv->last_channels = + channels = st->codec->channels; } else { AVCodecContext ctx; ctx.sample_rate = sample_rate; flv_set_audio_codec(s, st, &ctx, flags & FLV_AUDIO_CODECID_MASK); sample_rate = ctx.sample_rate; } - } else if(stream_type == FLV_STREAM_TYPE_VIDEO) { + } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { size -= flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK, 1); } @@ -810,11 +931,13 @@ retry_duration: int type = avio_r8(s->pb); size--; if (st->codec->codec_id == AV_CODEC_ID_H264 || st->codec->codec_id == AV_CODEC_ID_MPEG4) { - int32_t cts = (avio_rb24(s->pb)+0xff800000)^0xff800000; // sign extension + // sign extension + int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000; pts = dts + cts; if (cts < 0) { // dts are wrong flv->wrong_dts = 1; - av_log(s, AV_LOG_WARNING, "negative cts, previous timestamps might be wrong\n"); + av_log(s, AV_LOG_WARNING, + "negative cts, previous timestamps might be wrong\n"); } if (flv->wrong_dts) dts = AV_NOPTS_VALUE; @@ -832,7 +955,7 @@ retry_duration: MPEG4AudioConfig cfg; if (avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata, st->codec->extradata_size * 8, 1) >= 0) { - st->codec->channels = cfg.channels; + st->codec->channels = cfg.channels; st->codec->channel_layout = 0; if (cfg.ext_sample_rate) st->codec->sample_rate = cfg.ext_sample_rate; @@ -854,11 +977,11 @@ retry_duration: goto leave; } - ret= av_get_packet(s->pb, pkt, size); + ret = av_get_packet(s->pb, pkt, size); if (ret < 0) return ret; - pkt->dts = dts; - pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts; + pkt->dts = dts; + pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts; pkt->stream_index = st->index; if (flv->new_extradata[stream_type]) { uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, @@ -870,8 +993,9 @@ retry_duration: flv->new_extradata_size[stream_type] = 0; } } - if (stream_type == FLV_STREAM_TYPE_AUDIO && (sample_rate != flv->last_sample_rate || - channels != flv->last_channels)) { + if (stream_type == FLV_STREAM_TYPE_AUDIO && + (sample_rate != flv->last_sample_rate || + channels != flv->last_channels)) { flv->last_sample_rate = sample_rate; flv->last_channels = channels; ff_add_param_change(pkt, channels, 0, sample_rate, 0, 0); @@ -888,7 +1012,7 @@ leave: } static int flv_read_seek(AVFormatContext *s, int stream_index, - int64_t ts, int flags) + int64_t ts, int flags) { FLVContext *flv = s->priv_data; flv->validate_count = 0; @@ -898,11 +1022,11 @@ static int flv_read_seek(AVFormatContext *s, int stream_index, #define OFFSET(x) offsetof(FLVContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { - { "flv_metadata", "Allocate streams according the onMetaData array", OFFSET(trust_metadata), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VD}, + { "flv_metadata", "Allocate streams according to the onMetaData array", OFFSET(trust_metadata), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VD }, { NULL } }; -static const AVClass class = { +static const AVClass flv_class = { .class_name = "flvdec", .item_name = av_default_item_name, .option = options, @@ -919,5 +1043,5 @@ AVInputFormat ff_flv_demuxer = { .read_seek = flv_read_seek, .read_close = flv_read_close, .extensions = "flv", - .priv_class = &class, + .priv_class = &flv_class, }; diff --git a/ffmpeg/libavformat/flvenc.c b/ffmpeg/libavformat/flvenc.c index 502da0f..fb36f66 100644 --- a/ffmpeg/libavformat/flvenc.c +++ b/ffmpeg/libavformat/flvenc.c @@ -212,6 +212,11 @@ static int flv_write_header(AVFormatContext *s) } else { framerate = 1 / av_q2d(s->streams[i]->codec->time_base); } + if (video_enc) { + av_log(s, AV_LOG_ERROR, + "at most one video stream is supported in flv\n"); + return AVERROR(EINVAL); + } video_enc = enc; if (enc->codec_tag == 0) { av_log(s, AV_LOG_ERROR, "Video codec '%s' for stream %d is not compatible with FLV\n", @@ -220,6 +225,11 @@ static int flv_write_header(AVFormatContext *s) } break; case AVMEDIA_TYPE_AUDIO: + if (audio_enc) { + av_log(s, AV_LOG_ERROR, + "at most one audio stream is supported in flv\n"); + return AVERROR(EINVAL); + } audio_enc = enc; if (get_audio_flags(s, enc) < 0) return AVERROR_INVALIDDATA; @@ -450,8 +460,8 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) uint8_t *data = NULL; int flags = -1, flags_size, ret; - if (enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_VP6F || - enc->codec_id == AV_CODEC_ID_VP6A || enc->codec_id == AV_CODEC_ID_AAC) + if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A || + enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_AAC) flags_size = 2; else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) flags_size = 5; @@ -493,10 +503,13 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } else if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { + if (!s->streams[pkt->stream_index]->nb_frames) { av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: " "use audio bitstream filter 'aac_adtstoasc' to fix it " "('-bsf:a aac_adtstoasc' option with ffmpeg)\n"); return AVERROR_INVALIDDATA; + } + av_log(s, AV_LOG_WARNING, "aac bitstream error\n"); } if (flv->delay == AV_NOPTS_VALUE) @@ -526,7 +539,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if (enc->codec_type == AVMEDIA_TYPE_DATA) { int data_size; - int metadata_size_pos = avio_tell(pb); + int64_t metadata_size_pos = avio_tell(pb); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onTextData"); avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); @@ -550,13 +563,17 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) avio_w8(pb,flags); if (enc->codec_id == AV_CODEC_ID_VP6) avio_w8(pb,0); - if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A) - avio_w8(pb, enc->extradata_size ? enc->extradata[0] : 0); - else if (enc->codec_id == AV_CODEC_ID_AAC) - avio_w8(pb,1); // AAC raw + if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A) { + if (enc->extradata_size) + avio_w8(pb, enc->extradata[0]); + else + avio_w8(pb, ((FFALIGN(enc->width, 16) - enc->width) << 4) | + (FFALIGN(enc->height, 16) - enc->height)); + } else if (enc->codec_id == AV_CODEC_ID_AAC) + avio_w8(pb, 1); // AAC raw else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) { - avio_w8(pb,1); // AVC NALU - avio_wb24(pb,pkt->pts - pkt->dts); + avio_w8(pb, 1); // AVC NALU + avio_wb24(pb, pkt->pts - pkt->dts); } avio_write(pb, data ? data : pkt->data, size); @@ -566,7 +583,6 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) pkt->pts + flv->delay + pkt->duration); } - avio_flush(pb); av_free(data); return pb->error; diff --git a/ffmpeg/libavformat/framecrcenc.c b/ffmpeg/libavformat/framecrcenc.c index 92f2e91..dbe49b5 100644 --- a/ffmpeg/libavformat/framecrcenc.c +++ b/ffmpeg/libavformat/framecrcenc.c @@ -34,19 +34,27 @@ static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt) if (pkt->flags != AV_PKT_FLAG_KEY) av_strlcatf(buf, sizeof(buf), ", F=0x%0X", pkt->flags); if (pkt->side_data_elems) { - int i; + int i, j; av_strlcatf(buf, sizeof(buf), ", S=%d", pkt->side_data_elems); for (i=0; i<pkt->side_data_elems; i++) { - uint32_t side_data_crc = av_adler32_update(0, - pkt->side_data[i].data, - pkt->side_data[i].size); + uint32_t side_data_crc = 0; + if (HAVE_BIGENDIAN && AV_PKT_DATA_PALETTE == pkt->side_data[i].type) { + for (j=0; j<pkt->side_data[i].size; j++) { + side_data_crc = av_adler32_update(side_data_crc, + pkt->side_data[i].data + (j^3), + 1); + } + } else { + side_data_crc = av_adler32_update(0, + pkt->side_data[i].data, + pkt->side_data[i].size); + } av_strlcatf(buf, sizeof(buf), ", %8d, 0x%08x", pkt->side_data[i].size, side_data_crc); } } av_strlcatf(buf, sizeof(buf), "\n"); avio_write(s->pb, buf, strlen(buf)); - avio_flush(s->pb); return 0; } @@ -57,5 +65,6 @@ AVOutputFormat ff_framecrc_muxer = { .video_codec = AV_CODEC_ID_RAWVIDEO, .write_header = ff_framehash_write_header, .write_packet = framecrc_write_packet, - .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, }; diff --git a/ffmpeg/libavformat/framehash.c b/ffmpeg/libavformat/framehash.c index 28e9e84..f97f59b 100644 --- a/ffmpeg/libavformat/framehash.c +++ b/ffmpeg/libavformat/framehash.c @@ -1,20 +1,20 @@ /* * Common functions for the frame{crc,md5} muxers * - * 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 */ @@ -23,6 +23,9 @@ int ff_framehash_write_header(AVFormatContext *s) { int i; + + if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) + avio_printf(s->pb, "#software: %s\n", LIBAVFORMAT_IDENT); for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); diff --git a/ffmpeg/libavformat/g723_1.c b/ffmpeg/libavformat/g723_1.c index 8d35f88..4f3ce8f 100644 --- a/ffmpeg/libavformat/g723_1.c +++ b/ffmpeg/libavformat/g723_1.c @@ -24,13 +24,14 @@ * G.723.1 demuxer */ +#include "libavutil/attributes.h" #include "libavutil/channel_layout.h" #include "avformat.h" #include "internal.h" static const uint8_t frame_size[4] = { 24, 20, 4, 1 }; -static int g723_1_init(AVFormatContext *s) +static av_cold int g723_1_init(AVFormatContext *s) { AVStream *st; diff --git a/ffmpeg/libavformat/gif.c b/ffmpeg/libavformat/gif.c index 31b0101..e52498d 100644 --- a/ffmpeg/libavformat/gif.c +++ b/ffmpeg/libavformat/gif.c @@ -2,6 +2,8 @@ * Animated GIF muxer * Copyright (c) 2000 Fabrice Bellard * + * first version by Francois Revol <revol@free.fr> + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -19,333 +21,169 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * First version by Francois Revol revol@free.fr - * - * Features and limitations: - * - currently no compression is performed, - * in fact the size of the data is 9/8 the size of the image in 8bpp - * - uses only a global standard palette - * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS). - * - * Reference documents: - * http://www.goice.co.jp/member/mo/formats/gif.html - * http://astronomy.swin.edu.au/pbourke/dataformats/gif/ - * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt - * - * this url claims to have an LZW algorithm not covered by Unisys patent: - * http://www.msg.net/utility/whirlgif/gifencod.html - * could help reduce the size of the files _a lot_... - * some sites mentions an RLE type compression also. - */ - #include "avformat.h" +#include "internal.h" +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" #include "libavutil/log.h" #include "libavutil/opt.h" -/* The GIF format uses reversed order for bitstreams... */ -/* at least they don't use PDP_ENDIAN :) */ -#define BITSTREAM_WRITER_LE - -#include "libavcodec/put_bits.h" - -/* bitstream minipacket size */ -#define GIF_CHUNKS 100 - -/* slows down the decoding (and some browsers don't like it) */ -/* update on the 'some browsers don't like it issue from above: - * this was probably due to missing 'Data Sub-block Terminator' - * (byte 19) in the app_header */ -#define GIF_ADD_APP_HEADER // required to enable looping of animated gif - -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; -} rgb_triplet; - -/* we use the standard 216 color palette */ - -/* this script was used to create the palette: - * for r in 00 33 66 99 cc ff; do - * for g in 00 33 66 99 cc ff; do - * echo -n " " - * for b in 00 33 66 99 cc ff; do - * echo -n "{ 0x$r, 0x$g, 0x$b }, " - * done - * echo "" - * done - * done - */ - -static const rgb_triplet gif_clut[216] = { - { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff }, - { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff }, - { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff }, - { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff }, - { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff }, - { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff }, - { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff }, - { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff }, - { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff }, - { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff }, - { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff }, - { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff }, - { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff }, - { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff }, - { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff }, - { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff }, - { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff }, - { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff }, - { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff }, - { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff }, - { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff }, - { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff }, - { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff }, - { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff }, - { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff }, - { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff }, - { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff }, - { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff }, - { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff }, - { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff }, - { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff }, - { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff }, - { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff }, - { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff }, - { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff }, - { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff }, -}; - -/* GIF header */ static int gif_image_write_header(AVIOContext *pb, int width, int height, int loop_count, uint32_t *palette) { int i; - unsigned int v; avio_write(pb, "GIF", 3); avio_write(pb, "89a", 3); avio_wl16(pb, width); avio_wl16(pb, height); - avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */ - avio_w8(pb, 0x1f); /* background color index */ - avio_w8(pb, 0); /* aspect ratio */ - - /* the global palette */ - if (!palette) { - avio_write(pb, (const unsigned char *)gif_clut, 216 * 3); - for (i = 0; i < ((256 - 216) * 3); i++) - avio_w8(pb, 0); - } else { + if (palette) { + avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */ + avio_w8(pb, 0x1f); /* background color index */ + avio_w8(pb, 0); /* aspect ratio */ for (i = 0; i < 256; i++) { - v = palette[i]; - avio_w8(pb, (v >> 16) & 0xff); - avio_w8(pb, (v >> 8) & 0xff); - avio_w8(pb, (v) & 0xff); + const uint32_t v = palette[i] & 0xffffff; + avio_wb24(pb, v); } + } else { + avio_w8(pb, 0); /* flags */ + avio_w8(pb, 0); /* background color index */ + avio_w8(pb, 0); /* aspect ratio */ } - /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated - * GIF, see http://members.aol.com/royalef/gifabout.htm#net-extension - * - * byte 1 : 33 (hex 0x21) GIF Extension code - * byte 2 : 255 (hex 0xFF) Application Extension Label - * byte 3 : 11 (hex (0x0B) Length of Application Block - * (eleven bytes of data to follow) - * bytes 4 to 11 : "NETSCAPE" - * bytes 12 to 14 : "2.0" - * byte 15 : 3 (hex 0x03) Length of Data Sub-Block - * (three bytes of data to follow) - * byte 16 : 1 (hex 0x01) - * bytes 17 to 18 : 0 to 65535, an unsigned integer in - * lo-hi byte format. This indicate the - * number of iterations the loop should - * be executed. - * bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator - */ - /* application extension header */ -#ifdef GIF_ADD_APP_HEADER - if (loop_count >= 0 && loop_count <= 65535) { - avio_w8(pb, 0x21); - avio_w8(pb, 0xff); - avio_w8(pb, 0x0b); - // bytes 4 to 14 + if (loop_count >= 0 ) { + /* "NETSCAPE EXTENSION" for looped animation GIF */ + avio_w8(pb, 0x21); /* GIF Extension code */ + avio_w8(pb, 0xff); /* Application Extension Label */ + avio_w8(pb, 0x0b); /* Length of Application Block */ avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1); - avio_w8(pb, 0x03); // byte 15 - avio_w8(pb, 0x01); // byte 16 + avio_w8(pb, 0x03); /* Length of Data Sub-Block */ + avio_w8(pb, 0x01); avio_wl16(pb, (uint16_t)loop_count); - avio_w8(pb, 0x00); // byte 19 - } -#endif - return 0; -} - -/* this is maybe slow, but allows for extensions */ -static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b) -{ - return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6); -} - -static int gif_image_write_image(AVIOContext *pb, - int x1, int y1, int width, int height, - const uint8_t *buf, int linesize, int pix_fmt) -{ - PutBitContext p; - uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */ - int i, left, w, v; - const uint8_t *ptr; - /* image block */ - - avio_w8(pb, 0x2c); - avio_wl16(pb, x1); - avio_wl16(pb, y1); - avio_wl16(pb, width); - avio_wl16(pb, height); - avio_w8(pb, 0x00); /* flags */ - /* no local clut */ - - avio_w8(pb, 0x08); - - left = width * height; - - init_put_bits(&p, buffer, 130); - -/* - * the thing here is the bitstream is written as little packets, with a size - * byte before but it's still the same bitstream between packets (no flush !) - */ - ptr = buf; - w = width; - while (left > 0) { - put_bits(&p, 9, 0x0100); /* clear code */ - - for (i = (left < GIF_CHUNKS) ? left : GIF_CHUNKS; i; i--) { - if (pix_fmt == AV_PIX_FMT_RGB24) { - v = gif_clut_index(ptr[0], ptr[1], ptr[2]); - ptr += 3; - } else { - v = *ptr++; - } - put_bits(&p, 9, v); - if (--w == 0) { - w = width; - buf += linesize; - ptr = buf; - } - } - - if (left <= GIF_CHUNKS) { - put_bits(&p, 9, 0x101); /* end of stream */ - flush_put_bits(&p); - } - if (put_bits_ptr(&p) - p.buf > 0) { - avio_w8(pb, put_bits_ptr(&p) - p.buf); /* byte count of the packet */ - avio_write(pb, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */ - p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */ - } - left -= GIF_CHUNKS; + avio_w8(pb, 0x00); /* Data Sub-block Terminator */ } - avio_w8(pb, 0x00); /* end of image block */ return 0; } typedef struct { - AVClass *class; /** Class for private options. */ - int64_t time, file_time; - uint8_t buffer[100]; /* data chunks */ + AVClass *class; int loop; + int last_delay; + AVPacket *prev_pkt; + int duration; } GIFContext; static int gif_write_header(AVFormatContext *s) { GIFContext *gif = s->priv_data; AVIOContext *pb = s->pb; - AVCodecContext *enc, *video_enc; - int i, width, height /*, rate*/; - -/* XXX: do we reject audio streams or just ignore them ? - * if (s->nb_streams > 1) - * return -1; - */ - gif->time = 0; - gif->file_time = 0; + AVCodecContext *video_enc; + int width, height; + uint32_t palette[AVPALETTE_COUNT]; - video_enc = NULL; - for (i = 0; i < s->nb_streams; i++) { - enc = s->streams[i]->codec; - if (enc->codec_type != AVMEDIA_TYPE_AUDIO) - video_enc = enc; + if (s->nb_streams != 1 || + s->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO || + s->streams[0]->codec->codec_id != AV_CODEC_ID_GIF) { + av_log(s, AV_LOG_ERROR, + "GIF muxer supports only a single video GIF stream.\n"); + return AVERROR(EINVAL); } - if (!video_enc) { - av_free(gif); - return -1; - } else { - width = video_enc->width; - height = video_enc->height; -// rate = video_enc->time_base.den; - } + video_enc = s->streams[0]->codec; + width = video_enc->width; + height = video_enc->height; - if (video_enc->pix_fmt != AV_PIX_FMT_RGB24) { - av_log(s, AV_LOG_ERROR, - "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n"); - return AVERROR(EIO); + avpriv_set_pts_info(s->streams[0], 64, 1, 100); + if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) { + av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8); + gif_image_write_header(pb, width, height, gif->loop, NULL); + } else { + gif_image_write_header(pb, width, height, gif->loop, palette); } - gif_image_write_header(pb, width, height, gif->loop, NULL); - avio_flush(s->pb); return 0; } -static int gif_write_video(AVFormatContext *s, AVCodecContext *enc, - const uint8_t *buf, int size) +static int flush_packet(AVFormatContext *s, AVPacket *new) { + GIFContext *gif = s->priv_data; + int size; AVIOContext *pb = s->pb; - int jiffies; + uint8_t flags = 0x4, transparent_color_index = 0x1f; + const uint32_t *palette; + AVPacket *pkt = gif->prev_pkt; + + if (!pkt) + return 0; + + /* Mark one colour as transparent if the input palette contains at least + * one colour that is more than 50% transparent. */ + palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size); + if (palette && size != AVPALETTE_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n"); + return AVERROR_INVALIDDATA; + } + if (palette) { + unsigned i, smallest_alpha = 0xff; + + for (i = 0; i < AVPALETTE_COUNT; i++) { + const uint32_t v = palette[i]; + if (v >> 24 < smallest_alpha) { + smallest_alpha = v >> 24; + transparent_color_index = i; + } + } + if (smallest_alpha < 128) + flags |= 0x1; /* Transparent Color Flag */ + } + + if (new && new->pts != AV_NOPTS_VALUE) + gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts); + else if (!new && gif->last_delay >= 0) + gif->duration = gif->last_delay; /* graphic control extension block */ avio_w8(pb, 0x21); avio_w8(pb, 0xf9); avio_w8(pb, 0x04); /* block size */ - avio_w8(pb, 0x04); /* flags */ - - /* 1 jiffy is 1/70 s */ - /* the delay_time field indicates the number of jiffies - 1 */ - /* XXX: should use delay, in order to be more accurate */ - /* instead of using the same rounded value each time */ - /* XXX: don't even remember if I really use it for now */ - jiffies = (70 * enc->time_base.num / enc->time_base.den) - 1; - - avio_wl16(pb, jiffies); - - avio_w8(pb, 0x1f); /* transparent color index */ + avio_w8(pb, flags); + avio_wl16(pb, gif->duration); + avio_w8(pb, transparent_color_index); avio_w8(pb, 0x00); - gif_image_write_image(pb, 0, 0, enc->width, enc->height, - buf, enc->width * 3, AV_PIX_FMT_RGB24); + avio_write(pb, pkt->data, pkt->size); + + av_free_packet(gif->prev_pkt); + if (new) + av_copy_packet(gif->prev_pkt, new); - avio_flush(s->pb); return 0; } static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) { - AVCodecContext *codec = s->streams[pkt->stream_index]->codec; - if (codec->codec_type == AVMEDIA_TYPE_AUDIO) - return 0; /* just ignore audio */ - else - return gif_write_video(s, codec, pkt->data, pkt->size); + GIFContext *gif = s->priv_data; + + if (!gif->prev_pkt) { + gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt)); + if (!gif->prev_pkt) + return AVERROR(ENOMEM); + return av_copy_packet(gif->prev_pkt, pkt); + } + return flush_packet(s, pkt); } static int gif_write_trailer(AVFormatContext *s) { + GIFContext *gif = s->priv_data; AVIOContext *pb = s->pb; + flush_packet(s, NULL); + av_freep(&gif->prev_pkt); avio_w8(pb, 0x3b); return 0; @@ -354,8 +192,10 @@ static int gif_write_trailer(AVFormatContext *s) #define OFFSET(x) offsetof(GIFContext, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "loop", "Number of times to loop the output.", OFFSET(loop), - AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 65535, ENC }, + { "loop", "Number of times to loop the output: -1 - no loop, 0 - infinite loop", OFFSET(loop), + AV_OPT_TYPE_INT, { .i64 = 0 }, -1, 65535, ENC }, + { "final_delay", "Force delay (in centiseconds) after the last frame", OFFSET(last_delay), + AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC }, { NULL }, }; @@ -373,9 +213,10 @@ AVOutputFormat ff_gif_muxer = { .extensions = "gif", .priv_data_size = sizeof(GIFContext), .audio_codec = AV_CODEC_ID_NONE, - .video_codec = AV_CODEC_ID_RAWVIDEO, + .video_codec = AV_CODEC_ID_GIF, .write_header = gif_write_header, .write_packet = gif_write_packet, .write_trailer = gif_write_trailer, .priv_class = &gif_muxer_class, + .flags = AVFMT_VARIABLE_FPS, }; diff --git a/ffmpeg/libavformat/gifdec.c b/ffmpeg/libavformat/gifdec.c index 1122849..2981bca 100644 --- a/ffmpeg/libavformat/gifdec.c +++ b/ffmpeg/libavformat/gifdec.c @@ -44,6 +44,13 @@ typedef struct GIFDemuxContext { */ int min_delay; int default_delay; + + /** + * loop options + */ + int total_iter; + int iter_count; + int ignore_loop; } GIFDemuxContext; /** @@ -156,6 +163,27 @@ static int gif_read_ext(AVFormatContext *s) /* skip the rest of the Graphic Control Extension block */ if ((ret = avio_skip(pb, sb_size - 3)) < 0 ) return ret; + } else if (ext_label == GIF_APP_EXT_LABEL) { + uint8_t data[256]; + + sb_size = avio_r8(pb); + ret = avio_read(pb, data, sb_size); + if (ret < 0 || !sb_size) + return ret; + + if (sb_size == strlen(NETSCAPE_EXT_STR)) { + sb_size = avio_r8(pb); + ret = avio_read(pb, data, sb_size); + if (ret < 0 || !sb_size) + return ret; + + if (sb_size == 3 && data[0] == 1) { + gdc->total_iter = AV_RL16(data+1); + + if (gdc->total_iter == 0) + gdc->total_iter = -1; + } + } } if ((ret = gif_skip_subblocks(pb)) < 0) @@ -268,9 +296,12 @@ resync: } } - if (ret >= 0 && !frame_parsed) { + if ((ret >= 0 && !frame_parsed) || ret == AVERROR_EOF) { /* This might happen when there is no image block * between extension blocks and GIF_TRAILER or EOF */ + if (!gdc->ignore_loop && (block_label == GIF_TRAILER || url_feof(pb)) + && (gdc->total_iter < 0 || ++gdc->iter_count < gdc->total_iter)) + return avio_seek(pb, 0, SEEK_SET); return AVERROR_EOF; } else return ret; @@ -279,6 +310,7 @@ resync: static const AVOption options[] = { { "min_delay" , "minimum valid delay between frames (in hundredths of second)", offsetof(GIFDemuxContext, min_delay) , AV_OPT_TYPE_INT, {.i64 = GIF_MIN_DELAY} , 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM }, { "default_delay", "default delay between frames (in hundredths of second)" , offsetof(GIFDemuxContext, default_delay), AV_OPT_TYPE_INT, {.i64 = GIF_DEFAULT_DELAY}, 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM }, + { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext, ignore_loop) , AV_OPT_TYPE_INT, {.i64 = 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM }, { NULL }, }; diff --git a/ffmpeg/libavformat/gsmdec.c b/ffmpeg/libavformat/gsmdec.c index 9899266..dbe557b 100644 --- a/ffmpeg/libavformat/gsmdec.c +++ b/ffmpeg/libavformat/gsmdec.c @@ -2,20 +2,20 @@ * RAW GSM demuxer * Copyright (c) 2011 Justin Ruggles * - * 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 */ @@ -80,7 +80,7 @@ static const AVOption options[] = { { NULL }, }; -static const AVClass class = { +static const AVClass gsm_class = { .class_name = "gsm demuxer", .item_name = av_default_item_name, .option = options, @@ -96,5 +96,5 @@ AVInputFormat ff_gsm_demuxer = { .flags = AVFMT_GENERIC_INDEX, .extensions = "gsm", .raw_codec_id = AV_CODEC_ID_GSM, - .priv_class = &class, + .priv_class = &gsm_class, }; diff --git a/ffmpeg/libavformat/gxf.c b/ffmpeg/libavformat/gxf.c index 86e6291..c36479a 100644 --- a/ffmpeg/libavformat/gxf.c +++ b/ffmpeg/libavformat/gxf.c @@ -116,12 +116,10 @@ static int get_sindex(AVFormatContext *s, int id, int format) { st->codec->codec_id = AV_CODEC_ID_MJPEG; break; case 13: - case 15: - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = AV_CODEC_ID_DVVIDEO; - break; case 14: + case 15: case 16: + case 25: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_DVVIDEO; break; @@ -165,6 +163,12 @@ static int get_sindex(AVFormatContext *s, int id, int format) { st->codec->channel_layout = AV_CH_LAYOUT_STEREO; st->codec->sample_rate = 48000; break; + case 26: /* AVCi50 / AVCi100 (AVC Intra) */ + case 29: /* AVCHD */ + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_H264; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + break; // timecode tracks: case 7: case 8: @@ -172,6 +176,10 @@ static int get_sindex(AVFormatContext *s, int id, int format) { st->codec->codec_type = AVMEDIA_TYPE_DATA; st->codec->codec_id = AV_CODEC_ID_NONE; break; + case 30: + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_DNXHD; + break; default: st->codec->codec_type = AVMEDIA_TYPE_UNKNOWN; st->codec->codec_id = AV_CODEC_ID_NONE; diff --git a/ffmpeg/libavformat/gxfenc.c b/ffmpeg/libavformat/gxfenc.c index 28acb74..12031f7 100644 --- a/ffmpeg/libavformat/gxfenc.c +++ b/ffmpeg/libavformat/gxfenc.c @@ -217,12 +217,27 @@ static int gxf_write_mpeg_auxiliary(AVIOContext *pb, AVStream *st) return size + 3; } +static int gxf_write_dv_auxiliary(AVIOContext *pb, AVStream *st) +{ + int64_t track_aux_data = 0; + + avio_w8(pb, TRACK_AUX); + avio_w8(pb, 8); + if (st->codec->pix_fmt == AV_PIX_FMT_YUV420P) + track_aux_data |= 0x01; /* marks stream as DVCAM instead of DVPRO */ + track_aux_data |= 0x40000000; /* aux data is valid */ + avio_wl64(pb, track_aux_data); + return 8; +} + static int gxf_write_timecode_auxiliary(AVIOContext *pb, GXFContext *gxf) { uint32_t timecode = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop, gxf->tc.hh, gxf->tc.mm, gxf->tc.ss, gxf->tc.ff); + avio_w8(pb, TRACK_AUX); + avio_w8(pb, 8); avio_wl32(pb, timecode); /* reserved */ avio_wl32(pb, 0); @@ -234,7 +249,6 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc, GXFContext *gxf = s->priv_data; AVIOContext *pb = s->pb; int64_t pos; - int mpeg = sc->track_type == 4 || sc->track_type == 9; /* track description section */ avio_w8(pb, sc->media_type + 0x80); @@ -250,13 +264,21 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc, avio_wb16(pb, sc->media_info); avio_w8(pb, 0); - if (!mpeg) { - /* auxiliary information */ - avio_w8(pb, TRACK_AUX); - avio_w8(pb, 8); - if (sc->track_type == 3) + switch (sc->track_type) { + case 3: /* timecode */ gxf_write_timecode_auxiliary(pb, gxf); - else + break; + case 4: /* MPEG2 */ + case 9: /* MPEG1 */ + gxf_write_mpeg_auxiliary(pb, s->streams[index]); + break; + case 5: /* DV25 */ + case 6: /* DV50 */ + gxf_write_dv_auxiliary(pb, s->streams[index]); + break; + default: + avio_w8(pb, TRACK_AUX); + avio_w8(pb, 8); avio_wl64(pb, 0); } @@ -265,9 +287,6 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc, avio_w8(pb, 4); avio_wb32(pb, 0); - if (mpeg) - gxf_write_mpeg_auxiliary(pb, s->streams[index]); - /* frame rate */ avio_w8(pb, TRACK_FPS); avio_w8(pb, 4); @@ -362,12 +381,13 @@ static int gxf_write_map_packet(AVFormatContext *s, int rewrite) if (!rewrite) { if (!(gxf->map_offsets_nb % 30)) { - gxf->map_offsets = av_realloc_f(gxf->map_offsets, - sizeof(*gxf->map_offsets), - gxf->map_offsets_nb+30); - if (!gxf->map_offsets) { + int err; + if ((err = av_reallocp_array(&gxf->map_offsets, + gxf->map_offsets_nb + 30, + sizeof(*gxf->map_offsets))) < 0) { + gxf->map_offsets_nb = 0; av_log(s, AV_LOG_ERROR, "could not realloc map offsets\n"); - return -1; + return err; } } gxf->map_offsets[gxf->map_offsets_nb++] = pos; // do not increment here @@ -534,13 +554,20 @@ static int gxf_write_umf_media_timecode(AVIOContext *pb, int drop) return 32; } -static int gxf_write_umf_media_dv(AVIOContext *pb, GXFStreamContext *sc) +static int gxf_write_umf_media_dv(AVIOContext *pb, GXFStreamContext *sc, AVStream *st) { - int i; + int dv_umf_data = 0; - for (i = 0; i < 8; i++) { - avio_wb32(pb, 0); - } + if (st->codec->pix_fmt == AV_PIX_FMT_YUV420P) + dv_umf_data |= 0x20; /* marks as DVCAM instead of DVPRO */ + avio_wl32(pb, dv_umf_data); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); return 32; } @@ -604,7 +631,7 @@ static int gxf_write_umf_media_description(AVFormatContext *s) gxf_write_umf_media_audio(pb, sc); break; case AV_CODEC_ID_DVVIDEO: - gxf_write_umf_media_dv(pb, sc); + gxf_write_umf_media_dv(pb, sc, st); break; } } @@ -681,6 +708,7 @@ static int gxf_write_header(AVFormatContext *s) GXFStreamContext *vsc = NULL; uint8_t tracks[255] = {0}; int i, media_info = 0; + int ret; AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0); if (!pb->seekable) { @@ -801,7 +829,8 @@ static int gxf_write_header(AVFormatContext *s) gxf_init_timecode_track(&gxf->timecode_track, vsc); gxf->flags |= 0x200000; // time code track is non-drop frame - gxf_write_map_packet(s, 0); + if ((ret = gxf_write_map_packet(s, 0)) < 0) + return ret; gxf_write_flt_packet(s); gxf_write_umf_packet(s); @@ -825,6 +854,7 @@ static int gxf_write_trailer(AVFormatContext *s) AVIOContext *pb = s->pb; int64_t end; int i; + int ret; ff_audio_interleave_close(s); @@ -832,14 +862,16 @@ static int gxf_write_trailer(AVFormatContext *s) end = avio_tell(pb); avio_seek(pb, 0, SEEK_SET); /* overwrite map, flt and umf packets with new values */ - gxf_write_map_packet(s, 1); + if ((ret = gxf_write_map_packet(s, 1)) < 0) + return ret; gxf_write_flt_packet(s); gxf_write_umf_packet(s); avio_flush(pb); /* update duration in all map packets */ for (i = 1; i < gxf->map_offsets_nb; i++) { avio_seek(pb, gxf->map_offsets[i], SEEK_SET); - gxf_write_map_packet(s, 1); + if ((ret = gxf_write_map_packet(s, 1)) < 0) + return ret; avio_flush(pb); } @@ -917,7 +949,8 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt) AVStream *st = s->streams[pkt->stream_index]; int64_t pos = avio_tell(pb); int padding = 0; - int packet_start_offset = avio_tell(pb) / 1024; + unsigned packet_start_offset = avio_tell(pb) / 1024; + int ret; gxf_write_packet_header(pb, PKT_MEDIA); if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO && pkt->size % 4) /* MPEG-2 frames must be padded */ @@ -930,12 +963,14 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt) if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if (!(gxf->flt_entries_nb % 500)) { - gxf->flt_entries = av_realloc_f(gxf->flt_entries, - sizeof(*gxf->flt_entries), - gxf->flt_entries_nb+500); - if (!gxf->flt_entries) { + int err; + if ((err = av_reallocp_array(&gxf->flt_entries, + gxf->flt_entries_nb + 500, + sizeof(*gxf->flt_entries))) < 0) { + gxf->flt_entries_nb = 0; + gxf->nb_fields = 0; av_log(s, AV_LOG_ERROR, "could not reallocate flt entries\n"); - return -1; + return err; } } gxf->flt_entries[gxf->flt_entries_nb++] = packet_start_offset; @@ -946,12 +981,11 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt) gxf->packet_count++; if (gxf->packet_count == 100) { - gxf_write_map_packet(s, 0); + if ((ret = gxf_write_map_packet(s, 0)) < 0) + return ret; gxf->packet_count = 0; } - avio_flush(pb); - return 0; } diff --git a/ffmpeg/libavformat/h261dec.c b/ffmpeg/libavformat/h261dec.c index 1b254d6..a1d6821 100644 --- a/ffmpeg/libavformat/h261dec.c +++ b/ffmpeg/libavformat/h261dec.c @@ -25,40 +25,37 @@ static int h261_probe(AVProbeData *p) { - uint32_t code= -1; int i; int valid_psc=0; int invalid_psc=0; int next_gn=0; int src_fmt=0; - GetBitContext gb; - init_get_bits(&gb, p->buf, p->buf_size*8); + for(i=0; i<p->buf_size; i++){ + if ((AV_RB16(&p->buf[i]) - 1) < 0xFFU) { + int shift = av_log2_16bit(p->buf[i+1]); + uint32_t code = AV_RB64(&p->buf[FFMAX(i-1, 0)]) >> (24+shift); + if ((code & 0xffff0000) == 0x10000) { + int gn= (code>>12)&0xf; + if(!gn) + src_fmt= code&8; + if(gn != next_gn) invalid_psc++; + else valid_psc++; - for(i=0; i<p->buf_size*8; i++){ - if ((code & 0x01ff0000) || !(code & 0xff00)) { - code = (code<<8) + get_bits(&gb, 8); - i += 7; - } else - code = (code<<1) + get_bits1(&gb); - if ((code & 0xffff0000) == 0x10000) { - int gn= (code>>12)&0xf; - if(!gn) - src_fmt= code&8; - if(gn != next_gn) invalid_psc++; - else valid_psc++; - - if(src_fmt){ // CIF - next_gn= (gn+1 )%13; - }else{ //QCIF - next_gn= (gn+1+!!gn)% 7; + if(src_fmt){ // CIF + static const int lut[16]={1,2,3,4,5,6,7,8,9,10,11,12,0,16,16,16}; + next_gn = lut[gn]; + }else{ //QCIF + static const int lut[16]={1,3,16,5,16,0,16,16,16,16,16,16,16,16,16,16}; + next_gn = lut[gn]; + } } } } if(valid_psc > 2*invalid_psc + 6){ - return 50; + return AVPROBE_SCORE_EXTENSION; }else if(valid_psc > 2*invalid_psc + 2) - return 25; + return AVPROBE_SCORE_EXTENSION / 2; return 0; } diff --git a/ffmpeg/libavformat/h263dec.c b/ffmpeg/libavformat/h263dec.c index 667fdbd..e6e0345 100644 --- a/ffmpeg/libavformat/h263dec.c +++ b/ffmpeg/libavformat/h263dec.c @@ -56,9 +56,9 @@ static int h263_probe(AVProbeData *p) } } if(valid_psc > 2*invalid_psc + 2*res_change + 3){ - return 50; + return AVPROBE_SCORE_EXTENSION; }else if(valid_psc > 2*invalid_psc) - return 25; + return AVPROBE_SCORE_EXTENSION / 2; return 0; } diff --git a/ffmpeg/libavformat/h264dec.c b/ffmpeg/libavformat/h264dec.c index 9c67ab9..76073dd 100644 --- a/ffmpeg/libavformat/h264dec.c +++ b/ffmpeg/libavformat/h264dec.c @@ -24,47 +24,55 @@ static int h264_probe(AVProbeData *p) { - uint32_t code= -1; - int sps=0, pps=0, idr=0, res=0, sli=0; + uint32_t code = -1; + int sps = 0, pps = 0, idr = 0, res = 0, sli = 0; int i; - for(i=0; i<p->buf_size; i++){ - code = (code<<8) + p->buf[i]; + for (i = 0; i < p->buf_size; i++) { + code = (code << 8) + p->buf[i]; if ((code & 0xffffff00) == 0x100) { - int ref_idc= (code>>5)&3; - int type = code & 0x1F; - static const int8_t ref_zero[32]={ - 2, 0, 0, 0, 0,-1, 1,-1, - -1, 1, 1, 1, 1,-1, 2, 2, - 2, 2, 2, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2 + int ref_idc = (code >> 5) & 3; + int type = code & 0x1F; + static const int8_t ref_zero[] = { + 2, 0, 0, 0, 0, -1, 1, -1, + -1, 1, 1, 1, 1, -1, 2, 2, + 2, 2, 2, 0, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2 }; - if(code & 0x80) //forbidden bit + if (code & 0x80) // forbidden_bit return 0; - if(ref_zero[type] == 1 && ref_idc) + if (ref_zero[type] == 1 && ref_idc) return 0; - if(ref_zero[type] ==-1 && !ref_idc) + if (ref_zero[type] == -1 && !ref_idc) return 0; - if(ref_zero[type] == 2) + if (ref_zero[type] == 2) res++; - switch(type){ - case 1: sli++; break; - case 5: idr++; break; - case 7: + switch (type) { + case 1: + sli++; + break; + case 5: + idr++; + break; + case 7: if (p->buf[i + 2] & 0x03) return 0; sps++; break; - case 8: pps++; break; + case 8: + pps++; + break; } } } - if(sps && pps && (idr||sli>3) && res<(sps+pps+idr)) - return AVPROBE_SCORE_MAX/2+1; // +1 for .mpg + + if (sps && pps && (idr || sli > 3) && res < (sps + pps + idr)) + return AVPROBE_SCORE_EXTENSION + 1; // 1 more than .mpg + return 0; } -FF_DEF_RAWVIDEO_DEMUXER(h264 , "raw H.264 video", h264_probe, "h26l,h264,264", AV_CODEC_ID_H264) +FF_DEF_RAWVIDEO_DEMUXER(h264, "raw H.264 video", h264_probe, "h26l,h264,264,avc", AV_CODEC_ID_H264) diff --git a/ffmpeg/libavformat/hls.c b/ffmpeg/libavformat/hls.c index 7de6059..471a62d 100644 --- a/ffmpeg/libavformat/hls.c +++ b/ffmpeg/libavformat/hls.c @@ -56,7 +56,7 @@ enum KeyType { }; struct segment { - int duration; + int64_t duration; char url[MAX_URL_SIZE]; char key[MAX_URL_SIZE]; enum KeyType key_type; @@ -81,7 +81,7 @@ struct variant { int stream_offset; int finished; - int target_duration; + int64_t target_duration; int start_seq_no; int n_segments; struct segment **segments; @@ -105,6 +105,7 @@ typedef struct HLSContext { AVIOInterruptCB *interrupt_callback; char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context + char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context } HLSContext; static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) @@ -206,24 +207,27 @@ static void handle_key_args(struct key_info *info, const char *key, static int parse_playlist(HLSContext *c, const char *url, struct variant *var, AVIOContext *in) { - int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; + int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; + int64_t duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; - char line[1024]; + char line[MAX_URL_SIZE]; const char *ptr; int close_in = 0; + uint8_t *new_url = NULL; if (!in) { AVDictionary *opts = NULL; close_in = 1; - /* Some HLS servers dont like being sent the range header */ + /* Some HLS servers don't like being sent the range header */ av_dict_set(&opts, "seekable", "0", 0); // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user-agent", c->user_agent, 0); av_dict_set(&opts, "cookies", c->cookies, 0); + av_dict_set(&opts, "headers", c->headers, 0); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); @@ -232,6 +236,9 @@ static int parse_playlist(HLSContext *c, const char *url, return ret; } + if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) + url = new_url; + read_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; @@ -271,7 +278,7 @@ static int parse_playlist(HLSContext *c, const char *url, goto fail; } } - var->target_duration = atoi(ptr); + var->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { if (!var) { var = new_variant(c, 0, url, NULL); @@ -286,7 +293,7 @@ static int parse_playlist(HLSContext *c, const char *url, var->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; - duration = atoi(ptr); + duration = atof(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { @@ -332,6 +339,7 @@ static int parse_playlist(HLSContext *c, const char *url, var->last_load_time = av_gettime(); fail: + av_free(new_url); if (close_in) avio_close(in); return ret; @@ -346,6 +354,7 @@ static int open_input(HLSContext *c, struct variant *var) // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user-agent", c->user_agent, 0); av_dict_set(&opts, "cookies", c->cookies, 0); + av_dict_set(&opts, "headers", c->headers, 0); av_dict_set(&opts, "seekable", "0", 0); if (seg->key_type == KEY_NONE) { @@ -413,7 +422,6 @@ restart: int64_t reload_interval = v->n_segments > 0 ? v->segments[v->n_segments - 1]->duration : v->target_duration; - reload_interval *= 1000000; reload: if (!v->finished && @@ -423,7 +431,7 @@ reload: /* If we need to reload the playlist again below (if * there's still no more segments), switch to a reload * interval of half the target duration. */ - reload_interval = v->target_duration * 500000LL; + reload_interval = v->target_duration / 2; } if (v->cur_seq_no < v->start_seq_no) { av_log(NULL, AV_LOG_WARNING, @@ -457,7 +465,8 @@ reload: c->end_of_segment = 1; c->cur_seq_no = v->cur_seq_no; - if (v->ctx && v->ctx->nb_streams && v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { + if (v->ctx && v->ctx->nb_streams && + v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { v->needed = 0; for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; i++) { @@ -494,6 +503,12 @@ static int hls_read_header(AVFormatContext *s) av_opt_get(u->priv_data, "cookies", 0, (uint8_t**)&(c->cookies)); if (c->cookies && !strlen(c->cookies)) av_freep(&c->cookies); + + // get the previous headers & set back to null if string size is zero + av_freep(&c->headers); + av_opt_get(u->priv_data, "headers", 0, (uint8_t**)&(c->headers)); + if (c->headers && !strlen(c->headers)) + av_freep(&c->headers); } if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) @@ -526,7 +541,7 @@ static int hls_read_header(AVFormatContext *s) int64_t duration = 0; for (i = 0; i < c->variants[0]->n_segments; i++) duration += c->variants[0]->segments[i]->duration; - s->duration = duration * AV_TIME_BASE; + s->duration = duration; } /* Open the demuxer for each variant */ @@ -534,7 +549,8 @@ static int hls_read_header(AVFormatContext *s) struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; - AVProgram *program = NULL; + AVProgram *program; + if (v->n_segments == 0) continue; @@ -570,18 +586,17 @@ static int hls_read_header(AVFormatContext *s) goto fail; } v->ctx->pb = &v->pb; + v->stream_offset = stream_offset; ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; - v->stream_offset = stream_offset; v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; ret = avformat_find_stream_info(v->ctx, NULL); if (ret < 0) goto fail; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); - /* Create new AVprogram for variant i */ program = av_new_program(s, i); if (!program) goto fail; @@ -678,8 +693,11 @@ start: reset_packet(&var->pkt); break; } else { - if (c->first_timestamp == AV_NOPTS_VALUE) - c->first_timestamp = var->pkt.dts; + if (c->first_timestamp == AV_NOPTS_VALUE && + var->pkt.dts != AV_NOPTS_VALUE) + c->first_timestamp = av_rescale_q(var->pkt.dts, + var->ctx->streams[var->pkt.stream_index]->time_base, + AV_TIME_BASE_Q); } if (c->seek_timestamp == AV_NOPTS_VALUE) @@ -699,24 +717,35 @@ start: c->seek_timestamp = AV_NOPTS_VALUE; break; } + av_free_packet(&var->pkt); + reset_packet(&var->pkt); } } - /* Check if this stream has the packet with the lowest dts */ + /* Check if this stream still is on an earlier segment number, or + * has the packet with the lowest dts */ if (var->pkt.data) { - if(minvariant < 0) { + struct variant *minvar = minvariant < 0 ? + NULL : c->variants[minvariant]; + if (minvariant < 0 || var->cur_seq_no < minvar->cur_seq_no) { minvariant = i; - } else { - struct variant *minvar = c->variants[minvariant]; - int64_t dts = var->pkt.dts; - int64_t mindts = minvar->pkt.dts; - AVStream *st = var->ctx->streams[ var->pkt.stream_index]; - AVStream *minst= minvar->ctx->streams[minvar->pkt.stream_index]; + } else if (var->cur_seq_no == minvar->cur_seq_no) { + int64_t dts = var->pkt.dts; + int64_t mindts = minvar->pkt.dts; + AVStream *st = var->ctx->streams[var->pkt.stream_index]; + AVStream *minst = minvar->ctx->streams[minvar->pkt.stream_index]; - if( st->start_time != AV_NOPTS_VALUE) dts -= st->start_time; - if(minst->start_time != AV_NOPTS_VALUE) mindts -= minst->start_time; - - if (av_compare_ts(dts, st->time_base, mindts, minst->time_base) < 0) + if (dts == AV_NOPTS_VALUE) { minvariant = i; + } else if (mindts != AV_NOPTS_VALUE) { + if (st->start_time != AV_NOPTS_VALUE) + dts -= st->start_time; + if (minst->start_time != AV_NOPTS_VALUE) + mindts -= minst->start_time; + + if (av_compare_ts(dts, st->time_base, + mindts, minst->time_base) < 0) + minvariant = i; + } } } } @@ -757,7 +786,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, s->streams[stream_index]->time_base.den, flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); - timestamp = av_rescale_rnd(timestamp, 1, stream_index >= 0 ? + timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, stream_index >= 0 ? s->streams[stream_index]->time_base.den : AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? AV_ROUND_DOWN : AV_ROUND_UP); @@ -770,12 +799,9 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, for (i = 0; i < c->n_variants; i++) { /* Reset reading */ struct variant *var = c->variants[i]; - int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? 0 : - av_rescale_rnd(c->first_timestamp, 1, stream_index >= 0 ? - s->streams[stream_index]->time_base.den : - AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ? - AV_ROUND_DOWN : AV_ROUND_UP); - if (var->input) { + int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ? + 0 : c->first_timestamp; + if (var->input) { ffurl_close(var->input); var->input = NULL; } diff --git a/ffmpeg/libavformat/hlsenc.c b/ffmpeg/libavformat/hlsenc.c index 18914c0..3b50397 100644 --- a/ffmpeg/libavformat/hlsenc.c +++ b/ffmpeg/libavformat/hlsenc.c @@ -20,6 +20,7 @@ */ #include <float.h> +#include <stdint.h> #include "libavutil/mathematics.h" #include "libavutil/parseutils.h" @@ -49,7 +50,7 @@ typedef struct HLSContext { int has_video; int64_t start_pts; int64_t end_pts; - int64_t duration; ///< last segment duration computed so far, in seconds + int64_t duration; // last segment duration computed so far, in seconds int nb_entries; ListEntry *list; ListEntry *end_list; @@ -69,6 +70,7 @@ static int hls_mux_init(AVFormatContext *s) oc->oformat = hls->oformat; oc->interrupt_callback = s->interrupt_callback; + av_dict_copy(&oc->metadata, s->metadata, 0); for (i = 0; i < s->nb_streams; i++) { AVStream *st; @@ -164,14 +166,12 @@ static int hls_start(AVFormatContext *s) AVFormatContext *oc = c->avf; int err = 0; - if (c->wrap) - c->number %= c->wrap; - if (av_get_frame_filename(oc->filename, sizeof(oc->filename), - c->basename, c->number++) < 0) { + c->basename, c->wrap ? c->number % c->wrap : c->number) < 0) { av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename); return AVERROR(EINVAL); } + c->number++; if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) @@ -253,25 +253,28 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) AVFormatContext *oc = hls->avf; AVStream *st = s->streams[pkt->stream_index]; int64_t end_pts = hls->recording_time * hls->number; - int ret, is_ref_pkt = 0; + int is_ref_pkt = 1; + int ret, can_split = 1; if (hls->start_pts == AV_NOPTS_VALUE) { hls->start_pts = pkt->pts; hls->end_pts = pkt->pts; } - if ((hls->has_video && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) && - pkt->pts != AV_NOPTS_VALUE) { - is_ref_pkt = 1; - hls->duration = av_rescale(pkt->pts - hls->end_pts, - st->time_base.num, st->time_base.den); + if (hls->has_video) { + can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO && + pkt->flags & AV_PKT_FLAG_KEY; + is_ref_pkt = st->codec->codec_type == AVMEDIA_TYPE_VIDEO; } + if (pkt->pts == AV_NOPTS_VALUE) + is_ref_pkt = can_split = 0; - if (is_ref_pkt && - av_compare_ts(pkt->pts - hls->start_pts, st->time_base, - end_pts, AV_TIME_BASE_Q) >= 0 && - pkt->flags & AV_PKT_FLAG_KEY) { + if (is_ref_pkt) + hls->duration = av_rescale(pkt->pts - hls->end_pts, + st->time_base.num, st->time_base.den); + if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base, + end_pts, AV_TIME_BASE_Q) >= 0) { ret = append_entry(hls, hls->duration); if (ret) return ret; diff --git a/ffmpeg/libavformat/hlsproto.c b/ffmpeg/libavformat/hlsproto.c index 4e35043..f6fcbe5 100644 --- a/ffmpeg/libavformat/hlsproto.c +++ b/ffmpeg/libavformat/hlsproto.c @@ -45,7 +45,7 @@ */ struct segment { - int duration; + int64_t duration; char url[MAX_URL_SIZE]; }; @@ -56,7 +56,7 @@ struct variant { typedef struct HLSContext { char playlisturl[MAX_URL_SIZE]; - int target_duration; + int64_t target_duration; int start_seq_no; int finished; int n_segments; @@ -111,7 +111,8 @@ static int parse_playlist(URLContext *h, const char *url) { HLSContext *s = h->priv_data; AVIOContext *in; - int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; + int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0; + int64_t duration = 0; char line[1024]; const char *ptr; @@ -134,14 +135,14 @@ static int parse_playlist(URLContext *h, const char *url) &info); bandwidth = atoi(info.bandwidth); } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { - s->target_duration = atoi(ptr); + s->target_duration = atoi(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { s->start_seq_no = atoi(ptr); } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { s->finished = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; - duration = atoi(ptr); + duration = atof(ptr) * AV_TIME_BASE; } else if (av_strstart(line, "#", NULL)) { continue; } else if (line[0]) { @@ -270,7 +271,6 @@ start: reload_interval = s->n_segments > 0 ? s->segments[s->n_segments - 1]->duration : s->target_duration; - reload_interval *= 1000000; retry: if (!s->finished) { int64_t now = av_gettime(); @@ -280,7 +280,7 @@ retry: /* If we need to reload the playlist again below (if * there's still no more segments), switch to a reload * interval of half the target duration. */ - reload_interval = s->target_duration * 500000LL; + reload_interval = s->target_duration / 2; } } if (s->cur_seq_no < s->start_seq_no) { diff --git a/ffmpeg/libavformat/http.c b/ffmpeg/libavformat/http.c index 1e3cff7..0619e2a 100644 --- a/ffmpeg/libavformat/http.c +++ b/ffmpeg/libavformat/http.c @@ -29,6 +29,10 @@ #include "url.h" #include "libavutil/opt.h" +#if CONFIG_ZLIB +#include <zlib.h> +#endif + /* XXX: POST protocol is not completely implemented because ffmpeg uses only a subset of it. */ @@ -49,7 +53,9 @@ typedef struct { char *content_type; char *user_agent; int64_t off, filesize; - char location[MAX_URL_SIZE]; + int icy_data_read; ///< how much data was read since last ICY metadata packet + int icy_metaint; ///< after how many bytes of read data a new metadata packet will be found + char *location; HTTPAuthState auth_state; HTTPAuthState proxy_auth_state; char *headers; @@ -62,26 +68,43 @@ typedef struct { uint8_t *post_data; int post_datalen; int is_akamai; - int rw_timeout; + int is_mediagateway; char *mime_type; char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name) + int icy; + char *icy_metadata_headers; + char *icy_metadata_packet; +#if CONFIG_ZLIB + int compressed; + z_stream inflate_stream; + uint8_t *inflate_buffer; +#endif + AVDictionary *chained_options; + int send_expect_100; } HTTPContext; #define OFFSET(x) offsetof(HTTPContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM -#define DEC AV_OPT_FLAG_DECODING_PARAM +#define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION) static const AVOption options[] = { {"seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, D }, {"chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, {"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, {"content_type", "force a content type", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, -{"user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC}, +{"user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = DEFAULT_USER_AGENT}, 0, 0, D }, {"multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, {"post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D|E }, -{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, {"mime_type", "set MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, -{"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, +{"cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, {0}, 0, 0, D }, +{"icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, +{"icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, +{"icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, {0}, 0, 0, 0 }, +{"auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, {.i64 = HTTP_AUTH_NONE}, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D|E, "auth_type" }, +{"none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_NONE}, 0, 0, D|E, "auth_type" }, +{"basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, {.i64 = HTTP_AUTH_BASIC}, 0, 0, D|E, "auth_type" }, +{"send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E }, +{"location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E }, {NULL} }; #define HTTP_CLASS(flavor)\ @@ -109,7 +132,7 @@ void ff_http_init_auth_state(URLContext *dest, const URLContext *src) } /* return non zero if error */ -static int http_open_cnx(URLContext *h) +static int http_open_cnx(URLContext *h, AVDictionary **options) { const char *path, *proxy_path, *lower_proto = "tcp", *local_path; char hostname[1024], hoststr[1024], proto[10]; @@ -159,15 +182,8 @@ static int http_open_cnx(URLContext *h) ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL); if (!s->hd) { - AVDictionary *opts = NULL; - char opts_format[20]; - if (s->rw_timeout != -1) { - snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout); - av_dict_set(&opts, "timeout", opts_format, 0); - } /* if option is not given, don't pass it and let tcp use its own default */ err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE, - &h->interrupt_callback, &opts); - av_dict_free(&opts); + &h->interrupt_callback, options); if (err < 0) goto fail; } @@ -216,16 +232,27 @@ static int http_open_cnx(URLContext *h) int ff_http_do_new_request(URLContext *h, const char *uri) { HTTPContext *s = h->priv_data; + AVDictionary *options = NULL; + int ret; s->off = 0; - av_strlcpy(s->location, uri, sizeof(s->location)); - - return http_open_cnx(h); + s->icy_data_read = 0; + av_free(s->location); + s->location = av_strdup(uri); + if (!s->location) + return AVERROR(ENOMEM); + + av_dict_copy(&options, s->chained_options, 0); + ret = http_open_cnx(h, &options); + av_dict_free(&options); + return ret; } -static int http_open(URLContext *h, const char *uri, int flags) +static int http_open(URLContext *h, const char *uri, int flags, + AVDictionary **options) { HTTPContext *s = h->priv_data; + int ret; if( s->seekable == 1 ) h->is_streamed = 0; @@ -233,7 +260,11 @@ static int http_open(URLContext *h, const char *uri, int flags) h->is_streamed = 1; s->filesize = -1; - av_strlcpy(s->location, uri, sizeof(s->location)); + s->location = av_strdup(uri); + if (!s->location) + return AVERROR(ENOMEM); + if (options) + av_dict_copy(&s->chained_options, *options, 0); if (s->headers) { int len = strlen(s->headers); @@ -241,7 +272,10 @@ static int http_open(URLContext *h, const char *uri, int flags) av_log(h, AV_LOG_WARNING, "No trailing CRLF found in HTTP header.\n"); } - return http_open_cnx(h); + ret = http_open_cnx(h, options); + if (ret < 0) + av_dict_free(&s->chained_options); + return ret; } static int http_getc(HTTPContext *s) { @@ -304,7 +338,7 @@ static int process_line(URLContext *h, char *line, int line_count, p++; s->http_code = strtol(p, &end, 10); - av_dlog(NULL, "http_code=%d\n", s->http_code); + av_log(h, AV_LOG_DEBUG, "http_code=%d\n", s->http_code); /* error codes are 4xx and 5xx, but regard 401 as a success, so we * don't abort until all headers have been parsed. */ @@ -328,7 +362,14 @@ static int process_line(URLContext *h, char *line, int line_count, while (av_isspace(*p)) p++; if (!av_strcasecmp(tag, "Location")) { - av_strlcpy(s->location, p, sizeof(s->location)); + char redirected_location[MAX_URL_SIZE], *new_loc; + ff_make_absolute_url(redirected_location, sizeof(redirected_location), + s->location, p); + new_loc = av_strdup(redirected_location); + if (!new_loc) + return AVERROR(ENOMEM); + av_free(s->location); + s->location = new_loc; *new_location = 1; } else if (!av_strcasecmp (tag, "Content-Length") && s->filesize == -1) { s->filesize = strtoll(p, NULL, 10); @@ -357,8 +398,12 @@ static int process_line(URLContext *h, char *line, int line_count, } else if (!av_strcasecmp (tag, "Connection")) { if (!strcmp(p, "close")) s->willclose = 1; - } else if (!av_strcasecmp (tag, "Server") && !av_strcasecmp (p, "AkamaiGHost")) { - s->is_akamai = 1; + } else if (!av_strcasecmp (tag, "Server")) { + if (!av_strcasecmp (p, "AkamaiGHost")) { + s->is_akamai = 1; + } else if (!av_strncasecmp (p, "MediaGateway", 12)) { + s->is_mediagateway = 1; + } } else if (!av_strcasecmp (tag, "Content-Type")) { av_free(s->mime_type); s->mime_type = av_strdup(p); } else if (!av_strcasecmp (tag, "Set-Cookie")) { @@ -375,6 +420,40 @@ static int process_line(URLContext *h, char *line, int line_count, snprintf(s->cookies, str_size, "%s\n%s", tmp, p); av_free(tmp); } + } else if (!av_strcasecmp (tag, "Icy-MetaInt")) { + s->icy_metaint = strtoll(p, NULL, 10); + } else if (!av_strncasecmp(tag, "Icy-", 4)) { + // Concat all Icy- header lines + char *buf = av_asprintf("%s%s: %s\n", + s->icy_metadata_headers ? s->icy_metadata_headers : "", tag, p); + if (!buf) + return AVERROR(ENOMEM); + av_freep(&s->icy_metadata_headers); + s->icy_metadata_headers = buf; + } else if (!av_strcasecmp (tag, "Content-Encoding")) { + if (!av_strncasecmp(p, "gzip", 4) || !av_strncasecmp(p, "deflate", 7)) { +#if CONFIG_ZLIB + s->compressed = 1; + inflateEnd(&s->inflate_stream); + if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) { + av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n", + s->inflate_stream.msg); + return AVERROR(ENOSYS); + } + if (zlibCompileFlags() & (1 << 17)) { + av_log(h, AV_LOG_WARNING, "Your zlib was compiled without gzip support.\n"); + return AVERROR(ENOSYS); + } +#else + av_log(h, AV_LOG_WARNING, "Compressed (%s) content, need zlib with gzip support\n", p); + return AVERROR(ENOSYS); +#endif + } else if (!av_strncasecmp(p, "identity", 8)) { + // The normal, no-encoding case (although servers shouldn't include + // the header at all if this is the case). + } else { + av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p); + } } } return 1; @@ -421,6 +500,8 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, cvalue = av_strdup(param); } } + if (!cdomain) + cdomain = av_strdup(domain); // ensure all of the necessary values are valid if (!cdomain || !cpath || !cvalue) { @@ -495,7 +576,7 @@ static int http_read_header(URLContext *h, int *new_location) if ((err = http_get_line(s, line, sizeof(line))) < 0) return err; - av_dlog(NULL, "header='%s'\n", line); + av_log(h, AV_LOG_DEBUG, "header='%s'\n", line); err = process_line(h, line, s->line_count, new_location); if (err < 0) @@ -505,6 +586,9 @@ static int http_read_header(URLContext *h, int *new_location) s->line_count++; } + if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000) + h->is_streamed = 1; /* we can in fact _not_ seek */ + return err; } @@ -519,6 +603,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, int64_t off = s->off; int len = 0; const char *method; + int send_expect_100 = 0; /* send http header */ @@ -536,12 +621,22 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, method); proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth, local_path, method); + if (post && !s->post_data) { + send_expect_100 = s->send_expect_100; + /* The user has supplied authentication but we don't know the auth type, + * send Expect: 100-continue to get the 401 response including the + * WWW-Authenticate header, or an 100 continue if no auth actually + * is needed. */ + if (auth && *auth && + s->auth_state.auth_type == HTTP_AUTH_NONE && + s->http_code != 401) + send_expect_100 = 1; + } /* set default headers if needed */ if (!has_header(s->headers, "\r\nUser-Agent: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, - "User-Agent: %s\r\n", - s->user_agent ? s->user_agent : LIBAVFORMAT_IDENT); + "User-Agent: %s\r\n", s->user_agent); if (!has_header(s->headers, "\r\nAccept: ")) len += av_strlcpy(headers + len, "Accept: */*\r\n", sizeof(headers) - len); @@ -551,6 +646,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->seekable == -1)) len += av_strlcatf(headers + len, sizeof(headers) - len, "Range: bytes=%"PRId64"-\r\n", s->off); + if (send_expect_100 && !has_header(s->headers, "\r\nExpect: ")) + len += av_strlcatf(headers + len, sizeof(headers) - len, + "Expect: 100-continue\r\n"); if (!has_header(s->headers, "\r\nConnection: ")) { if (s->multiple_requests) { @@ -579,6 +677,10 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, av_free(cookies); } } + if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy) { + len += av_strlcatf(headers + len, sizeof(headers) - len, + "Icy-MetaData: %d\r\n", 1); + } /* now add in custom headers */ if (s->headers) @@ -600,6 +702,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, av_freep(&authstr); av_freep(&proxyauthstr); + + av_log(h, AV_LOG_DEBUG, "request: %s\n", s->buffer); + if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0) return err; @@ -612,11 +717,12 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, s->buf_end = s->buffer; s->line_count = 0; s->off = 0; + s->icy_data_read = 0; s->filesize = -1; s->willclose = 0; s->end_chunked_post = 0; s->end_header = 0; - if (post && !s->post_data) { + if (post && !s->post_data && !send_expect_100) { /* Pretend that it did work. We didn't read any header yet, since * we've still to send the POST data, but the code calling this * function will check http_code after we return. */ @@ -651,12 +757,45 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) } if (len > 0) { s->off += len; + s->icy_data_read += len; if (s->chunksize > 0) s->chunksize -= len; } return len; } +#if CONFIG_ZLIB +#define DECOMPRESS_BUF_SIZE (256 * 1024) +static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; + int ret; + + if (!s->inflate_buffer) { + s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE); + if (!s->inflate_buffer) + return AVERROR(ENOMEM); + } + + if (s->inflate_stream.avail_in == 0) { + int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE); + if (read <= 0) + return read; + s->inflate_stream.next_in = s->inflate_buffer; + s->inflate_stream.avail_in = read; + } + + s->inflate_stream.avail_out = size; + s->inflate_stream.next_out = buf; + + ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n", ret, s->inflate_stream.msg); + + return size - s->inflate_stream.avail_out; +} +#endif + static int http_read(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; @@ -692,6 +831,36 @@ static int http_read(URLContext *h, uint8_t *buf, int size) } size = FFMIN(size, s->chunksize); } + if (s->icy_metaint > 0) { + int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */ + if (!remaining) { + // The metadata packet is variable sized. It has a 1 byte header + // which sets the length of the packet (divided by 16). If it's 0, + // the metadata doesn't change. After the packet, icy_metaint bytes + // of normal data follow. + int ch = http_getc(s); + if (ch < 0) + return ch; + if (ch > 0) { + char data[255 * 16 + 1]; + int n; + int ret; + ch *= 16; + for (n = 0; n < ch; n++) + data[n] = http_getc(s); + data[ch + 1] = 0; + if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0) + return ret; + } + s->icy_data_read = 0; + remaining = s->icy_metaint; + } + size = FFMIN(size, remaining); + } +#if CONFIG_ZLIB + if (s->compressed) + return http_buf_read_compressed(h, buf, size); +#endif return http_buf_read(h, buf, size); } @@ -743,6 +912,11 @@ static int http_close(URLContext *h) int ret = 0; HTTPContext *s = h->priv_data; +#if CONFIG_ZLIB + inflateEnd(&s->inflate_stream); + av_freep(&s->inflate_buffer); +#endif + if (!s->end_chunked_post) { /* Close the write direction by sending the end of chunked encoding. */ ret = http_shutdown(h, h->flags); @@ -750,6 +924,7 @@ static int http_close(URLContext *h) if (s->hd) ffurl_closep(&s->hd); + av_dict_free(&s->chained_options); return ret; } @@ -760,6 +935,7 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence) int64_t old_off = s->off; uint8_t old_buf[BUFFER_SIZE]; int old_buf_size; + AVDictionary *options = NULL; if (whence == AVSEEK_SIZE) return s->filesize; @@ -777,7 +953,9 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence) s->off = off; /* if it fails, continue on old connection */ - if (http_open_cnx(h) < 0) { + av_dict_copy(&options, s->chained_options, 0); + if (http_open_cnx(h, &options) < 0) { + av_dict_free(&options); memcpy(s->buffer, old_buf, old_buf_size); s->buf_ptr = s->buffer; s->buf_end = s->buffer + old_buf_size; @@ -785,6 +963,7 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence) s->off = old_off; return -1; } + av_dict_free(&options); ffurl_close(old_hd); return off; } @@ -799,7 +978,7 @@ http_get_file_handle(URLContext *h) #if CONFIG_HTTP_PROTOCOL URLProtocol ff_http_protocol = { .name = "http", - .url_open = http_open, + .url_open2 = http_open, .url_read = http_read, .url_write = http_write, .url_seek = http_seek, @@ -814,7 +993,7 @@ URLProtocol ff_http_protocol = { #if CONFIG_HTTPS_PROTOCOL URLProtocol ff_https_protocol = { .name = "https", - .url_open = http_open, + .url_open2 = http_open, .url_read = http_read, .url_write = http_write, .url_seek = http_seek, @@ -846,8 +1025,6 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags) HTTPAuthType cur_auth_type; char *authstr; int new_loc; - AVDictionary *opts = NULL; - char opts_format[20]; if( s->seekable == 1 ) h->is_streamed = 0; @@ -864,13 +1041,8 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags) ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, NULL); redo: - if (s->rw_timeout != -1) { - snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout); - av_dict_set(&opts, "timeout", opts_format, 0); - } /* if option is not given, don't pass it and let tcp use its own default */ ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, - &h->interrupt_callback, &opts); - av_dict_free(&opts); + &h->interrupt_callback, NULL); if (ret < 0) return ret; diff --git a/ffmpeg/libavformat/icodec.c b/ffmpeg/libavformat/icodec.c index fa308da..4c038e9 100644 --- a/ffmpeg/libavformat/icodec.c +++ b/ffmpeg/libavformat/icodec.c @@ -45,7 +45,7 @@ typedef struct { static int probe(AVProbeData *p) { if (AV_RL16(p->buf) == 0 && AV_RL16(p->buf + 2) == 1 && AV_RL16(p->buf + 4)) - return AVPROBE_SCORE_MAX / 3; + return AVPROBE_SCORE_MAX / 4; return 0; } diff --git a/ffmpeg/libavformat/icoenc.c b/ffmpeg/libavformat/icoenc.c index 3e6a1ea..561c6ca 100644 --- a/ffmpeg/libavformat/icoenc.c +++ b/ffmpeg/libavformat/icoenc.c @@ -151,8 +151,6 @@ static int ico_write_packet(AVFormatContext *s, AVPacket *pkt) avio_w8(pb, 0x00); // Write bitmask (opaque) } - avio_flush(pb); - return 0; } diff --git a/ffmpeg/libavformat/id3v2.c b/ffmpeg/libavformat/id3v2.c index 3e347d1..3eb368e 100644 --- a/ffmpeg/libavformat/id3v2.c +++ b/ffmpeg/libavformat/id3v2.c @@ -32,72 +32,71 @@ #include <zlib.h> #endif -#include "id3v2.h" -#include "id3v1.h" #include "libavutil/avstring.h" -#include "libavutil/intreadwrite.h" #include "libavutil/dict.h" +#include "libavutil/intreadwrite.h" #include "avio_internal.h" #include "internal.h" +#include "id3v1.h" +#include "id3v2.h" const AVMetadataConv ff_id3v2_34_metadata_conv[] = { - { "TALB", "album"}, - { "TCOM", "composer"}, - { "TCON", "genre"}, - { "TCOP", "copyright"}, - { "TENC", "encoded_by"}, - { "TIT2", "title"}, - { "TLAN", "language"}, - { "TPE1", "artist"}, - { "TPE2", "album_artist"}, - { "TPE3", "performer"}, - { "TPOS", "disc"}, - { "TPUB", "publisher"}, - { "TRCK", "track"}, - { "TSSE", "encoder"}, + { "TALB", "album" }, + { "TCOM", "composer" }, + { "TCON", "genre" }, + { "TCOP", "copyright" }, + { "TENC", "encoded_by" }, + { "TIT2", "title" }, + { "TLAN", "language" }, + { "TPE1", "artist" }, + { "TPE2", "album_artist" }, + { "TPE3", "performer" }, + { "TPOS", "disc" }, + { "TPUB", "publisher" }, + { "TRCK", "track" }, + { "TSSE", "encoder" }, { 0 } }; const AVMetadataConv ff_id3v2_4_metadata_conv[] = { - { "TDRL", "date"}, - { "TDRC", "date"}, - { "TDEN", "creation_time"}, - { "TSOA", "album-sort"}, - { "TSOP", "artist-sort"}, - { "TSOT", "title-sort"}, + { "TDRL", "date" }, + { "TDRC", "date" }, + { "TDEN", "creation_time" }, + { "TSOA", "album-sort" }, + { "TSOP", "artist-sort" }, + { "TSOT", "title-sort" }, { 0 } }; static const AVMetadataConv id3v2_2_metadata_conv[] = { - { "TAL", "album"}, - { "TCO", "genre"}, - { "TT2", "title"}, - { "TEN", "encoded_by"}, - { "TP1", "artist"}, - { "TP2", "album_artist"}, - { "TP3", "performer"}, - { "TRK", "track"}, + { "TAL", "album" }, + { "TCO", "genre" }, + { "TT2", "title" }, + { "TEN", "encoded_by" }, + { "TP1", "artist" }, + { "TP2", "album_artist" }, + { "TP3", "performer" }, + { "TRK", "track" }, { 0 } }; - const char ff_id3v2_tags[][4] = { - "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT", - "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", - "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", - "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE", - { 0 }, + "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT", + "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED", + "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", + "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE", + { 0 }, }; const char ff_id3v2_4_tags[][4] = { - "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO", - "TPRO", "TSOA", "TSOP", "TSOT", "TSST", - { 0 }, + "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO", + "TPRO", "TSOA", "TSOP", "TSOT", "TSST", + { 0 }, }; const char ff_id3v2_3_tags[][4] = { - "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER", - { 0 }, + "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER", + { 0 }, }; const char *ff_id3v2_picture_types[21] = { @@ -125,36 +124,36 @@ const char *ff_id3v2_picture_types[21] = { }; const CodecMime ff_id3v2_mime_tags[] = { - {"image/gif" , AV_CODEC_ID_GIF}, - {"image/jpeg", AV_CODEC_ID_MJPEG}, - {"image/jpg", AV_CODEC_ID_MJPEG}, - {"image/png" , AV_CODEC_ID_PNG}, - {"image/tiff", AV_CODEC_ID_TIFF}, - {"image/bmp", AV_CODEC_ID_BMP}, - {"JPG", AV_CODEC_ID_MJPEG}, /* ID3v2.2 */ - {"PNG" , AV_CODEC_ID_PNG}, /* ID3v2.2 */ - {"", AV_CODEC_ID_NONE}, + { "image/gif", AV_CODEC_ID_GIF }, + { "image/jpeg", AV_CODEC_ID_MJPEG }, + { "image/jpg", AV_CODEC_ID_MJPEG }, + { "image/png", AV_CODEC_ID_PNG }, + { "image/tiff", AV_CODEC_ID_TIFF }, + { "image/bmp", AV_CODEC_ID_BMP }, + { "JPG", AV_CODEC_ID_MJPEG }, /* ID3v2.2 */ + { "PNG", AV_CODEC_ID_PNG }, /* ID3v2.2 */ + { "", AV_CODEC_ID_NONE }, }; -int ff_id3v2_match(const uint8_t *buf, const char * magic) +int ff_id3v2_match(const uint8_t *buf, const char *magic) { return buf[0] == magic[0] && buf[1] == magic[1] && buf[2] == magic[2] && - buf[3] != 0xff && - buf[4] != 0xff && - (buf[6] & 0x80) == 0 && - (buf[7] & 0x80) == 0 && - (buf[8] & 0x80) == 0 && - (buf[9] & 0x80) == 0; + buf[3] != 0xff && + buf[4] != 0xff && + (buf[6] & 0x80) == 0 && + (buf[7] & 0x80) == 0 && + (buf[8] & 0x80) == 0 && + (buf[9] & 0x80) == 0; } -int ff_id3v2_tag_len(const uint8_t * buf) +int ff_id3v2_tag_len(const uint8_t *buf) { int len = ((buf[6] & 0x7f) << 21) + ((buf[7] & 0x7f) << 14) + ((buf[8] & 0x7f) << 7) + - (buf[9] & 0x7f) + + (buf[9] & 0x7f) + ID3v2_HEADER_SIZE; if (buf[5] & 0x10) len += ID3v2_HEADER_SIZE; @@ -210,7 +209,6 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, } switch (encoding) { - case ID3v2_ENCODING_ISO8859: while (left && ch) { ch = avio_r8(pb); @@ -246,7 +244,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);) } if (left < 0) - left += 2; /* did not read last char from pb */ + left += 2; /* did not read last char from pb */ break; case ID3v2_ENCODING_UTF8: @@ -272,7 +270,8 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, /** * Parse a text tag. */ -static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key) +static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, + AVDictionary **metadata, const char *key) { uint8_t *dst; int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL; @@ -289,9 +288,9 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const cha return; } - if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) - && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) - && genre <= ID3v1_GENRE_MAX) { + if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) && + (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) && + genre <= ID3v1_GENRE_MAX) { av_freep(&dst); dst = av_strdup(ff_id3v1_genre_str[genre]); } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) { @@ -307,16 +306,17 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const cha av_freep(&dst); if (dst) - av_dict_set(&s->metadata, key, dst, dict_flags); + av_dict_set(metadata, key, dst, dict_flags); } /** * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct. */ -static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta) +static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, + char *tag, ID3v2ExtraMeta **extra_meta, int isv34) { ID3v2ExtraMetaGEOB *geob_data = NULL; - ID3v2ExtraMeta *new_extra = NULL; + ID3v2ExtraMeta *new_extra = NULL; char encoding; unsigned int len; @@ -325,13 +325,15 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char * geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB)); if (!geob_data) { - av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB)); + av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", + sizeof(ID3v2ExtraMetaGEOB)); return; } new_extra = av_mallocz(sizeof(ID3v2ExtraMeta)); if (!new_extra) { - av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMeta)); + av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", + sizeof(ID3v2ExtraMeta)); goto fail; } @@ -340,18 +342,19 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char * taglen--; /* read MIME type (always ISO-8859) */ - if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, &taglen) < 0 - || taglen <= 0) + if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, + &taglen) < 0 || + taglen <= 0) goto fail; /* read file name */ - if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 - || taglen <= 0) + if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 || + taglen <= 0) goto fail; /* read content description */ - if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 - || taglen < 0) + if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 || + taglen < 0) goto fail; if (taglen) { @@ -362,18 +365,19 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char * goto fail; } if ((len = avio_read(pb, geob_data->data, taglen)) < taglen) - av_log(s, AV_LOG_WARNING, "Error reading GEOB frame, data truncated.\n"); + av_log(s, AV_LOG_WARNING, + "Error reading GEOB frame, data truncated.\n"); geob_data->datasize = len; } else { - geob_data->data = NULL; + geob_data->data = NULL; geob_data->datasize = 0; } /* add data to the list */ - new_extra->tag = "GEOB"; + new_extra->tag = "GEOB"; new_extra->data = geob_data; new_extra->next = *extra_meta; - *extra_meta = new_extra; + *extra_meta = new_extra; return; @@ -386,11 +390,12 @@ fail: static int is_number(const char *str) { - while (*str >= '0' && *str <= '9') str++; + while (*str >= '0' && *str <= '9') + str++; return !*str; } -static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag) +static AVDictionaryEntry *get_date_tag(AVDictionary *m, const char *tag) { AVDictionaryEntry *t; if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) && @@ -402,28 +407,29 @@ static AVDictionaryEntry* get_date_tag(AVDictionary *m, const char *tag) static void merge_date(AVDictionary **m) { AVDictionaryEntry *t; - char date[17] = {0}; // YYYY-MM-DD hh:mm + char date[17] = { 0 }; // YYYY-MM-DD hh:mm if (!(t = get_date_tag(*m, "TYER")) && !(t = get_date_tag(*m, "TYE"))) return; av_strlcpy(date, t->value, 5); av_dict_set(m, "TYER", NULL, 0); - av_dict_set(m, "TYE", NULL, 0); + av_dict_set(m, "TYE", NULL, 0); if (!(t = get_date_tag(*m, "TDAT")) && !(t = get_date_tag(*m, "TDA"))) goto finish; snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value); av_dict_set(m, "TDAT", NULL, 0); - av_dict_set(m, "TDA", NULL, 0); + av_dict_set(m, "TDA", NULL, 0); if (!(t = get_date_tag(*m, "TIME")) && !(t = get_date_tag(*m, "TIM"))) goto finish; - snprintf(date + 10, sizeof(date) - 10, " %.2s:%.2s", t->value, t->value + 2); + snprintf(date + 10, sizeof(date) - 10, + " %.2s:%.2s", t->value, t->value + 2); av_dict_set(m, "TIME", NULL, 0); - av_dict_set(m, "TIM", NULL, 0); + av_dict_set(m, "TIM", NULL, 0); finish: if (date[0]) @@ -438,15 +444,16 @@ static void free_apic(void *obj) av_freep(&apic); } -static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta) +static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, + char *tag, ID3v2ExtraMeta **extra_meta, int isv34) { int enc, pic_type; - char mimetype[64]; - const CodecMime *mime = ff_id3v2_mime_tags; - enum AVCodecID id = AV_CODEC_ID_NONE; - ID3v2ExtraMetaAPIC *apic = NULL; + char mimetype[64]; + const CodecMime *mime = ff_id3v2_mime_tags; + enum AVCodecID id = AV_CODEC_ID_NONE; + ID3v2ExtraMetaAPIC *apic = NULL; ID3v2ExtraMeta *new_extra = NULL; - int64_t end = avio_tell(pb) + taglen; + int64_t end = avio_tell(pb) + taglen; if (taglen <= 4) goto fail; @@ -460,7 +467,12 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag taglen--; /* mimetype */ + if (isv34) { taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype)); + } else { + avio_read(pb, mimetype, 3); + mimetype[3] = 0; + } while (mime->id != AV_CODEC_ID_NONE) { if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) { id = mime->id; @@ -469,7 +481,8 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag mime++; } if (id == AV_CODEC_ID_NONE) { - av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s, skipping.\n", mimetype); + av_log(s, AV_LOG_WARNING, + "Unknown attached picture mimetype: %s, skipping.\n", mimetype); goto fail; } apic->id = id; @@ -478,25 +491,28 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag pic_type = avio_r8(pb); taglen--; if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) { - av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", pic_type); + av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", + pic_type); pic_type = 0; } apic->type = ff_id3v2_picture_types[pic_type]; /* description and picture data */ if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) { - av_log(s, AV_LOG_ERROR, "Error decoding attached picture description.\n"); + av_log(s, AV_LOG_ERROR, + "Error decoding attached picture description.\n"); goto fail; } - apic->buf = av_buffer_alloc(taglen); + apic->buf = av_buffer_alloc(taglen + FF_INPUT_BUFFER_PADDING_SIZE); if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen) goto fail; + memset(apic->buf->data + taglen, 0, FF_INPUT_BUFFER_PADDING_SIZE); - new_extra->tag = "APIC"; - new_extra->data = apic; - new_extra->next = *extra_meta; - *extra_meta = new_extra; + new_extra->tag = "APIC"; + new_extra->data = apic; + new_extra->next = *extra_meta; + *extra_meta = new_extra; return; @@ -507,47 +523,65 @@ fail: avio_seek(pb, end, SEEK_SET); } -static void read_chapter(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta) +static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *ttag, ID3v2ExtraMeta **extra_meta, int isv34) { AVRational time_base = {1, 1000}; - char title[1024]; uint32_t start, end; + AVChapter *chapter; + uint8_t *dst = NULL; + int taglen; + char tag[5]; - taglen -= avio_get_str(pb, taglen, title, sizeof(title)); - if (taglen < 16) + if (decode_str(s, pb, 0, &dst, &len) < 0) + return; + if (len < 16) return; start = avio_rb32(pb); end = avio_rb32(pb); - taglen -= 27; - if (taglen > 0) { - char tag[4]; - - avio_skip(pb, 8); - avio_read(pb, tag, 4); - if (!memcmp(tag, "TIT2", 4)) { - taglen = FFMIN(taglen, avio_rb32(pb)); - if (taglen < 0) - return; - avio_skip(pb, 3); - avio_get_str(pb, taglen, title, sizeof(title)); - } + avio_skip(pb, 8); + + chapter = avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, dst); + if (!chapter) { + av_free(dst); + return; } - avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, title); + len -= 16; + while (len > 10) { + if (avio_read(pb, tag, 4) < 4) + goto end; + tag[4] = 0; + taglen = avio_rb32(pb); + avio_skip(pb, 2); + len -= 10; + if (taglen < 0 || taglen > len) + goto end; + if (tag[0] == 'T') + read_ttag(s, pb, taglen, &chapter->metadata, tag); + else + avio_skip(pb, taglen); + len -= taglen; + } + + ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_34_metadata_conv); + ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_4_metadata_conv); +end: + av_free(dst); } typedef struct ID3v2EMFunc { const char *tag3; const char *tag4; - void (*read)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta **); + void (*read)(AVFormatContext *, AVIOContext *, int, char *, + ID3v2ExtraMeta **, int isv34); void (*free)(void *obj); } ID3v2EMFunc; static const ID3v2EMFunc id3v2_extra_meta_funcs[] = { { "GEO", "GEOB", read_geobtag, free_geobtag }, - { "PIC", "APIC", read_apic, free_apic }, - { "CHAP","CHAP", read_chapter, NULL }, + { "PIC", "APIC", read_apic, free_apic }, + { "CHAP","CHAP", read_chapter, NULL }, { NULL } }; @@ -570,7 +604,8 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34) return NULL; } -static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta) +static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, + uint8_t flags, ID3v2ExtraMeta **extra_meta) { int isv34, unsync; unsigned tlen; @@ -581,7 +616,7 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t AVIOContext pb; AVIOContext *pbx; unsigned char *buffer = NULL; - int buffer_size = 0; + int buffer_size = 0; const ID3v2EMFunc *extra_func = NULL; unsigned char *uncompressed_buffer = NULL; int uncompressed_buffer_size = 0; @@ -594,13 +629,13 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t reason = "compression"; goto error; } - isv34 = 0; + isv34 = 0; taghdrlen = 6; break; case 3: case 4: - isv34 = 1; + isv34 = 1; taghdrlen = 10; break; @@ -614,7 +649,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */ int extlen = get_size(s->pb, 4); if (version == 4) - extlen -= 4; // in v2.4 the length includes the length field we just read + /* In v2.4 the length includes the length field we just read. */ + extlen -= 4; if (extlen < 0) { reason = "invalid extended header length"; @@ -630,24 +666,26 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t while (len >= taghdrlen) { unsigned int tflags = 0; - int tunsync = 0; - int tcomp = 0; - int tencr = 0; + int tunsync = 0; + int tcomp = 0; + int tencr = 0; unsigned long dlen; if (isv34) { - avio_read(s->pb, tag, 4); + if (avio_read(s->pb, tag, 4) < 4) + break; tag[4] = 0; - if(version==3){ + if (version == 3) { tlen = avio_rb32(s->pb); - }else + } else tlen = get_size(s->pb, 4); - tflags = avio_rb16(s->pb); + tflags = avio_rb16(s->pb); tunsync = tflags & ID3v2_FLAG_UNSYNCH; } else { - avio_read(s->pb, tag, 3); + if (avio_read(s->pb, tag, 3) < 3) + break; tag[3] = 0; - tlen = avio_rb24(s->pb); + tlen = avio_rb24(s->pb); } if (tlen > (1<<28)) break; @@ -660,7 +698,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t if (!tlen) { if (tag[0]) - av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n", tag); + av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n", + tag); continue; } @@ -688,7 +727,9 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag); avio_skip(s->pb, tlen); /* check for text tag or supported special meta tag */ - } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) { + } else if (tag[0] == 'T' || + (extra_meta && + (extra_func = get_extra_meta_func(tag, isv34)))) { pbx = s->pb; if (unsync || tunsync || tcomp) { @@ -703,16 +744,19 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t uint8_t *b; b = buffer; - while (avio_tell(s->pb) < end && b - buffer < tlen) { + while (avio_tell(s->pb) < end && b - buffer < tlen && !s->pb->eof_reached) { *b++ = avio_r8(s->pb); - if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 && b - buffer < tlen) { + if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 && + b - buffer < tlen && + !s->pb->eof_reached ) { uint8_t val = avio_r8(s->pb); *b++ = val ? val : avio_r8(s->pb); } } - ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL, NULL); + ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL, + NULL); tlen = b - buffer; - pbx = &pb; // read from sync buffer + pbx = &pb; // read from sync buffer } #if CONFIG_ZLIB @@ -748,12 +792,11 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t #endif if (tag[0] == 'T') /* parse text tag */ - read_ttag(s, pbx, tlen, tag); + read_ttag(s, pbx, tlen, &s->metadata, tag); else /* parse special meta tag */ - extra_func->read(s, pbx, tlen, tag, extra_meta); - } - else if (!tag[0]) { + extra_func->read(s, pbx, tlen, tag, extra_meta, isv34); + } else if (!tag[0]) { if (tag[1]) av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n"); avio_skip(s->pb, tlen); @@ -764,23 +807,26 @@ seek: avio_seek(s->pb, next, SEEK_SET); } - if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */ + /* Footer preset, always 10 bytes, skip over it */ + if (version == 4 && flags & 0x10) end += 10; - error: +error: if (reason) - av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); + av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", + version, reason); avio_seek(s->pb, end, SEEK_SET); av_free(buffer); av_free(uncompressed_buffer); return; } -void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta) +void ff_id3v2_read(AVFormatContext *s, const char *magic, + ID3v2ExtraMeta **extra_meta) { int len, ret; uint8_t buf[ID3v2_HEADER_SIZE]; - int found_header; + int found_header; int64_t off; do { @@ -798,7 +844,7 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f); - ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta); + id3v2_parse(s, len, buf[3], buf[5], extra_meta); } else { avio_seek(s->pb, off, SEEK_SET); } @@ -847,7 +893,7 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) av_init_packet(&st->attached_pic); st->attached_pic.buf = apic->buf; st->attached_pic.data = apic->buf->data; - st->attached_pic.size = apic->buf->size; + st->attached_pic.size = apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE; st->attached_pic.stream_index = st->index; st->attached_pic.flags |= AV_PKT_FLAG_KEY; diff --git a/ffmpeg/libavformat/id3v2enc.c b/ffmpeg/libavformat/id3v2enc.c index a10d679..6052244 100644 --- a/ffmpeg/libavformat/id3v2enc.c +++ b/ffmpeg/libavformat/id3v2enc.c @@ -26,8 +26,11 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" #include "avio.h" +#include "avio_internal.h" #include "id3v2.h" +#define PADDING_BYTES 10 + static void id3v2_put_size(AVIOContext *pb, int size) { avio_w8(pb, size >> 21 & 0x7f); @@ -162,33 +165,31 @@ void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, avio_wb32(pb, 0); } -int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) +static int write_metadata(AVIOContext *pb, AVDictionary **metadata, + ID3v2EncContext *id3, int enc) { AVDictionaryEntry *t = NULL; - int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM : - ID3v2_ENCODING_UTF8; + int ret; - ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL); + ff_metadata_conv(metadata, ff_id3v2_34_metadata_conv, NULL); if (id3->version == 3) - id3v2_3_metadata_split_date(&s->metadata); + id3v2_3_metadata_split_date(metadata); else if (id3->version == 4) - ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL); - - while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { - int ret; + ff_metadata_conv(metadata, ff_id3v2_4_metadata_conv, NULL); - if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) { + while ((t = av_dict_get(*metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { + if ((ret = id3v2_check_write_tag(id3, pb, t, ff_id3v2_tags, enc)) > 0) { id3->len += ret; continue; } - if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ? - ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { + if ((ret = id3v2_check_write_tag(id3, pb, t, id3->version == 3 ? + ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { id3->len += ret; continue; } /* unknown tag, write as TXXX frame */ - if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) + if ((ret = id3v2_put_ttag(id3, pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) return ret; id3->len += ret; } @@ -196,6 +197,64 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) return 0; } +static int write_chapter(AVFormatContext *s, ID3v2EncContext *id3, int id, int enc) +{ + const AVRational time_base = {1, 1000}; + AVChapter *ch = s->chapters[id]; + uint8_t *dyn_buf = NULL; + AVIOContext *dyn_bc = NULL; + char name[123]; + int len, start, end, ret; + + if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0) + goto fail; + + start = av_rescale_q(ch->start, ch->time_base, time_base); + end = av_rescale_q(ch->end, ch->time_base, time_base); + + snprintf(name, 122, "ch%d", id); + id3->len += avio_put_str(dyn_bc, name); + avio_wb32(dyn_bc, start); + avio_wb32(dyn_bc, end); + avio_wb32(dyn_bc, 0xFFFFFFFFu); + avio_wb32(dyn_bc, 0xFFFFFFFFu); + + if ((ret = write_metadata(dyn_bc, &ch->metadata, id3, enc)) < 0) + goto fail; + + len = avio_close_dyn_buf(dyn_bc, &dyn_buf); + id3->len += 16 + ID3v2_HEADER_SIZE; + + avio_wb32(s->pb, MKBETAG('C', 'H', 'A', 'P')); + avio_wb32(s->pb, len); + avio_wb16(s->pb, 0); + avio_write(s->pb, dyn_buf, len); + +fail: + if (dyn_bc && !dyn_buf) + avio_close_dyn_buf(dyn_bc, &dyn_buf); + av_freep(&dyn_buf); + + return ret; +} + +int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) +{ + int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM : + ID3v2_ENCODING_UTF8; + int i, ret; + + if ((ret = write_metadata(s->pb, &s->metadata, id3, enc)) < 0) + return ret; + + for (i = 0; i < s->nb_chapters; i++) { + if ((ret = write_chapter(s, id3, i, enc)) < 0) + return ret; + } + + return 0; +} + int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; @@ -236,6 +295,10 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) if ((e = av_dict_get(st->metadata, "title", NULL, 0))) desc = e->value; + /* use UTF16 only for non-ASCII strings */ + if (enc == ID3v2_ENCODING_UTF16BOM && string_is_ascii(desc)) + enc = ID3v2_ENCODING_ISO8859; + /* start writing */ if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); @@ -263,7 +326,15 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb) { - int64_t cur_pos = avio_tell(pb); + int64_t cur_pos; + + /* adding an arbitrary amount of padding bytes at the end of the + * ID3 metadata fixes cover art display for some software (iTunes, + * Traktor, Serato, Torq) */ + ffio_fill(pb, 0, PADDING_BYTES); + id3->len += PADDING_BYTES; + + cur_pos = avio_tell(pb); avio_seek(pb, id3->size_pos, SEEK_SET); id3v2_put_size(pb, id3->len); avio_seek(pb, cur_pos, SEEK_SET); diff --git a/ffmpeg/libavformat/idcin.c b/ffmpeg/libavformat/idcin.c index 2a8af40..cc25fb0 100644 --- a/ffmpeg/libavformat/idcin.c +++ b/ffmpeg/libavformat/idcin.c @@ -93,7 +93,9 @@ typedef struct IdcinDemuxContext { static int idcin_probe(AVProbeData *p) { - unsigned int number; + unsigned int number, sample_rate; + unsigned int w, h; + int i; /* * This is what you could call a "probabilistic" file check: id CIN @@ -108,36 +110,43 @@ static int idcin_probe(AVProbeData *p) /* check we have enough data to do all checks, otherwise the 0-padding may cause a wrong recognition */ - if (p->buf_size < 20) + if (p->buf_size < 20 + HUFFMAN_TABLE_SIZE + 12) return 0; /* check the video width */ - number = AV_RL32(&p->buf[0]); - if ((number == 0) || (number > 1024)) + w = AV_RL32(&p->buf[0]); + if ((w == 0) || (w > 1024)) return 0; /* check the video height */ - number = AV_RL32(&p->buf[4]); - if ((number == 0) || (number > 1024)) + h = AV_RL32(&p->buf[4]); + if ((h == 0) || (h > 1024)) return 0; /* check the audio sample rate */ - number = AV_RL32(&p->buf[8]); - if ((number != 0) && ((number < 8000) | (number > 48000))) + sample_rate = AV_RL32(&p->buf[8]); + if (sample_rate && (sample_rate < 8000 || sample_rate > 48000)) return 0; /* check the audio bytes/sample */ number = AV_RL32(&p->buf[12]); - if (number > 2) + if (number > 2 || sample_rate && !number) return 0; /* check the audio channels */ number = AV_RL32(&p->buf[16]); - if (number > 2) + if (number > 2 || sample_rate && !number) return 0; - /* return half certainly since this check is a bit sketchy */ - return AVPROBE_SCORE_MAX / 2; + i = 20 + HUFFMAN_TABLE_SIZE; + if (AV_RL32(&p->buf[i]) == 1) + i += 768; + + if (i+12 > p->buf_size || AV_RL32(&p->buf[i+8]) != w*h) + return 1; + + /* return half certainty since this check is a bit sketchy */ + return AVPROBE_SCORE_EXTENSION; } static int idcin_read_header(AVFormatContext *s) @@ -196,15 +205,8 @@ static int idcin_read_header(AVFormatContext *s) st->codec->height = height; /* load up the Huffman tables into extradata */ - st->codec->extradata_size = HUFFMAN_TABLE_SIZE; - st->codec->extradata = av_malloc(HUFFMAN_TABLE_SIZE); - ret = avio_read(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE); - if (ret < 0) { + if ((ret = ff_get_extradata(st->codec, pb, HUFFMAN_TABLE_SIZE)) < 0) return ret; - } else if (ret != HUFFMAN_TABLE_SIZE) { - av_log(s, AV_LOG_ERROR, "incomplete header\n"); - return AVERROR(EIO); - } if (idcin->audio_present) { idcin->audio_present = 1; diff --git a/ffmpeg/libavformat/idroqdec.c b/ffmpeg/libavformat/idroqdec.c index 6f843d7..8cdd72e 100644 --- a/ffmpeg/libavformat/idroqdec.c +++ b/ffmpeg/libavformat/idroqdec.c @@ -145,6 +145,8 @@ static int roq_read_packet(AVFormatContext *s, break; case RoQ_QUAD_CODEBOOK: + if (roq->video_stream_index < 0) + return AVERROR_INVALIDDATA; /* packet needs to contain both this codebook and next VQ chunk */ codebook_offset = avio_tell(pb) - RoQ_CHUNK_PREAMBLE_SIZE; codebook_size = chunk_size; @@ -194,6 +196,11 @@ static int roq_read_packet(AVFormatContext *s, st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; } case RoQ_QUAD_VQ: + if (chunk_type == RoQ_QUAD_VQ) { + if (roq->video_stream_index < 0) + return AVERROR_INVALIDDATA; + } + /* load up the packet */ if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE)) return AVERROR(EIO); diff --git a/ffmpeg/libavformat/iff.c b/ffmpeg/libavformat/iff.c index 1efc147..b5751c5 100644 --- a/ffmpeg/libavformat/iff.c +++ b/ffmpeg/libavformat/iff.c @@ -462,6 +462,10 @@ static int iff_read_packet(AVFormatContext *s, buf = pkt->data; bytestream_put_be16(&buf, 2); ret = avio_read(pb, buf, iff->body_size); + if (ret<0) { + av_free_packet(pkt); + } else if (ret < iff->body_size) + av_shrink_packet(pkt, ret + 2); } else { av_assert0(0); } @@ -481,5 +485,5 @@ AVInputFormat ff_iff_demuxer = { .read_probe = iff_probe, .read_header = iff_read_header, .read_packet = iff_read_packet, - .flags = AVFMT_GENERIC_INDEX, + .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, }; diff --git a/ffmpeg/libavformat/ilbc.c b/ffmpeg/libavformat/ilbc.c index 7a23b2f..3f154ce 100644 --- a/ffmpeg/libavformat/ilbc.c +++ b/ffmpeg/libavformat/ilbc.c @@ -56,7 +56,6 @@ static int ilbc_write_header(AVFormatContext *s) static int ilbc_write_packet(AVFormatContext *s, AVPacket *pkt) { avio_write(s->pb, pkt->data, pkt->size); - avio_flush(s->pb); return 0; } diff --git a/ffmpeg/libavformat/img2.c b/ffmpeg/libavformat/img2.c index eee100a..4fd4fd2 100644 --- a/ffmpeg/libavformat/img2.c +++ b/ffmpeg/libavformat/img2.c @@ -32,6 +32,7 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_MJPEG, "jpeg" }, { AV_CODEC_ID_MJPEG, "jpg" }, { AV_CODEC_ID_MJPEG, "jps" }, + { AV_CODEC_ID_MJPEG, "mpo" }, { AV_CODEC_ID_LJPEG, "ljpg" }, { AV_CODEC_ID_JPEGLS, "jls" }, { AV_CODEC_ID_PNG, "png" }, @@ -50,7 +51,6 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_RAWVIDEO, "y" }, { AV_CODEC_ID_RAWVIDEO, "raw" }, { AV_CODEC_ID_BMP, "bmp" }, - { AV_CODEC_ID_GIF, "gif" }, { AV_CODEC_ID_TARGA, "tga" }, { AV_CODEC_ID_TIFF, "tiff" }, { AV_CODEC_ID_TIFF, "tif" }, @@ -67,13 +67,14 @@ static const IdStrMap img_tags[] = { { AV_CODEC_ID_SUNRAST, "im32" }, { AV_CODEC_ID_SUNRAST, "sunras" }, { AV_CODEC_ID_JPEG2000, "j2c" }, - { AV_CODEC_ID_JPEG2000, "j2k" }, { AV_CODEC_ID_JPEG2000, "jp2" }, { AV_CODEC_ID_JPEG2000, "jpc" }, + { AV_CODEC_ID_JPEG2000, "j2k" }, { AV_CODEC_ID_DPX, "dpx" }, { AV_CODEC_ID_EXR, "exr" }, { AV_CODEC_ID_PICTOR, "pic" }, { AV_CODEC_ID_V210X, "yuv10" }, + { AV_CODEC_ID_WEBP, "webp" }, { AV_CODEC_ID_XBM, "xbm" }, { AV_CODEC_ID_XFACE, "xface" }, { AV_CODEC_ID_XWD, "xwd" }, diff --git a/ffmpeg/libavformat/img2dec.c b/ffmpeg/libavformat/img2dec.c index 882abb9..5163e69 100644 --- a/ffmpeg/libavformat/img2dec.c +++ b/ffmpeg/libavformat/img2dec.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <sys/stat.h> #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" @@ -52,8 +53,8 @@ typedef struct { int split_planes; /**< use independent file for each Y, U, V plane */ char path[1024]; char *pixel_format; /**< Set by a private option. */ - char *video_size; /**< Set by a private option. */ - char *framerate; /**< Set by a private option. */ + int width, height; /**< Set by a private option. */ + AVRational framerate; /**< Set by a private option. */ int loop; enum { PT_GLOB_SEQUENCE, PT_GLOB, PT_SEQUENCE } pattern_type; int use_glob; @@ -63,6 +64,7 @@ typedef struct { int start_number; int start_number_range; int frame_size; + int ts_from_file; } VideoDemuxData; static const int sizes[][2] = { @@ -185,7 +187,7 @@ static int img_read_probe(AVProbeData *p) else if (av_match_ext(p->filename, "raw") || av_match_ext(p->filename, "gif")) return 5; else - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; } return 0; } @@ -193,11 +195,9 @@ static int img_read_probe(AVProbeData *p) static int img_read_header(AVFormatContext *s1) { VideoDemuxData *s = s1->priv_data; - int first_index, last_index, ret = 0; - int width = 0, height = 0; + int first_index, last_index; AVStream *st; enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE; - AVRational framerate; s1->ctx_flags |= AVFMTCTX_NOHEADER; @@ -212,17 +212,6 @@ static int img_read_header(AVFormatContext *s1) s->pixel_format); return AVERROR(EINVAL); } - if (s->video_size && - (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) { - av_log(s, AV_LOG_ERROR, - "Could not parse video size: %s.\n", s->video_size); - return ret; - } - if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) { - av_log(s, AV_LOG_ERROR, - "Could not parse framerate: %s.\n", s->framerate); - return ret; - } av_strlcpy(s->path, s1->filename, sizeof(s->path)); s->img_number = 0; @@ -236,11 +225,14 @@ static int img_read_header(AVFormatContext *s1) st->need_parsing = AVSTREAM_PARSE_FULL; } - avpriv_set_pts_info(st, 60, framerate.den, framerate.num); + if (s->ts_from_file) + avpriv_set_pts_info(st, 64, 1, 1); + else + avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num); - if (width && height) { - st->codec->width = width; - st->codec->height = height; + if (s->width && s->height) { + st->codec->width = s->width; + st->codec->height = s->height; } if (!s->is_pipe) { @@ -280,7 +272,7 @@ static int img_read_header(AVFormatContext *s1) if (find_image_range(&first_index, &last_index, s->path, s->start_number, s->start_number_range) < 0) { av_log(s1, AV_LOG_ERROR, - "Could find no file with with path '%s' and index in the range %d-%d\n", + "Could find no file with path '%s' and index in the range %d-%d\n", s->path, s->start_number, s->start_number + s->start_number_range - 1); return AVERROR(ENOENT); } @@ -309,8 +301,10 @@ static int img_read_header(AVFormatContext *s1) s->img_last = last_index; s->img_number = first_index; /* compute duration */ - st->start_time = 0; - st->duration = last_index - first_index + 1; + if (!s->ts_from_file) { + st->start_time = 0; + st->duration = last_index - first_index + 1; + } } if (s1->video_codec_id) { @@ -394,8 +388,15 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) return AVERROR(ENOMEM); pkt->stream_index = 0; pkt->flags |= AV_PKT_FLAG_KEY; - if (!s->is_pipe) + if (s->ts_from_file) { + struct stat img_stat; + if (stat(filename, &img_stat)) + return AVERROR(EIO); + pkt->pts = (int64_t)img_stat.st_mtime; + av_add_index_entry(s1->streams[0], s->img_number, pkt->pts, 0, 0, AVINDEX_KEYFRAME); + } else if (!s->is_pipe) { pkt->pts = s->pts; + } pkt->size = 0; for (i = 0; i < 3; i++) { @@ -433,6 +434,15 @@ static int img_read_close(struct AVFormatContext* s1) static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { VideoDemuxData *s1 = s->priv_data; + AVStream *st = s->streams[0]; + + if (s1->ts_from_file) { + int index = av_index_search_timestamp(st, timestamp, flags); + if(index < 0) + return -1; + s1->img_number = st->index_entries[index].pos; + return 0; + } if (timestamp < 0 || !s1->loop && timestamp > s1->img_last - s1->img_first) return -1; @@ -444,7 +454,7 @@ static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp #define OFFSET(x) offsetof(VideoDemuxData, x) #define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { - { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC }, + { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC }, { "loop", "force loop over input file sequence", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC }, { "pattern_type", "set pattern type", OFFSET(pattern_type), AV_OPT_TYPE_INT, {.i64=PT_GLOB_SEQUENCE}, 0, INT_MAX, DEC, "pattern_type"}, @@ -455,8 +465,9 @@ static const AVOption options[] = { { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, { "start_number", "set first number in the sequence", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC }, { "start_number_range", "set range for looking at the first sequence number", OFFSET(start_number_range), AV_OPT_TYPE_INT, {.i64 = 5}, 1, INT_MAX, DEC }, - { "video_size", "set video size", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, { "frame_size", "force frame size in bytes", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC }, + { "ts_from_file", "set frame timestamp from file's one", OFFSET(ts_from_file), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC }, { NULL }, }; diff --git a/ffmpeg/libavformat/img2enc.c b/ffmpeg/libavformat/img2enc.c index 67b5819..f61b0ca 100644 --- a/ffmpeg/libavformat/img2enc.c +++ b/ffmpeg/libavformat/img2enc.c @@ -21,6 +21,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/log.h" #include "libavutil/opt.h" @@ -28,7 +29,6 @@ #include "avformat.h" #include "avio_internal.h" #include "internal.h" -#include "libavutil/opt.h" typedef struct { const AVClass *class; /**< Class for private options. */ @@ -36,7 +36,9 @@ typedef struct { int is_pipe; int split_planes; /**< use independent file for each Y, U, V plane */ char path[1024]; - int updatefirst; + int update; + int use_strftime; + const char *muxer; } VideoMuxData; static int write_header(AVFormatContext *s) @@ -44,7 +46,6 @@ static int write_header(AVFormatContext *s) VideoMuxData *img = s->priv_data; AVStream *st = s->streams[0]; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codec->pix_fmt); - const char *str; av_strlcpy(img->path, s->filename, sizeof(img->path)); @@ -54,14 +55,17 @@ static int write_header(AVFormatContext *s) else img->is_pipe = 1; - str = strrchr(img->path, '.'); - img->split_planes = str - && !av_strcasecmp(str + 1, "y") - && s->nb_streams == 1 - && st->codec->codec_id == AV_CODEC_ID_RAWVIDEO - && desc - &&(desc->flags & PIX_FMT_PLANAR) - && desc->nb_components >= 3; + if (st->codec->codec_id == AV_CODEC_ID_GIF) { + img->muxer = "gif"; + } else if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) { + const char *str = strrchr(img->path, '.'); + img->split_planes = str + && !av_strcasecmp(str + 1, "y") + && s->nb_streams == 1 + && desc + &&(desc->flags & AV_PIX_FMT_FLAG_PLANAR) + && desc->nb_components >= 3; + } return 0; } @@ -75,8 +79,19 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) int i; if (!img->is_pipe) { - if (av_get_frame_filename(filename, sizeof(filename), - img->path, img->img_number) < 0 && img->img_number > 1 && !img->updatefirst) { + if (img->update) { + av_strlcpy(filename, img->path, sizeof(filename)); + } else if (img->use_strftime) { + time_t now0; + struct tm *tm; + time(&now0); + tm = localtime(&now0); + if (!strftime(filename, sizeof(filename), img->path, tm)) { + av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n"); + return AVERROR(EINVAL); + } + } else if (av_get_frame_filename(filename, sizeof(filename), img->path, img->img_number) < 0 && + img->img_number > 1) { av_log(s, AV_LOG_ERROR, "Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n", img->img_number, img->path); @@ -91,7 +106,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) if (!img->split_planes || i+1 >= desc->nb_components) break; - filename[strlen(filename) - 1] = ((int[]){'U','V','A','x'})[i]; + filename[strlen(filename) - 1] = "UVAx"[i]; } } else { pb[0] = s->pb; @@ -99,7 +114,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) if (img->split_planes) { int ysize = codec->width * codec->height; - int usize = ((-codec->width)>>desc->log2_chroma_w) * ((-codec->height)>>desc->log2_chroma_h); + int usize = FF_CEIL_RSHIFT(codec->width, desc->log2_chroma_w) * FF_CEIL_RSHIFT(codec->height, desc->log2_chroma_h); if (desc->comp[0].depth_minus1 >= 8) { ysize *= 2; usize *= 2; @@ -113,6 +128,37 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) avio_write(pb[3], pkt->data + ysize + 2*usize, ysize); avio_close(pb[3]); } + } else if (img->muxer) { + int ret; + AVStream *st; + AVPacket pkt2 = {0}; + AVFormatContext *fmt = NULL; + + av_assert0(!img->split_planes); + + ret = avformat_alloc_output_context2(&fmt, NULL, img->muxer, s->filename); + if (ret < 0) + return ret; + st = avformat_new_stream(fmt, NULL); + if (!st) { + avformat_free_context(fmt); + return AVERROR(ENOMEM); + } + st->id = pkt->stream_index; + + fmt->pb = pb[0]; + if ((ret = av_copy_packet(&pkt2, pkt)) < 0 || + (ret = av_dup_packet(&pkt2)) < 0 || + (ret = avcodec_copy_context(st->codec, s->streams[0]->codec)) < 0 || + (ret = avformat_write_header(fmt, NULL)) < 0 || + (ret = av_interleaved_write_frame(fmt, &pkt2)) < 0 || + (ret = av_write_trailer(fmt)) < 0) { + av_free_packet(&pkt2); + avformat_free_context(fmt); + return ret; + } + av_free_packet(&pkt2); + avformat_free_context(fmt); } else { avio_write(pb[0], pkt->data, pkt->size); } @@ -128,8 +174,10 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) #define OFFSET(x) offsetof(VideoMuxData, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption muxoptions[] = { - { "updatefirst", "update the first image file", OFFSET(updatefirst), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, - { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, ENC }, + { "updatefirst", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, + { "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, + { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC }, + { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, { NULL }, }; @@ -145,8 +193,8 @@ AVOutputFormat ff_image2_muxer = { .name = "image2", .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), .extensions = "bmp,dpx,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png," - "ppm,sgi,tga,tif,tiff,jp2,j2c,xwd,sun,ras,rs,im1,im8,im24," - "sunras,xbm,xface", + "ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24," + "sunras,webp,xbm,xface", .priv_data_size = sizeof(VideoMuxData), .video_codec = AV_CODEC_ID_MJPEG, .write_header = write_header, diff --git a/ffmpeg/libavformat/internal.h b/ffmpeg/libavformat/internal.h index 4d56388..1560e9f 100644 --- a/ffmpeg/libavformat/internal.h +++ b/ffmpeg/libavformat/internal.h @@ -26,6 +26,10 @@ #define MAX_URL_SIZE 4096 +/** size of probe buffer, for guessing file type from file contents */ +#define PROBE_BUF_MIN 2048 +#define PROBE_BUF_MAX (1<<20) + #ifdef DEBUG # define hex_dump_debug(class, buf, size) av_hex_dump_log(class, AV_LOG_DEBUG, buf, size) #else @@ -90,31 +94,6 @@ void ff_read_frame_flush(AVFormatContext *s); uint64_t ff_ntp_time(void); /** - * Assemble a URL string from components. This is the reverse operation - * of av_url_split. - * - * Note, this requires networking to be initialized, so the caller must - * ensure ff_network_init has been called. - * - * @see av_url_split - * - * @param str the buffer to fill with the url - * @param size the size of the str buffer - * @param proto the protocol identifier, if null, the separator - * after the identifier is left out, too - * @param authorization an optional authorization string, may be null. - * An empty string is treated the same as a null string. - * @param hostname the host name string - * @param port the port number, left out from the string if negative - * @param fmt a generic format string for everything to add after the - * host/port, may be null - * @return the number of characters written to the destination buffer - */ -int ff_url_join(char *str, int size, const char *proto, - const char *authorization, const char *hostname, - int port, const char *fmt, ...) av_printf_format(7, 8); - -/** * Append the media-specific SDP fragment for the media stream c * to the buffer buff. * @@ -240,17 +219,6 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base, */ void ff_reduce_index(AVFormatContext *s, int stream_index); -/** - * Convert a relative url into an absolute url, given a base url. - * - * @param buf the buffer where output absolute url is written - * @param size the size of buf - * @param base the base url, may be equal to buf. - * @param rel the new url, which is interpreted relative to base - */ -void ff_make_absolute_url(char *buf, int size, const char *base, - const char *rel); - enum AVCodecID ff_guess_image2_codec(const char *filename); /** @@ -278,6 +246,9 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, */ void ff_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp); +int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos, + int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )); + /** * Perform a binary search using read_timestamp(). * @@ -386,10 +357,37 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags); AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precission); /** - * Generate standard extradata for AVC-Intra based on width/height and field order. + * Generate standard extradata for AVC-Intra based on width/height and field + * order. + */ +int ff_generate_avci_extradata(AVStream *st); + +/** + * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end + * which is always set to 0. + * + * @param size size of extradata + * @return 0 if OK, AVERROR_xxx on error + */ +int ff_alloc_extradata(AVCodecContext *avctx, int size); + +/** + * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end + * which is always set to 0 and fill it from pb. + * + * @param size size of extradata + * @return >= 0 if OK, AVERROR_xxx on error + */ +int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size); + +/** + * add frame for rfps calculation. + * + * @param dts timestamp of the i-th frame + * @return 0 if OK, AVERROR_xxx on error */ -void ff_generate_avci_extradata(AVStream *st); +int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t dts); -int ff_http_match_no_proxy(const char *no_proxy, const char *hostname); +void ff_rfps_calculate(AVFormatContext *ic); #endif /* AVFORMAT_INTERNAL_H */ diff --git a/ffmpeg/libavformat/ipmovie.c b/ffmpeg/libavformat/ipmovie.c index 676363b..4a766ef 100644 --- a/ffmpeg/libavformat/ipmovie.c +++ b/ffmpeg/libavformat/ipmovie.c @@ -321,7 +321,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_CREATE_TIMER: av_dlog(NULL, "create timer\n"); - if ((opcode_version > 0) || (opcode_size > 6)) { + if ((opcode_version > 0) || (opcode_size != 6)) { av_dlog(NULL, "bad create_timer opcode\n"); chunk_type = CHUNK_BAD; break; @@ -339,7 +339,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_INIT_AUDIO_BUFFERS: av_dlog(NULL, "initialize audio buffers\n"); - if ((opcode_version > 1) || (opcode_size > 10)) { + if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) { av_dlog(NULL, "bad init_audio_buffers opcode\n"); chunk_type = CHUNK_BAD; break; @@ -376,7 +376,9 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_INIT_VIDEO_BUFFERS: av_dlog(NULL, "initialize video buffers\n"); - if ((opcode_version > 2) || (opcode_size > 8)) { + if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4 + || opcode_version == 2 && opcode_size < 8 + ) { av_dlog(NULL, "bad init_video_buffers opcode\n"); chunk_type = CHUNK_BAD; break; @@ -449,8 +451,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, av_dlog(NULL, "set palette\n"); /* check for the logical maximum palette size * (3 * 256 + 4 bytes) */ - if (opcode_size > 0x304) { - av_dlog(NULL, "demux_ipmovie: set_palette opcode too large\n"); + if (opcode_size > 0x304 || opcode_size < 4) { + av_dlog(NULL, "demux_ipmovie: set_palette opcode with invalid size\n"); chunk_type = CHUNK_BAD; break; } @@ -463,7 +465,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, first_color = AV_RL16(&scratch[0]); last_color = first_color + AV_RL16(&scratch[2]) - 1; /* sanity check (since they are 16 bit values) */ - if ((first_color > 0xFF) || (last_color > 0xFF)) { + if ( (first_color > 0xFF) || (last_color > 0xFF) + || (last_color - first_color + 1)*3 + 4 > opcode_size) { av_dlog(NULL, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n", first_color, last_color); chunk_type = CHUNK_BAD; diff --git a/ffmpeg/libavformat/isom.c b/ffmpeg/libavformat/isom.c index 3f419a8..f6a4646 100644 --- a/ffmpeg/libavformat/isom.c +++ b/ffmpeg/libavformat/isom.c @@ -21,8 +21,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -//#define DEBUG - #include "avformat.h" #include "internal.h" #include "isom.h" @@ -153,6 +151,9 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('W', 'R', 'A', 'W') }, + { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */ + { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, /* HEVC/H.265 which indicates parameter sets may be in ES */ + { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'p') }, /* AVC-Intra 50M 720p24/30/60 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '5', 'q') }, /* AVC-Intra 50M 720p25/50 */ @@ -166,6 +167,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '3') }, /* AVC-Intra 100M 1080p24/30/60 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '5') }, /* AVC-Intra 100M 1080i50 */ { AV_CODEC_ID_H264, MKTAG('a', 'i', '1', '6') }, /* AVC-Intra 100M 1080i60 */ + { AV_CODEC_ID_H264, MKTAG('a', 'i', 'v', 'x') }, /* XAVC 4:2:2 10bit */ { AV_CODEC_ID_H264, MKTAG('A', 'V', 'i', 'n') }, /* AVC-Intra with implicit SPS/PPS */ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */ @@ -188,6 +190,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '4', 'p') }, /* MPEG2 IMX PAL 625/50 40mb/s produced by FCP */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'n') }, /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'p') }, /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */ + { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '1') }, /* XDCAM HD422 720p30 CBR */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '4') }, /* XDCAM HD422 720p24 CBR */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '5') }, /* XDCAM HD422 720p25 CBR */ { AV_CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', '5', '9') }, /* XDCAM HD422 720p60 CBR */ @@ -244,6 +247,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_PRORES, MKTAG('a', 'p', '4', 'h') }, /* Apple ProRes 4444 */ { AV_CODEC_ID_FLIC, MKTAG('f', 'l', 'i', 'c') }, + { AV_CODEC_ID_AIC, MKTAG('i', 'c', 'o', 'd') }, + { AV_CODEC_ID_NONE, 0 }, }; @@ -279,6 +284,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = { { AV_CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, { AV_CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, { AV_CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, + { AV_CODEC_ID_PCM_S16BE, MKTAG('l', 'p', 'c', 'm') }, { AV_CODEC_ID_PCM_S16LE, MKTAG('l', 'p', 'c', 'm') }, { AV_CODEC_ID_PCM_S24BE, MKTAG('i', 'n', '2', '4') }, { AV_CODEC_ID_PCM_S24LE, MKTAG('i', 'n', '2', '4') }, @@ -293,6 +299,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = { { AV_CODEC_ID_QDM2, MKTAG('Q', 'D', 'M', '2') }, { AV_CODEC_ID_QDMC, MKTAG('Q', 'D', 'M', 'C') }, { AV_CODEC_ID_SPEEX, MKTAG('s', 'p', 'e', 'x') }, /* Flash Media Server */ + { AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', 'N') }, { AV_CODEC_ID_WMAV2, MKTAG('W', 'M', 'A', '2') }, { AV_CODEC_ID_EVRC, MKTAG('s', 'e', 'v', 'c') }, /* 3GPP2 */ { AV_CODEC_ID_SMV, MKTAG('s', 's', 'm', 'v') }, /* 3GPP2 */ @@ -431,6 +438,7 @@ static const AVCodecTag mp4_audio_types[] = { int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext *pb) { int len, tag; + int ret; int object_type_id = avio_r8(pb); avio_r8(pb); /* stream type */ avio_rb24(pb); /* buffer size db */ @@ -450,13 +458,10 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext if (!len || (uint64_t)len > (1<<30)) return -1; av_free(st->codec->extradata); - st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, len); - st->codec->extradata_size = len; + if ((ret = ff_get_extradata(st->codec, pb, len)) < 0) + return ret; if (st->codec->codec_id == AV_CODEC_ID_AAC) { - MPEG4AudioConfig cfg; + MPEG4AudioConfig cfg = {0}; avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata, st->codec->extradata_size * 8, 1); st->codec->channels = cfg.channels; diff --git a/ffmpeg/libavformat/isom.h b/ffmpeg/libavformat/isom.h index 4154baf..2834b11 100644 --- a/ffmpeg/libavformat/isom.h +++ b/ffmpeg/libavformat/isom.h @@ -110,7 +110,7 @@ typedef struct MOVStreamContext { int ctts_index; int ctts_sample; unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom - unsigned int alt_sample_size; ///< always contains sample size from stsz atom + unsigned int stsz_sample_size; ///< always contains sample size from stsz atom unsigned int sample_count; int *sample_sizes; int keyframe_absent; @@ -162,6 +162,8 @@ typedef struct MOVContext { int use_absolute_path; int ignore_editlist; int64_t next_root_atom; ///< offset of the next root atom + int *bitrates; ///< bitrates read before streams creation + int bitrates_count; } MOVContext; int ff_mp4_read_descr_len(AVIOContext *pb); @@ -200,6 +202,27 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); #define MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO 0x02000000 #define MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES 0x01000000 +#define MOV_TKHD_FLAG_ENABLED 0x0001 +#define MOV_TKHD_FLAG_IN_MOVIE 0x0002 +#define MOV_TKHD_FLAG_IN_PREVIEW 0x0004 +#define MOV_TKHD_FLAG_IN_POSTER 0x0008 + +#define TAG_IS_AVCI(tag) \ + ((tag) == MKTAG('a', 'i', '5', 'p') || \ + (tag) == MKTAG('a', 'i', '5', 'q') || \ + (tag) == MKTAG('a', 'i', '5', '2') || \ + (tag) == MKTAG('a', 'i', '5', '3') || \ + (tag) == MKTAG('a', 'i', '5', '5') || \ + (tag) == MKTAG('a', 'i', '5', '6') || \ + (tag) == MKTAG('a', 'i', '1', 'p') || \ + (tag) == MKTAG('a', 'i', '1', 'q') || \ + (tag) == MKTAG('a', 'i', '1', '2') || \ + (tag) == MKTAG('a', 'i', '1', '3') || \ + (tag) == MKTAG('a', 'i', '1', '5') || \ + (tag) == MKTAG('a', 'i', '1', '6') || \ + (tag) == MKTAG('A', 'V', 'i', 'n')) + + int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb, MOVAtom atom); enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags); diff --git a/ffmpeg/libavformat/iss.c b/ffmpeg/libavformat/iss.c index e4335b4..e994531 100644 --- a/ffmpeg/libavformat/iss.c +++ b/ffmpeg/libavformat/iss.c @@ -76,14 +76,23 @@ static av_cold int iss_read_header(AVFormatContext *s) get_token(pb, token, sizeof(token)); //"IMA_ADPCM_Sound" get_token(pb, token, sizeof(token)); //packet size - sscanf(token, "%d", &iss->packet_size); + if (sscanf(token, "%d", &iss->packet_size) != 1) { + av_log(s, AV_LOG_ERROR, "Failed parsing packet size\n"); + return AVERROR_INVALIDDATA; + } get_token(pb, token, sizeof(token)); //File ID get_token(pb, token, sizeof(token)); //out size get_token(pb, token, sizeof(token)); //stereo - sscanf(token, "%d", &stereo); + if (sscanf(token, "%d", &stereo) != 1) { + av_log(s, AV_LOG_ERROR, "Failed parsing stereo flag\n"); + return AVERROR_INVALIDDATA; + } get_token(pb, token, sizeof(token)); //Unknown1 get_token(pb, token, sizeof(token)); //RateDivisor - sscanf(token, "%d", &rate_divisor); + if (sscanf(token, "%d", &rate_divisor) != 1) { + av_log(s, AV_LOG_ERROR, "Failed parsing rate_divisor\n"); + return AVERROR_INVALIDDATA; + } get_token(pb, token, sizeof(token)); //Unknown2 get_token(pb, token, sizeof(token)); //Version ID get_token(pb, token, sizeof(token)); //Size diff --git a/ffmpeg/libavformat/ivfenc.c b/ffmpeg/libavformat/ivfenc.c index ddb205b..45bae22 100644 --- a/ffmpeg/libavformat/ivfenc.c +++ b/ffmpeg/libavformat/ivfenc.c @@ -53,7 +53,6 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt) avio_wl32(pb, pkt->size); avio_wl64(pb, pkt->pts); avio_write(pb, pkt->data, pkt->size); - avio_flush(pb); return 0; } diff --git a/ffmpeg/libavformat/jacosubdec.c b/ffmpeg/libavformat/jacosubdec.c index 89e7e1b..e77ab40 100644 --- a/ffmpeg/libavformat/jacosubdec.c +++ b/ffmpeg/libavformat/jacosubdec.c @@ -43,8 +43,9 @@ typedef struct { static int timed_line(const char *ptr) { char c; + int fs, fe; return (sscanf(ptr, "%*u:%*u:%*u.%*u %*u:%*u:%*u.%*u %c", &c) == 1 || - sscanf(ptr, "@%*u @%*u %c", &c) == 1); + (sscanf(ptr, "@%u @%u %c", &fs, &fe, &c) == 3 && fs < fe)); } static int jacosub_probe(AVProbeData *p) @@ -60,10 +61,10 @@ static int jacosub_probe(AVProbeData *p) ptr++; if (*ptr != '#' && *ptr != '\n') { if (timed_line(ptr)) - return AVPROBE_SCORE_MAX/2 + 1; + return AVPROBE_SCORE_EXTENSION + 1; return 0; } - ptr += strcspn(ptr, "\n") + 1; + ptr += ff_subtitles_next_line(ptr); } return 0; } diff --git a/ffmpeg/libavformat/jvdec.c b/ffmpeg/libavformat/jvdec.c index e941492..03ac43d 100644 --- a/ffmpeg/libavformat/jvdec.c +++ b/ffmpeg/libavformat/jvdec.c @@ -33,10 +33,10 @@ #define JV_PREAMBLE_SIZE 5 typedef struct { - int audio_size; /** audio packet size (bytes) */ - int video_size; /** video packet size (bytes) */ - int palette_size; /** palette size (bytes) */ - int video_type; /** per-frame video compression type */ + int audio_size; /**< audio packet size (bytes) */ + int video_size; /**< video packet size (bytes) */ + int palette_size; /**< palette size (bytes) */ + int video_type; /**< per-frame video compression type */ } JVFrame; typedef struct { @@ -59,6 +59,15 @@ static int read_probe(AVProbeData *pd) return 0; } +static int read_close(AVFormatContext *s) +{ + JVDemuxContext *jv = s->priv_data; + + av_freep(&jv->frames); + + return 0; +} + static int read_header(AVFormatContext *s) { JVDemuxContext *jv = s->priv_data; @@ -119,10 +128,23 @@ static int read_header(AVFormatContext *s) jvf->audio_size = avio_rl32(pb); jvf->video_size = avio_rl32(pb); jvf->palette_size = avio_r8(pb) ? 768 : 0; - jvf->video_size = FFMIN(FFMAX(jvf->video_size, 0), - INT_MAX - JV_PREAMBLE_SIZE - jvf->palette_size); + + if ((jvf->video_size | jvf->audio_size) & ~0xFFFFFF || + e->size - jvf->audio_size + - jvf->video_size + - jvf->palette_size < 0) { + if (s->error_recognition & AV_EF_EXPLODE) { + read_close(s); + return AVERROR_INVALIDDATA; + } + jvf->audio_size = + jvf->video_size = + jvf->palette_size = 0; + } + if (avio_r8(pb)) av_log(s, AV_LOG_WARNING, "unsupported audio codec\n"); + jvf->video_type = avio_r8(pb); avio_skip(pb, 1); @@ -184,6 +206,9 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) } } + if (s->pb->eof_reached) + return AVERROR_EOF; + return AVERROR(EIO); } @@ -218,15 +243,6 @@ static int read_seek(AVFormatContext *s, int stream_index, return 0; } -static int read_close(AVFormatContext *s) -{ - JVDemuxContext *jv = s->priv_data; - - av_freep(&jv->frames); - - return 0; -} - AVInputFormat ff_jv_demuxer = { .name = "jv", .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV"), diff --git a/ffmpeg/libavformat/latmenc.c b/ffmpeg/libavformat/latmenc.c index 9dfb4e4..e69de2b 100644 --- a/ffmpeg/libavformat/latmenc.c +++ b/ffmpeg/libavformat/latmenc.c @@ -2,20 +2,20 @@ * LATM/LOAS muxer * Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com> * - * 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 */ @@ -124,7 +124,7 @@ static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs) if (!ctx->channel_conf) { GetBitContext gb; - init_get_bits(&gb, avctx->extradata, avctx->extradata_size * 8); + init_get_bits8(&gb, avctx->extradata, avctx->extradata_size); skip_bits_long(&gb, ctx->off + 3); avpriv_copy_pce_data(bs, &gb); } diff --git a/ffmpeg/libavformat/libavformat.pc b/ffmpeg/libavformat/libavformat.pc index ef9016f..460614c 100644 --- a/ffmpeg/libavformat/libavformat.pc +++ b/ffmpeg/libavformat/libavformat.pc @@ -5,10 +5,10 @@ includedir=${prefix}/include Name: libavformat Description: FFmpeg container format library -Version: 55.0.100 +Version: 55.22.100 Requires: -Requires.private: libavcodec = 55.1.100 +Requires.private: libavcodec = 55.46.100 Conflicts: -Libs: -L${libdir} -lavformat -Libs.private: -ldl -lXfixes -lXext -lX11 -ljack -lasound -lxvidcore -lx264 -lvorbisenc -lvorbis -logg -ltheoraenc -ltheoradec -logg -lschroedinger-1.0 -lmp3lame -lfaac -lm -pthread -lz -lrt +Libs: -L${libdir} -lavformat +Libs.private: -lXfixes -lXext -lX11 -lx264 -lmp3lame -lm -lz -pthread Cflags: -I${includedir} diff --git a/ffmpeg/libavformat/libmodplug.c b/ffmpeg/libavformat/libmodplug.c index aa8edcc..836b7c2 100644 --- a/ffmpeg/libavformat/libmodplug.c +++ b/ffmpeg/libavformat/libmodplug.c @@ -166,14 +166,14 @@ static int modplug_read_header(AVFormatContext *s) AVIOContext *pb = s->pb; ModPlug_Settings settings; ModPlugContext *modplug = s->priv_data; - int sz = avio_size(pb); + int64_t sz = avio_size(pb); if (sz < 0) { av_log(s, AV_LOG_WARNING, "Could not determine file size\n"); sz = modplug->max_size; } else if (modplug->max_size && sz > modplug->max_size) { sz = modplug->max_size; - av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %dB " + av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %"PRIi64"B " "but demuxing is likely to fail due to incomplete buffer\n", sz == FF_MODPLUG_DEF_FILE_SIZE ? " (see -max_size)" : "", sz); } @@ -347,6 +347,19 @@ static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int return 0; } +static const char modplug_extensions[] = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm,itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz"; + +static int modplug_probe(AVProbeData *p) +{ + if (av_match_ext(p->filename, modplug_extensions)) { + if (p->buf_size < 16384) + return AVPROBE_SCORE_EXTENSION/2-1; + else + return AVPROBE_SCORE_EXTENSION; + } + return 0; +} + static const AVClass modplug_class = { .class_name = "ModPlug demuxer", .item_name = av_default_item_name, @@ -358,11 +371,11 @@ AVInputFormat ff_libmodplug_demuxer = { .name = "libmodplug", .long_name = NULL_IF_CONFIG_SMALL("ModPlug demuxer"), .priv_data_size = sizeof(ModPlugContext), + .read_probe = modplug_probe, .read_header = modplug_read_header, .read_packet = modplug_read_packet, .read_close = modplug_read_close, .read_seek = modplug_read_seek, - .extensions = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm" - ",itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz", // compressed mods + .extensions = modplug_extensions, .priv_class = &modplug_class, }; diff --git a/ffmpeg/libavformat/libnut.c b/ffmpeg/libavformat/libnut.c index 838c55a..be8f3cb 100644 --- a/ffmpeg/libavformat/libnut.c +++ b/ffmpeg/libavformat/libnut.c @@ -223,14 +223,16 @@ static int nut_read_header(AVFormatContext * avf) { AVStream * st = avformat_new_stream(avf, NULL); int j; + if (!st) + return AVERROR(ENOMEM); + for (j = 0; j < s[i].fourcc_len && j < 8; j++) st->codec->codec_tag |= s[i].fourcc[j]<<(j*8); st->codec->has_b_frames = s[i].decode_delay; st->codec->extradata_size = s[i].codec_specific_len; if (st->codec->extradata_size) { - st->codec->extradata = av_mallocz(st->codec->extradata_size); - if(!st->codec->extradata){ + if(ff_alloc_extradata(st->codec, st->codec->extradata_size)){ nut_demuxer_uninit(nut); priv->nut = NULL; return AVERROR(ENOMEM); diff --git a/ffmpeg/libavformat/loasdec.c b/ffmpeg/libavformat/loasdec.c index d3a8dbd..05ef0fe 100644 --- a/ffmpeg/libavformat/loasdec.c +++ b/ffmpeg/libavformat/loasdec.c @@ -52,9 +52,9 @@ static int loas_probe(AVProbeData *p) if(buf == buf0) first_frames= frames; } - if (first_frames>=3) return AVPROBE_SCORE_MAX/2+1; - else if(max_frames>100)return AVPROBE_SCORE_MAX/2; - else if(max_frames>=3) return AVPROBE_SCORE_MAX/4; + if (first_frames>=3) return AVPROBE_SCORE_EXTENSION+1; + else if(max_frames>100)return AVPROBE_SCORE_EXTENSION; + else if(max_frames>=3) return AVPROBE_SCORE_EXTENSION / 2; else return 0; } diff --git a/ffmpeg/libavformat/lvfdec.c b/ffmpeg/libavformat/lvfdec.c index f8dda58..1ff67c8 100644 --- a/ffmpeg/libavformat/lvfdec.c +++ b/ffmpeg/libavformat/lvfdec.c @@ -25,9 +25,13 @@ static int lvf_probe(AVProbeData *p) { - if (AV_RL32(p->buf) == MKTAG('L', 'V', 'F', 'F')) - return AVPROBE_SCORE_MAX / 2; - return 0; + if (AV_RL32(p->buf) != MKTAG('L', 'V', 'F', 'F')) + return 0; + + if (!AV_RL32(p->buf + 16) || AV_RL32(p->buf + 16) > 256) + return AVPROBE_SCORE_MAX / 8; + + return AVPROBE_SCORE_EXTENSION; } static int lvf_read_header(AVFormatContext *s) diff --git a/ffmpeg/libavformat/lxfdec.c b/ffmpeg/libavformat/lxfdec.c index 876f988..f0a9639 100644 --- a/ffmpeg/libavformat/lxfdec.c +++ b/ffmpeg/libavformat/lxfdec.c @@ -29,7 +29,6 @@ #define LXF_IDENT "LEITCH\0" #define LXF_IDENT_LENGTH 8 #define LXF_SAMPLERATE 48000 -#define LXF_MAX_AUDIO_PACKET (8008*15*4) ///< 15-channel 32-bit NTSC audio frame static const AVCodecTag lxf_tags[] = { { AV_CODEC_ID_MJPEG, 0 }, @@ -116,7 +115,7 @@ static int get_packet_header(AVFormatContext *s) uint32_t version, audio_format, header_size, channels, tmp; AVStream *st; uint8_t header[LXF_MAX_PACKET_HEADER_SIZE]; - const uint8_t *p; + const uint8_t *p = header + LXF_IDENT_LENGTH; //find and read the ident if ((ret = sync(s, header)) < 0) @@ -126,11 +125,11 @@ static int get_packet_header(AVFormatContext *s) if (ret != 8) return ret < 0 ? ret : AVERROR_EOF; - p = header + LXF_IDENT_LENGTH; version = bytestream_get_le32(&p); header_size = bytestream_get_le32(&p); if (version > 1) - avpriv_request_sample(s, "format version %i", version); + avpriv_request_sample(s, "Unknown format version %i\n", version); + if (header_size < (version ? 72 : 60) || header_size > LXF_MAX_PACKET_HEADER_SIZE || (header_size & 3)) { @@ -141,9 +140,8 @@ static int get_packet_header(AVFormatContext *s) //read the rest of the packet header if ((ret = avio_read(pb, header + (p - header), header_size - (p - header))) != - header_size - (p - header)) { + header_size - (p - header)) return ret < 0 ? ret : AVERROR_EOF; - } if (check_checksum(header, header_size)) av_log(s, AV_LOG_ERROR, "checksum error\n"); @@ -163,16 +161,19 @@ static int get_packet_header(AVFormatContext *s) break; case 1: //audio - if (!s->streams || !(st = s->streams[1])) { + if (s->nb_streams < 2) { av_log(s, AV_LOG_INFO, "got audio packet, but no audio stream present\n"); break; } - if (version == 0) p += 8; + if (version == 0) + p += 8; audio_format = bytestream_get_le32(&p); channels = bytestream_get_le32(&p); track_size = bytestream_get_le32(&p); + st = s->streams[1]; + //set codec based on specified audio bitdepth //we only support tightly packed 16-, 20-, 24- and 32-bit PCM at the moment st->codec->bits_per_coded_sample = (audio_format >> 6) & 0x3F; @@ -258,6 +259,7 @@ static int lxf_read_header(AVFormatContext *s) st->codec->bit_rate = 1000000 * ((video_params >> 14) & 0xFF); st->codec->codec_tag = video_params & 0xF; st->codec->codec_id = ff_codec_get_id(lxf_tags, st->codec->codec_tag); + st->need_parsing = AVSTREAM_PARSE_HEADERS; av_log(s, AV_LOG_DEBUG, "record: %x = %i-%02i-%02i\n", record_date, 1900 + (record_date & 0x7F), (record_date >> 7) & 0xF, @@ -290,7 +292,6 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) { LXFDemuxContext *lxf = s->priv_data; AVIOContext *pb = s->pb; - AVStream *ast = NULL; uint32_t stream; int ret, ret2; @@ -304,18 +305,11 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EAGAIN); } - if (stream == 1 && !(ast = s->streams[1])) { + if (stream == 1 && s->nb_streams < 2) { av_log(s, AV_LOG_ERROR, "got audio packet without having an audio stream\n"); return AVERROR_INVALIDDATA; } - //make sure the data fits in the de-planerization buffer - if (ast && ret > LXF_MAX_AUDIO_PACKET) { - av_log(s, AV_LOG_ERROR, "audio packet too large (%i > %i)\n", - ret, LXF_MAX_AUDIO_PACKET); - return AVERROR_INVALIDDATA; - } - if ((ret2 = av_new_packet(pkt, ret)) < 0) return ret2; @@ -326,7 +320,7 @@ static int lxf_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->stream_index = stream; - if (!ast) { + if (!stream) { //picture type (0 = closed I, 1 = open I, 2 = P, 3 = B) if (((lxf->video_format >> 22) & 0x3) < 2) pkt->flags |= AV_PKT_FLAG_KEY; diff --git a/ffmpeg/libavformat/m4vdec.c b/ffmpeg/libavformat/m4vdec.c index e72fb42..c2fd4d7 100644 --- a/ffmpeg/libavformat/m4vdec.c +++ b/ffmpeg/libavformat/m4vdec.c @@ -45,7 +45,7 @@ static int mpeg4video_probe(AVProbeData *probe_packet) } if (VOP >= VISO && VOP >= VOL && VO >= VOL && VOL > 0 && res==0) - return VOP+VO > 3 ? AVPROBE_SCORE_MAX/2 : AVPROBE_SCORE_MAX/4; + return VOP+VO > 3 ? AVPROBE_SCORE_EXTENSION : AVPROBE_SCORE_EXTENSION/2; return 0; } diff --git a/ffmpeg/libavformat/matroska.c b/ffmpeg/libavformat/matroska.c index 09eecf2..77a88a8 100644 --- a/ffmpeg/libavformat/matroska.c +++ b/ffmpeg/libavformat/matroska.c @@ -35,8 +35,8 @@ const CodecTags ff_mkv_codec_tags[]={ {"A_MPEG/L2" , AV_CODEC_ID_MP2}, {"A_MPEG/L1" , AV_CODEC_ID_MP2}, {"A_MPEG/L3" , AV_CODEC_ID_MP3}, - {"A_OPUS/EXPERIMENTAL",AV_CODEC_ID_OPUS}, {"A_OPUS", AV_CODEC_ID_OPUS}, + {"A_OPUS/EXPERIMENTAL",AV_CODEC_ID_OPUS}, {"A_PCM/FLOAT/IEEE" , AV_CODEC_ID_PCM_F32LE}, {"A_PCM/FLOAT/IEEE" , AV_CODEC_ID_PCM_F64LE}, {"A_PCM/INT/BIG" , AV_CODEC_ID_PCM_S16BE}, @@ -57,14 +57,25 @@ const CodecTags ff_mkv_codec_tags[]={ {"A_VORBIS" , AV_CODEC_ID_VORBIS}, {"A_WAVPACK4" , AV_CODEC_ID_WAVPACK}, + {"D_WEBVTT/SUBTITLES" , AV_CODEC_ID_WEBVTT}, + {"D_WEBVTT/CAPTIONS" , AV_CODEC_ID_WEBVTT}, + {"D_WEBVTT/DESCRIPTIONS", AV_CODEC_ID_WEBVTT}, + {"D_WEBVTT/METADATA" , AV_CODEC_ID_WEBVTT}, + {"S_TEXT/UTF8" , AV_CODEC_ID_SUBRIP}, {"S_TEXT/UTF8" , AV_CODEC_ID_TEXT}, {"S_TEXT/UTF8" , AV_CODEC_ID_SRT}, {"S_TEXT/ASCII" , AV_CODEC_ID_TEXT}, +#if FF_API_ASS_SSA {"S_TEXT/ASS" , AV_CODEC_ID_SSA}, {"S_TEXT/SSA" , AV_CODEC_ID_SSA}, {"S_ASS" , AV_CODEC_ID_SSA}, {"S_SSA" , AV_CODEC_ID_SSA}, +#endif + {"S_TEXT/ASS" , AV_CODEC_ID_ASS}, + {"S_TEXT/SSA" , AV_CODEC_ID_ASS}, + {"S_ASS" , AV_CODEC_ID_ASS}, + {"S_SSA" , AV_CODEC_ID_ASS}, {"S_VOBSUB" , AV_CODEC_ID_DVD_SUBTITLE}, {"S_DVBSUB" , AV_CODEC_ID_DVB_SUBTITLE}, {"S_HDMV/PGS" , AV_CODEC_ID_HDMV_PGS_SUBTITLE}, @@ -77,6 +88,7 @@ const CodecTags ff_mkv_codec_tags[]={ {"V_MPEG4/ISO/AP" , AV_CODEC_ID_MPEG4}, {"V_MPEG4/ISO/SP" , AV_CODEC_ID_MPEG4}, {"V_MPEG4/ISO/AVC" , AV_CODEC_ID_H264}, + {"V_MPEGH/ISO/HEVC" , AV_CODEC_ID_HEVC}, {"V_MPEG4/MS/V3" , AV_CODEC_ID_MSMPEG4V3}, {"V_PRORES" , AV_CODEC_ID_PRORES}, {"V_REAL/RV10" , AV_CODEC_ID_RV10}, diff --git a/ffmpeg/libavformat/matroska.h b/ffmpeg/libavformat/matroska.h index 8a7e10b..3bb5aee 100644 --- a/ffmpeg/libavformat/matroska.h +++ b/ffmpeg/libavformat/matroska.h @@ -91,6 +91,8 @@ #define MATROSKA_ID_CODECINFOURL 0x3B4040 #define MATROSKA_ID_CODECDOWNLOADURL 0x26B240 #define MATROSKA_ID_CODECDECODEALL 0xAA +#define MATROSKA_ID_CODECDELAY 0x56AA +#define MATROSKA_ID_SEEKPREROLL 0x56BB #define MATROSKA_ID_TRACKNAME 0x536E #define MATROSKA_ID_TRACKLANGUAGE 0x22B59C #define MATROSKA_ID_TRACKFLAGENABLED 0xB9 @@ -156,6 +158,8 @@ /* IDs in the cuetrackposition master */ #define MATROSKA_ID_CUETRACK 0xF7 #define MATROSKA_ID_CUECLUSTERPOSITION 0xF1 +#define MATROSKA_ID_CUERELATIVEPOSITION 0xF0 +#define MATROSKA_ID_CUEDURATION 0xB2 #define MATROSKA_ID_CUEBLOCKNUMBER 0x5378 /* IDs in the tags master */ @@ -195,6 +199,8 @@ #define MATROSKA_ID_BLOCK 0xA1 #define MATROSKA_ID_BLOCKDURATION 0x9B #define MATROSKA_ID_BLOCKREFERENCE 0xFB +#define MATROSKA_ID_CODECSTATE 0xA4 +#define MATROSKA_ID_DISCARDPADDING 0x75A2 /* IDs in the attachments master */ #define MATROSKA_ID_ATTACHEDFILE 0x61A7 @@ -229,6 +235,7 @@ typedef enum { MATROSKA_TRACK_TYPE_LOGO = 0x10, MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, MATROSKA_TRACK_TYPE_CONTROL = 0x20, + MATROSKA_TRACK_TYPE_METADATA = 0x21, } MatroskaTrackType; typedef enum { @@ -261,7 +268,7 @@ typedef enum { */ typedef struct CodecTags{ - char str[20]; + char str[22]; enum AVCodecID id; }CodecTags; diff --git a/ffmpeg/libavformat/matroskadec.c b/ffmpeg/libavformat/matroskadec.c index eea29da..e994786 100644 --- a/ffmpeg/libavformat/matroskadec.c +++ b/ffmpeg/libavformat/matroskadec.c @@ -62,6 +62,7 @@ typedef enum { EBML_NEST, EBML_PASS, EBML_STOP, + EBML_SINT, EBML_TYPE_COUNT } EbmlType; @@ -163,6 +164,8 @@ typedef struct { uint64_t default_duration; uint64_t flag_default; uint64_t flag_forced; + uint64_t codec_delay; + uint64_t seek_preroll; MatroskaTrackVideo video; MatroskaTrackAudio audio; MatroskaTrackOperation operation; @@ -290,6 +293,7 @@ typedef struct { EbmlBin bin; uint64_t additional_id; EbmlBin additional; + int64_t discard_padding; } MatroskaBlock; static EbmlSyntax ebml_header[] = { @@ -321,8 +325,8 @@ static EbmlSyntax matroska_info[] = { static EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT,0, offsetof(MatroskaTrackVideo,frame_rate) }, - { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_width) }, - { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height) }, + { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_width), {.u=-1} }, + { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height), {.u=-1} }, { MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_width) }, { MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_height) }, { MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo,color_space) }, @@ -409,6 +413,8 @@ static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKOPERATION, EBML_NEST, 0, offsetof(MatroskaTrack,operation), {.n=matroska_track_operation} }, { MATROSKA_ID_TRACKCONTENTENCODINGS,EBML_NEST, 0, 0, {.n=matroska_track_encodings} }, { MATROSKA_ID_TRACKMAXBLKADDID, EBML_UINT, 0, offsetof(MatroskaTrack,max_block_additional_id) }, + { MATROSKA_ID_CODECDELAY, EBML_UINT, 0, offsetof(MatroskaTrack,codec_delay) }, + { MATROSKA_ID_SEEKPREROLL, EBML_UINT, 0, offsetof(MatroskaTrack,seek_preroll) }, { MATROSKA_ID_TRACKFLAGENABLED, EBML_NONE }, { MATROSKA_ID_TRACKFLAGLACING, EBML_NONE }, { MATROSKA_ID_CODECNAME, EBML_NONE }, @@ -474,6 +480,8 @@ static EbmlSyntax matroska_chapters[] = { static EbmlSyntax matroska_index_pos[] = { { MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos,track) }, { MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos,pos) }, + { MATROSKA_ID_CUERELATIVEPOSITION,EBML_NONE }, + { MATROSKA_ID_CUEDURATION, EBML_NONE }, { MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE }, { 0 } }; @@ -563,7 +571,9 @@ static EbmlSyntax matroska_blockgroup[] = { { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, {.n=matroska_blockadditions} }, { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) }, { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration) }, - { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) }, + { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock,discard_padding) }, + { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock,reference) }, + { MATROSKA_ID_CODECSTATE, EBML_NONE }, { 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} }, { 0 } }; @@ -627,21 +637,20 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) matroska->current_id = 0; matroska->num_levels = 0; - // seek to next position to resync from - if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0 || avio_tell(pb) <= last_pos) + /* seek to next position to resync from */ + if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0) goto eof; id = avio_rb32(pb); // try to find a toplevel element while (!url_feof(pb)) { - if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS || - id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS || + if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS || + id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS || id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS || - id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) - { - matroska->current_id = id; - return 0; + id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) { + matroska->current_id = id; + return 0; } id = (id << 8) | avio_r8(pb); } @@ -751,6 +760,30 @@ static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num) } /* + * Read the next element as a signed int. + * 0 is success, < 0 is failure. + */ +static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num) +{ + int n = 1; + + if (size > 8) + return AVERROR_INVALIDDATA; + + if (size == 0) { + *num = 0; + } else { + *num = sign_extend(avio_r8(pb), 8); + + /* big-endian ordering; build up number */ + while (n++ < size) + *num = (*num << 8) | avio_r8(pb); + } + + return 0; +} + +/* * Read the next element as a float. * 0 is success, < 0 is failure. */ @@ -916,7 +949,13 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, break; case EBML_STR: case EBML_UTF8: - *(char **)((char *)data+syntax[i].data_offset) = av_strdup(syntax[i].def.s); + // the default may be NULL + if (syntax[i].def.s) { + uint8_t **dst = (uint8_t**)((uint8_t*)data + syntax[i].data_offset); + *dst = av_strdup(syntax[i].def.s); + if (!*dst) + return AVERROR(ENOMEM); + } break; } @@ -948,7 +987,7 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, data = (char *)data + syntax->data_offset; if (syntax->list_elem_size) { EbmlList *list = data; - newelem = av_realloc(list->elem, (list->nb_elem+1)*syntax->list_elem_size); + newelem = av_realloc_array(list->elem, list->nb_elem+1, syntax->list_elem_size); if (!newelem) return AVERROR(ENOMEM); list->elem = newelem; @@ -971,6 +1010,7 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, switch (syntax->type) { case EBML_UINT: res = ebml_read_uint (pb, length, data); break; + case EBML_SINT: res = ebml_read_sint (pb, length, data); break; case EBML_FLOAT: res = ebml_read_float (pb, length, data); break; case EBML_STR: case EBML_UTF8: res = ebml_read_ascii (pb, length, data); break; @@ -1060,7 +1100,7 @@ static int matroska_probe(AVProbeData *p) } // probably valid EBML header but no recognized doctype - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; } static MatroskaTrack *matroska_find_track_by_num(MatroskaDemuxContext *matroska, @@ -1213,6 +1253,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, return result; } +#if FF_API_ASS_SSA static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, AVPacket *pkt, uint64_t display_duration) { @@ -1259,6 +1300,7 @@ static int matroska_merge_packets(AVPacket *out, AVPacket *in) av_free(in); return 0; } +#endif static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, AVDictionary **metadata, char *prefix) @@ -1268,7 +1310,8 @@ static void matroska_convert_tag(AVFormatContext *s, EbmlList *list, int i; for (i=0; i < list->nb_elem; i++) { - const char *lang= (tags[i].lang && strcmp(tags[i].lang, "und")) ? tags[i].lang : NULL; + const char *lang = tags[i].lang && strcmp(tags[i].lang, "und") ? + tags[i].lang : NULL; if (!tags[i].name) { av_log(s, AV_LOG_WARNING, "Skipping invalid tag with no TagName.\n"); @@ -1442,7 +1485,7 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska) { for (i = 0; i < seekhead_list->nb_elem; i++) if (seekhead[i].id == MATROSKA_ID_CUES) break; - assert(i <= seekhead_list->nb_elem); + av_assert1(i <= seekhead_list->nb_elem); if (matroska_parse_seekhead_entry(matroska, i) < 0) matroska->cues_parsing_deferred = -1; @@ -1564,7 +1607,8 @@ static int matroska_read_header(AVFormatContext *s) /* Apply some sanity checks. */ if (track->type != MATROSKA_TRACK_TYPE_VIDEO && track->type != MATROSKA_TRACK_TYPE_AUDIO && - track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { + track->type != MATROSKA_TRACK_TYPE_SUBTITLE && + track->type != MATROSKA_TRACK_TYPE_METADATA) { av_log(matroska->ctx, AV_LOG_INFO, "Unknown or unsupported track type %"PRIu64"\n", track->type); @@ -1576,9 +1620,9 @@ static int matroska_read_header(AVFormatContext *s) if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { if (!track->default_duration && track->video.frame_rate > 0) track->default_duration = 1000000000/track->video.frame_rate; - if (!track->video.display_width) + if (track->video.display_width == -1) track->video.display_width = track->video.pixel_width; - if (!track->video.display_height) + if (track->video.display_height == -1) track->video.display_height = track->video.pixel_height; if (track->video.color_space.size == 4) fourcc = AV_RL32(track->video.color_space.data); @@ -1681,18 +1725,6 @@ static int matroska_read_header(AVFormatContext *s) && (track->codec_priv.data != NULL)) { fourcc = AV_RL32(track->codec_priv.data); codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc); - } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) { - /* Only ALAC's magic cookie is stored in Matroska's track headers. - Create the "atom size", "tag", and "tag version" fields the - decoder expects manually. */ - extradata_size = 12 + track->codec_priv.size; - extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (extradata == NULL) - return AVERROR(ENOMEM); - AV_WB32(extradata, extradata_size); - memcpy(&extradata[4], "alac", 4); - AV_WB32(&extradata[8], 0); - memcpy(&extradata[12], track->codec_priv.data, track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_PCM_S16BE) { switch (track->audio.bitdepth) { case 8: codec_id = AV_CODEC_ID_PCM_U8; break; @@ -1723,6 +1755,19 @@ static int matroska_read_header(AVFormatContext *s) extradata_size = 5; } else extradata_size = 2; + } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) { + /* Only ALAC's magic cookie is stored in Matroska's track headers. + Create the "atom size", "tag", and "tag version" fields the + decoder expects manually. */ + extradata_size = 12 + track->codec_priv.size; + extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + if (extradata == NULL) + return AVERROR(ENOMEM); + AV_WB32(extradata, extradata_size); + memcpy(&extradata[4], "alac", 4); + AV_WB32(&extradata[8], 0); + memcpy(&extradata[12], track->codec_priv.data, + track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_TTA) { extradata_size = 30; extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); @@ -1734,8 +1779,10 @@ static int matroska_read_header(AVFormatContext *s) avio_wl16(&b, 1); avio_wl16(&b, track->audio.channels); avio_wl16(&b, track->audio.bitdepth); + if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX) + return AVERROR_INVALIDDATA; avio_wl32(&b, track->audio.out_samplerate); - avio_wl32(&b, matroska->ctx->duration * track->audio.out_samplerate); + avio_wl32(&b, av_rescale((matroska->duration * matroska->time_scale), track->audio.out_samplerate, AV_TIME_BASE * 1000)); } else if (codec_id == AV_CODEC_ID_RV10 || codec_id == AV_CODEC_ID_RV20 || codec_id == AV_CODEC_ID_RV30 || codec_id == AV_CODEC_ID_RV40) { extradata_offset = 26; @@ -1756,13 +1803,19 @@ static int matroska_read_header(AVFormatContext *s) track->audio.sub_packet_h = avio_rb16(&b); track->audio.frame_size = avio_rb16(&b); track->audio.sub_packet_size = avio_rb16(&b); - track->audio.buf = av_malloc(track->audio.frame_size * track->audio.sub_packet_h); + if (flavor < 0 || track->audio.coded_framesize <= 0 || + track->audio.sub_packet_h <= 0 || track->audio.frame_size <= 0 || + track->audio.sub_packet_size <= 0) + return AVERROR_INVALIDDATA; + track->audio.buf = av_malloc_array(track->audio.sub_packet_h, track->audio.frame_size); + if (!track->audio.buf) + return AVERROR(ENOMEM); if (codec_id == AV_CODEC_ID_RA_288) { st->codec->block_align = track->audio.coded_framesize; track->codec_priv.size = 0; } else { if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) { - const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 }; + static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 }; track->audio.sub_packet_size = ff_sipr_subpk_size[flavor]; st->codec->bit_rate = sipr_bit_rate[flavor]; } @@ -1781,7 +1834,7 @@ static int matroska_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, matroska->time_scale*track->time_scale, 1000*1000*1000); /* 64 bit pts in ns */ st->codec->codec_id = codec_id; - st->start_time = 0; + if (strcmp(track->language, "und")) av_dict_set(&st->metadata, "language", track->language, 0); av_dict_set(&st->metadata, "title", track->name, 0); @@ -1796,11 +1849,8 @@ static int matroska_read_header(AVFormatContext *s) st->codec->extradata = extradata; st->codec->extradata_size = extradata_size; } else if(track->codec_priv.data && track->codec_priv.size > 0){ - st->codec->extradata = av_mallocz(track->codec_priv.size + - FF_INPUT_BUFFER_PADDING_SIZE); - if(st->codec->extradata == NULL) + if (ff_alloc_extradata(st->codec, track->codec_priv.size)) return AVERROR(ENOMEM); - st->codec->extradata_size = track->codec_priv.size; memcpy(st->codec->extradata, track->codec_priv.data + extradata_offset, track->codec_priv.size); @@ -1819,12 +1869,15 @@ static int matroska_read_header(AVFormatContext *s) st->codec->height * track->video.display_width, st->codec-> width * track->video.display_height, 255); - st->need_parsing = AVSTREAM_PARSE_HEADERS; + if (st->codec->codec_id != AV_CODEC_ID_HEVC) + st->need_parsing = AVSTREAM_PARSE_HEADERS; + if (track->default_duration) { av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, 1000000000, track->default_duration, 30000); #if FF_API_R_FRAME_RATE - st->r_frame_rate = st->avg_frame_rate; + if (st->avg_frame_rate.num < st->avg_frame_rate.den * 1000L) + st->r_frame_rate = st->avg_frame_rate; #endif } @@ -1857,9 +1910,35 @@ static int matroska_read_header(AVFormatContext *s) st->codec->bits_per_coded_sample = track->audio.bitdepth; if (st->codec->codec_id != AV_CODEC_ID_AAC) st->need_parsing = AVSTREAM_PARSE_HEADERS; + if (track->codec_delay > 0) { + st->codec->delay = av_rescale_q(track->codec_delay, + (AVRational){1, 1000000000}, + (AVRational){1, st->codec->sample_rate}); + } + if (track->seek_preroll > 0) { + av_codec_set_seek_preroll(st->codec, + av_rescale_q(track->seek_preroll, + (AVRational){1, 1000000000}, + (AVRational){1, st->codec->sample_rate})); + } + } else if (codec_id == AV_CODEC_ID_WEBVTT) { + st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; + + if (!strcmp(track->codec_id, "D_WEBVTT/CAPTIONS")) { + st->disposition |= AV_DISPOSITION_CAPTIONS; + } else if (!strcmp(track->codec_id, "D_WEBVTT/DESCRIPTIONS")) { + st->disposition |= AV_DISPOSITION_DESCRIPTIONS; + } else if (!strcmp(track->codec_id, "D_WEBVTT/METADATA")) { + st->disposition |= AV_DISPOSITION_METADATA; + } } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - if (st->codec->codec_id == AV_CODEC_ID_SSA) +#if FF_API_ASS_SSA + if (st->codec->codec_id == AV_CODEC_ID_SSA || + st->codec->codec_id == AV_CODEC_ID_ASS) +#else + if (st->codec->codec_id == AV_CODEC_ID_ASS) +#endif matroska->contains_ssa = 1; } } @@ -1877,10 +1956,8 @@ static int matroska_read_header(AVFormatContext *s) av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0); st->codec->codec_id = AV_CODEC_ID_NONE; st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; - st->codec->extradata = av_malloc(attachements[j].bin.size + FF_INPUT_BUFFER_PADDING_SIZE); - if(st->codec->extradata == NULL) + if (ff_alloc_extradata(st->codec, attachements[j].bin.size)) break; - st->codec->extradata_size = attachements[j].bin.size; memcpy(st->codec->extradata, attachements[j].bin.data, attachements[j].bin.size); for (i=0; ff_mkv_mime_tags[i].id != AV_CODEC_ID_NONE; i++) { @@ -1961,10 +2038,10 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska) } static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, - int size, int type, + int* buf_size, int type, uint32_t **lace_buf, int *laces) { - int res = 0, n; + int res = 0, n, size = *buf_size; uint8_t *data = *buf; uint32_t *lace_size; @@ -1992,18 +2069,18 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, uint32_t total = 0; for (n = 0; res == 0 && n < *laces - 1; n++) { while (1) { - if (size == 0) { - res = AVERROR_EOF; + if (size <= total) { + res = AVERROR_INVALIDDATA; break; } temp = *data; + total += temp; lace_size[n] += temp; data += 1; size -= 1; if (temp != 0xff) break; } - total += lace_size[n]; } if (size <= total) { res = AVERROR_INVALIDDATA; @@ -2025,12 +2102,12 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, case 0x3: /* EBML lacing */ { uint64_t num; - uint32_t total; + uint64_t total; n = matroska_ebmlnum_uint(matroska, data, size, &num); - if (n < 0) { + if (n < 0 || num > INT_MAX) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); - res = n; + res = n<0 ? n : AVERROR_INVALIDDATA; break; } data += n; @@ -2040,10 +2117,10 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, int64_t snum; int r; r = matroska_ebmlnum_sint(matroska, data, size, &snum); - if (r < 0) { + if (r < 0 || lace_size[n - 1] + snum > (uint64_t)INT_MAX) { av_log(matroska->ctx, AV_LOG_INFO, "EBML block data error\n"); - res = r; + res = r<0 ? r : AVERROR_INVALIDDATA; break; } data += r; @@ -2062,6 +2139,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, *buf = data; *lace_buf = lace_size; + *buf_size = size; return res; } @@ -2135,13 +2213,210 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, return 0; } + +/* reconstruct full wavpack blocks from mangled matroska ones */ +static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, + uint8_t **pdst, int *size) +{ + uint8_t *dst = NULL; + int dstlen = 0; + int srclen = *size; + uint32_t samples; + uint16_t ver; + int ret, offset = 0; + + if (srclen < 12 || track->stream->codec->extradata_size < 2) + return AVERROR_INVALIDDATA; + + ver = AV_RL16(track->stream->codec->extradata); + + samples = AV_RL32(src); + src += 4; + srclen -= 4; + + while (srclen >= 8) { + int multiblock; + uint32_t blocksize; + uint8_t *tmp; + + uint32_t flags = AV_RL32(src); + uint32_t crc = AV_RL32(src + 4); + src += 8; + srclen -= 8; + + multiblock = (flags & 0x1800) != 0x1800; + if (multiblock) { + if (srclen < 4) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + blocksize = AV_RL32(src); + src += 4; + srclen -= 4; + } else + blocksize = srclen; + + if (blocksize > srclen) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + tmp = av_realloc(dst, dstlen + blocksize + 32); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst = tmp; + dstlen += blocksize + 32; + + AV_WL32(dst + offset, MKTAG('w', 'v', 'p', 'k')); // tag + AV_WL32(dst + offset + 4, blocksize + 24); // blocksize - 8 + AV_WL16(dst + offset + 8, ver); // version + AV_WL16(dst + offset + 10, 0); // track/index_no + AV_WL32(dst + offset + 12, 0); // total samples + AV_WL32(dst + offset + 16, 0); // block index + AV_WL32(dst + offset + 20, samples); // number of samples + AV_WL32(dst + offset + 24, flags); // flags + AV_WL32(dst + offset + 28, crc); // crc + memcpy (dst + offset + 32, src, blocksize); // block data + + src += blocksize; + srclen -= blocksize; + offset += blocksize + 32; + } + + *pdst = dst; + *size = dstlen; + + return 0; + +fail: + av_freep(&dst); + return ret; +} + +static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, + MatroskaTrack *track, + AVStream *st, + uint8_t *data, int data_len, + uint64_t timecode, + uint64_t duration, + int64_t pos) +{ + AVPacket *pkt; + uint8_t *id, *settings, *text, *buf; + int id_len, settings_len, text_len; + uint8_t *p, *q; + int err; + + if (data_len <= 0) + return AVERROR_INVALIDDATA; + + p = data; + q = data + data_len; + + id = p; + id_len = -1; + while (p < q) { + if (*p == '\r' || *p == '\n') { + id_len = p - id; + if (*p == '\r') + p++; + break; + } + p++; + } + + if (p >= q || *p != '\n') + return AVERROR_INVALIDDATA; + p++; + + settings = p; + settings_len = -1; + while (p < q) { + if (*p == '\r' || *p == '\n') { + settings_len = p - settings; + if (*p == '\r') + p++; + break; + } + p++; + } + + if (p >= q || *p != '\n') + return AVERROR_INVALIDDATA; + p++; + + text = p; + text_len = q - p; + while (text_len > 0) { + const int len = text_len - 1; + const uint8_t c = p[len]; + if (c != '\r' && c != '\n') + break; + text_len = len; + } + + if (text_len <= 0) + return AVERROR_INVALIDDATA; + + pkt = av_mallocz(sizeof(*pkt)); + err = av_new_packet(pkt, text_len); + if (err < 0) { + av_free(pkt); + return AVERROR(err); + } + + memcpy(pkt->data, text, text_len); + + if (id_len > 0) { + buf = av_packet_new_side_data(pkt, + AV_PKT_DATA_WEBVTT_IDENTIFIER, + id_len); + if (buf == NULL) { + av_free(pkt); + return AVERROR(ENOMEM); + } + memcpy(buf, id, id_len); + } + + if (settings_len > 0) { + buf = av_packet_new_side_data(pkt, + AV_PKT_DATA_WEBVTT_SETTINGS, + settings_len); + if (buf == NULL) { + av_free(pkt); + return AVERROR(ENOMEM); + } + memcpy(buf, settings, settings_len); + } + + // Do we need this for subtitles? + // pkt->flags = AV_PKT_FLAG_KEY; + + pkt->stream_index = st->index; + pkt->pts = timecode; + + // Do we need this for subtitles? + // pkt->dts = timecode; + + pkt->duration = duration; + pkt->pos = pos; + + dynarray_add(&matroska->packets, &matroska->num_packets, pkt); + matroska->prev_pkt = pkt; + + return 0; +} + static int matroska_parse_frame(MatroskaDemuxContext *matroska, MatroskaTrack *track, AVStream *st, uint8_t *data, int pkt_size, uint64_t timecode, uint64_t lace_duration, int64_t pos, int is_keyframe, - uint8_t *additional, uint64_t additional_id, int additional_size) + uint8_t *additional, uint64_t additional_id, int additional_size, + int64_t discard_padding) { MatroskaTrackEncoding *encodings = track->encodings.elem; uint8_t *pkt_data = data; @@ -2154,6 +2429,18 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, return res; } + if (st->codec->codec_id == AV_CODEC_ID_WAVPACK) { + uint8_t *wv_data; + res = matroska_parse_wavpack(track, pkt_data, &wv_data, &pkt_size); + if (res < 0) { + av_log(matroska->ctx, AV_LOG_ERROR, "Error parsing a wavpack block.\n"); + goto fail; + } + if (pkt_data != data) + av_freep(&pkt_data); + pkt_data = wv_data; + } + if (st->codec->codec_id == AV_CODEC_ID_PRORES) offset = 8; @@ -2161,7 +2448,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, /* XXX: prevent data copy... */ if (av_new_packet(pkt, pkt_size + offset) < 0) { av_free(pkt); - return AVERROR(ENOMEM); + res = AVERROR(ENOMEM); + goto fail; } if (st->codec->codec_id == AV_CODEC_ID_PRORES) { @@ -2173,7 +2461,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, memcpy(pkt->data + offset, pkt_data, pkt_size); if (pkt_data != data) - av_free(pkt_data); + av_freep(&pkt_data); pkt->flags = is_keyframe; pkt->stream_index = st->index; @@ -2191,6 +2479,21 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, memcpy(side_data + 8, additional, additional_size); } + if (discard_padding) { + uint8_t *side_data = av_packet_new_side_data(pkt, + AV_PKT_DATA_SKIP_SAMPLES, + 10); + if(side_data == NULL) { + av_free_packet(pkt); + av_free(pkt); + return AVERROR(ENOMEM); + } + AV_WL32(side_data, 0); + AV_WL32(side_data + 4, av_rescale_q(discard_padding, + (AVRational){1, 1000000000}, + (AVRational){1, st->codec->sample_rate})); + } + if (track->ms_compat) pkt->dts = timecode; else @@ -2220,6 +2523,7 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, pkt->duration = lace_duration; } +#if FF_API_ASS_SSA if (st->codec->codec_id == AV_CODEC_ID_SSA) matroska_fix_ass_packet(matroska, pkt, lace_duration); @@ -2233,15 +2537,23 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, dynarray_add(&matroska->packets,&matroska->num_packets,pkt); matroska->prev_pkt = pkt; } +#else + dynarray_add(&matroska->packets, &matroska->num_packets, pkt); + matroska->prev_pkt = pkt; +#endif return 0; +fail: + if (pkt_data != data) + av_freep(&pkt_data); + return res; } static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size, int64_t pos, uint64_t cluster_time, uint64_t block_duration, int is_keyframe, uint8_t *additional, uint64_t additional_id, int additional_size, - int64_t cluster_pos) + int64_t cluster_pos, int64_t discard_padding) { uint64_t timecode = AV_NOPTS_VALUE; MatroskaTrack *track; @@ -2251,6 +2563,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, uint32_t *lace_size = NULL; int n, flags, laces = 0; uint64_t num; + int trust_default_duration = 1; if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); @@ -2271,7 +2584,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, return res; av_assert1(block_duration != AV_NOPTS_VALUE); - block_time = AV_RB16(data); + block_time = sign_extend(AV_RB16(data), 16); data += 2; flags = *data++; size -= 3; @@ -2291,21 +2604,29 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (matroska->skip_to_keyframe && track->type != MATROSKA_TRACK_TYPE_SUBTITLE) { if (timecode < matroska->skip_to_timecode) return res; - if (!st->skip_to_keyframe) { + if (is_keyframe) + matroska->skip_to_keyframe = 0; + else if (!st->skip_to_keyframe) { av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n"); matroska->skip_to_keyframe = 0; } - if (is_keyframe) - matroska->skip_to_keyframe = 0; } - res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1, + res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1, &lace_size, &laces); if (res) goto end; - if (!block_duration) + if (track->audio.samplerate == 8000) { + // If this is needed for more codecs, then add them here + if (st->codec->codec_id == AV_CODEC_ID_AC3) { + if(track->audio.samplerate != st->codec->sample_rate || !st->codec->frame_size) + trust_default_duration = 0; + } + } + + if (!block_duration && trust_default_duration) block_duration = track->default_duration * laces / matroska->time_scale; if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time)) @@ -2326,16 +2647,26 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, st->codec->codec_id == AV_CODEC_ID_ATRAC3) && st->codec->block_align && track->audio.sub_packet_size) { - res = matroska_parse_rm_audio(matroska, track, st, data, size, + res = matroska_parse_rm_audio(matroska, track, st, data, + lace_size[n], timecode, pos); if (res) goto end; + } else if (st->codec->codec_id == AV_CODEC_ID_WEBVTT) { + res = matroska_parse_webvtt(matroska, track, st, + data, lace_size[n], + timecode, lace_duration, + pos); + if (res) + goto end; + } else { res = matroska_parse_frame(matroska, track, st, data, lace_size[n], timecode, lace_duration, pos, !n? is_keyframe : 0, - additional, additional_id, additional_size); + additional, additional_id, additional_size, + discard_padding); if (res) goto end; } @@ -2402,11 +2733,11 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) blocks[i].duration, is_keyframe, additional, blocks[i].additional_id, blocks[i].additional.size, - matroska->current_cluster_pos); + matroska->current_cluster_pos, + blocks[i].discard_padding); } } - if (res < 0) matroska->done = 1; return res; } @@ -2433,7 +2764,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, blocks[i].duration, is_keyframe, NULL, 0, 0, - pos); + pos, blocks[i].discard_padding); } ebml_free(matroska_cluster, &cluster); return res; @@ -2495,10 +2826,11 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE && tracks[i].stream->discard != AVDISCARD_ALL) { index_sub = av_index_search_timestamp(tracks[i].stream, st->index_entries[index].timestamp, AVSEEK_FLAG_BACKWARD); - if (index_sub >= 0 - && st->index_entries[index_sub].pos < st->index_entries[index_min].pos - && st->index_entries[index].timestamp - st->index_entries[index_sub].timestamp < 30000000000/matroska->time_scale) - index_min = index_sub; + while(index_sub >= 0 + && index_min >= 0 + && tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos + && st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000/matroska->time_scale) + index_min--; } } diff --git a/ffmpeg/libavformat/matroskaenc.c b/ffmpeg/libavformat/matroskaenc.c index a151eef..98804d1 100644 --- a/ffmpeg/libavformat/matroskaenc.c +++ b/ffmpeg/libavformat/matroskaenc.c @@ -19,25 +19,34 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + +#include "avc.h" #include "avformat.h" +#include "avio_internal.h" +#include "avlanguage.h" +#include "flacenc.h" #include "internal.h" -#include "riff.h" #include "isom.h" #include "matroska.h" -#include "avc.h" -#include "flacenc.h" -#include "avlanguage.h" -#include "libavutil/samplefmt.h" -#include "libavutil/sha.h" -#include "libavutil/intreadwrite.h" +#include "riff.h" +#include "subtitles.h" +#include "wv.h" + +#include "libavutil/avstring.h" +#include "libavutil/dict.h" #include "libavutil/intfloat.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/lfg.h" #include "libavutil/mathematics.h" +#include "libavutil/opt.h" #include "libavutil/random_seed.h" -#include "libavutil/lfg.h" -#include "libavutil/dict.h" -#include "libavutil/avstring.h" +#include "libavutil/samplefmt.h" +#include "libavutil/sha.h" + #include "libavcodec/xiph.h" #include "libavcodec/mpeg4audio.h" +#include "libavcodec/internal.h" typedef struct ebml_master { int64_t pos; ///< absolute offset in the file where the master's elements start @@ -62,6 +71,8 @@ typedef struct { uint64_t pts; int tracknum; int64_t cluster_pos; ///< file offset of the cluster containing the block + int64_t relative_pos; ///< relative offset from the position of the cluster containing the block + int64_t duration; ///< duration of the block according to time base } mkv_cuepoint; typedef struct { @@ -79,6 +90,7 @@ typedef struct { #define MODE_WEBM 0x02 typedef struct MatroskaMuxContext { + const AVClass *class; int mode; AVIOContext *dyn_bc; ebml_master segment; @@ -95,6 +107,14 @@ typedef struct MatroskaMuxContext { AVPacket cur_audio_pkt; int have_attachments; + + int reserve_cues_space; + int cluster_size_limit; + int64_t cues_pos; + int64_t cluster_time_limit; + + uint32_t chapter_id_offset; + int wrote_chapters; } MatroskaMuxContext; @@ -102,13 +122,16 @@ typedef struct MatroskaMuxContext { * offset, 4 bytes for target EBML ID */ #define MAX_SEEKENTRY_SIZE 21 -/** per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2 +/** per-cuepoint-track - 5 1-byte EBML IDs, 5 1-byte EBML sizes, 4 * 8-byte uint max */ -#define MAX_CUETRACKPOS_SIZE 22 +#define MAX_CUETRACKPOS_SIZE 42 /** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */ #define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks +/** Seek preroll value for opus */ +#define OPUS_SEEK_PREROLL 80000000 + static int ebml_id_size(unsigned int id) { @@ -131,8 +154,7 @@ static void put_ebml_size_unknown(AVIOContext *pb, int bytes) { av_assert0(bytes <= 8); avio_w8(pb, 0x1ff >> bytes); - while (--bytes) - avio_w8(pb, 0xff); + ffio_fill(pb, 0xff, bytes - 1); } /** @@ -182,6 +204,19 @@ static void put_ebml_uint(AVIOContext *pb, unsigned int elementid, uint64_t val) avio_w8(pb, (uint8_t)(val >> i*8)); } +static void put_ebml_sint(AVIOContext *pb, unsigned int elementid, int64_t val) +{ + int i, bytes = 1; + uint64_t tmp = 2*(val < 0 ? val^-1 : val); + + while (tmp>>=8) bytes++; + + put_ebml_id(pb, elementid); + put_ebml_num(pb, bytes, 0); + for (i = bytes - 1; i >= 0; i--) + avio_w8(pb, (uint8_t)(val >> i*8)); +} + static void put_ebml_float(AVIOContext *pb, unsigned int elementid, double val) { put_ebml_id(pb, elementid); @@ -222,8 +257,7 @@ static void put_ebml_void(AVIOContext *pb, uint64_t size) put_ebml_num(pb, size-1, 0); else put_ebml_num(pb, size-9, 8); - while(avio_tell(pb) < currentpos + size) - avio_w8(pb, 0); + ffio_fill(pb, 0, currentpos + size - avio_tell(pb)); } static ebml_master start_ebml_master(AVIOContext *pb, unsigned int elementid, uint64_t expectedsize) @@ -246,9 +280,7 @@ static void end_ebml_master(AVIOContext *pb, ebml_master master) static void put_xiph_size(AVIOContext *pb, int size) { - int i; - for (i = 0; i < size / 255; i++) - avio_w8(pb, 255); + ffio_fill(pb, 255, size / 255); avio_w8(pb, size % 255); } @@ -291,14 +323,14 @@ static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries) return -1; - entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry)); + entries = av_realloc_array(entries, seekhead->num_entries + 1, sizeof(mkv_seekhead_entry)); if (entries == NULL) return AVERROR(ENOMEM); + seekhead->entries = entries; - entries[seekhead->num_entries ].elementid = elementid; - entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset; + seekhead->entries[seekhead->num_entries].elementid = elementid; + seekhead->entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset; - seekhead->entries = entries; return 0; } @@ -349,7 +381,7 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, mkv_seekhead *seekhead) currentpos = seekhead->filepos; } fail: - av_free(seekhead->entries); + av_freep(&seekhead->entries); av_free(seekhead); return currentpos; @@ -365,22 +397,25 @@ static mkv_cues * mkv_start_cues(int64_t segment_offset) return cues; } -static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos) +static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos, int64_t relative_pos, + int64_t duration) { mkv_cuepoint *entries = cues->entries; if (ts < 0) return 0; - entries = av_realloc(entries, (cues->num_entries + 1) * sizeof(mkv_cuepoint)); + entries = av_realloc_array(entries, cues->num_entries + 1, sizeof(mkv_cuepoint)); if (entries == NULL) return AVERROR(ENOMEM); + cues->entries = entries; - entries[cues->num_entries ].pts = ts; - entries[cues->num_entries ].tracknum = stream + 1; - entries[cues->num_entries++].cluster_pos = cluster_pos - cues->segment_offset; + cues->entries[cues->num_entries].pts = ts; + cues->entries[cues->num_entries].tracknum = stream + 1; + cues->entries[cues->num_entries].cluster_pos = cluster_pos - cues->segment_offset; + cues->entries[cues->num_entries].relative_pos = relative_pos; + cues->entries[cues->num_entries++].duration = duration; - cues->entries = entries; return 0; } @@ -412,8 +447,11 @@ static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, mkv_track *tracks continue; tracks[tracknum].has_cue = 1; track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE); - put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum ); - put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION, entry[j].cluster_pos); + put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum ); + put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION , entry[j].cluster_pos); + put_ebml_uint(pb, MATROSKA_ID_CUERELATIVEPOSITION, entry[j].relative_pos); + if (entry[j].duration != -1) + put_ebml_uint(pb, MATROSKA_ID_CUEDURATION , entry[j].duration); end_ebml_master(pb, track_positions); } i += j - 1; @@ -452,6 +490,15 @@ static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, AVCodecContex return 0; } +static int put_wv_codecpriv(AVIOContext *pb, AVCodecContext *codec) +{ + if (codec->extradata && codec->extradata_size == 2) + avio_write(pb, codec->extradata, 2); + else + avio_wl16(pb, 0x403); // fallback to the version mentioned in matroska specs + return 0; +} + static void get_aac_sample_rates(AVFormatContext *s, AVCodecContext *codec, int *sample_rate, int *output_sample_rate) { MPEG4AudioConfig mp4ac; @@ -481,6 +528,8 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo ret = put_xiph_codecpriv(s, dyn_cp, codec); else if (codec->codec_id == AV_CODEC_ID_FLAC) ret = ff_flac_write_header(dyn_cp, codec, 1); + else if (codec->codec_id == AV_CODEC_ID_WAVPACK) + ret = put_wv_codecpriv(dyn_cp, codec); else if (codec->codec_id == AV_CODEC_ID_H264) ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); else if (codec->codec_id == AV_CODEC_ID_ALAC) { @@ -510,7 +559,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo ret = AVERROR(EINVAL); } - ff_put_bmp_header(dyn_cp, codec, ff_codec_bmp_tags, 0); + ff_put_bmp_header(dyn_cp, codec, ff_codec_bmp_tags, 0, 0); } } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) { @@ -558,6 +607,8 @@ static int mkv_write_tracks(AVFormatContext *s) int bit_depth = av_get_bits_per_sample(codec->codec_id); int sample_rate = codec->sample_rate; int output_sample_rate = 0; + int display_width_div = 1; + int display_height_div = 1; AVDictionaryEntry *tag; if (codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) { @@ -581,28 +632,64 @@ static int mkv_write_tracks(AVFormatContext *s) if ((tag = av_dict_get(st->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TRACKNAME, tag->value); tag = av_dict_get(st->metadata, "language", NULL, 0); - put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und"); + if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) { + put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und"); + } else if (tag && tag->value) { + put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag->value); + } - if (default_stream_exists) { + // The default value for TRACKFLAGDEFAULT is 1, so add element + // if we need to clear it. + if (default_stream_exists && !(st->disposition & AV_DISPOSITION_DEFAULT)) put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, !!(st->disposition & AV_DISPOSITION_DEFAULT)); - } + if (st->disposition & AV_DISPOSITION_FORCED) put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1); - // look for a codec ID string specific to mkv to use, - // if none are found, use AVI codes - for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) { - if (ff_mkv_codec_tags[j].id == codec->codec_id) { - put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str); - native_id = 1; - break; + if (mkv->mode == MODE_WEBM && codec->codec_id == AV_CODEC_ID_WEBVTT) { + const char *codec_id; + if (st->disposition & AV_DISPOSITION_CAPTIONS) { + codec_id = "D_WEBVTT/CAPTIONS"; + native_id = MATROSKA_TRACK_TYPE_SUBTITLE; + } else if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) { + codec_id = "D_WEBVTT/DESCRIPTIONS"; + native_id = MATROSKA_TRACK_TYPE_METADATA; + } else if (st->disposition & AV_DISPOSITION_METADATA) { + codec_id = "D_WEBVTT/METADATA"; + native_id = MATROSKA_TRACK_TYPE_METADATA; + } else { + codec_id = "D_WEBVTT/SUBTITLES"; + native_id = MATROSKA_TRACK_TYPE_SUBTITLE; + } + put_ebml_string(pb, MATROSKA_ID_CODECID, codec_id); + } else { + // look for a codec ID string specific to mkv to use, + // if none are found, use AVI codes + for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) { + if (ff_mkv_codec_tags[j].id == codec->codec_id) { + put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str); + native_id = 1; + break; + } } } + if (codec->codec_id == AV_CODEC_ID_OPUS) { + uint64_t codec_delay =av_rescale_q(codec->delay, + (AVRational){1, codec->sample_rate}, + (AVRational){1, 1000000000}); + put_ebml_uint(pb, MATROSKA_ID_CODECDELAY, codec_delay); + put_ebml_uint(pb, MATROSKA_ID_SEEKPREROLL, OPUS_SEEK_PREROLL); + + } + if (mkv->mode == MODE_WEBM && !(codec->codec_id == AV_CODEC_ID_VP8 || - codec->codec_id == AV_CODEC_ID_VORBIS)) { + codec->codec_id == AV_CODEC_ID_VP9 || + ((codec->codec_id == AV_CODEC_ID_OPUS)&&(codec->strict_std_compliance <= FF_COMPLIANCE_EXPERIMENTAL)) || + codec->codec_id == AV_CODEC_ID_VORBIS || + codec->codec_id == AV_CODEC_ID_WEBVTT)) { av_log(s, AV_LOG_ERROR, - "Only VP8 video and Vorbis audio are supported for WebM.\n"); + "Only VP8,VP9 video and Vorbis,Opus(experimental, use -strict -2) audio and WebVTT subtitles are supported for WebM.\n"); return AVERROR(EINVAL); } @@ -653,6 +740,27 @@ static int mkv_write_tracks(AVFormatContext *s) return AVERROR(EINVAL); } else put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, st_mode); + + switch (st_mode) { + case 1: + case 8: + case 9: + case 11: + display_width_div = 2; + break; + case 2: + case 3: + case 6: + case 7: + display_height_div = 2; + break; + } + } + + if ((tag = av_dict_get(st->metadata, "alpha_mode", NULL, 0)) || + (tag = av_dict_get( s->metadata, "alpha_mode", NULL, 0)) || + (codec->pix_fmt == AV_PIX_FMT_YUVA420P)) { + put_ebml_uint(pb, MATROSKA_ID_VIDEOALPHAMODE, 1); } if (st->sample_aspect_ratio.num) { @@ -661,8 +769,11 @@ static int mkv_write_tracks(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Overflow in display width\n"); return AVERROR(EINVAL); } - put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width); - put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height); + put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width / display_width_div); + put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height / display_height_div); + } else if (display_width_div != 1 || display_height_div != 1) { + put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , codec->width / display_width_div); + put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height / display_height_div); } if (codec->codec_id == AV_CODEC_ID_RAWVIDEO) { @@ -690,18 +801,25 @@ static int mkv_write_tracks(AVFormatContext *s) break; case AVMEDIA_TYPE_SUBTITLE: - put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_SUBTITLE); if (!native_id) { av_log(s, AV_LOG_ERROR, "Subtitle codec %d is not supported.\n", codec->codec_id); return AVERROR(ENOSYS); } + + if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) + native_id = MATROSKA_TRACK_TYPE_SUBTITLE; + + put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, native_id); break; default: av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska.\n"); - break; + return AVERROR(EINVAL); + } + + if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) { + ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id); + if (ret < 0) return ret; } - ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id); - if (ret < 0) return ret; end_ebml_master(pb, track); @@ -720,7 +838,7 @@ static int mkv_write_chapters(AVFormatContext *s) AVRational scale = {1, 1E9}; int i, ret; - if (!s->nb_chapters) + if (!s->nb_chapters || mkv->wrote_chapters) return 0; ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb)); @@ -736,7 +854,7 @@ static int mkv_write_chapters(AVFormatContext *s) AVDictionaryEntry *t = NULL; chapteratom = start_ebml_master(pb, MATROSKA_ID_CHAPTERATOM, 0); - put_ebml_uint(pb, MATROSKA_ID_CHAPTERUID, c->id); + put_ebml_uint(pb, MATROSKA_ID_CHAPTERUID, c->id + mkv->chapter_id_offset); put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMESTART, av_rescale_q(c->start, c->time_base, scale)); put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMEEND, @@ -753,6 +871,8 @@ static int mkv_write_chapters(AVFormatContext *s) } end_ebml_master(pb, editionentry); end_ebml_master(pb, chapters); + + mkv->wrote_chapters = 1; return 0; } @@ -815,14 +935,26 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme return 0; } +static int mkv_check_tag(AVDictionary *m) +{ + AVDictionaryEntry *t = NULL; + + while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) + if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode")) + return 1; + + return 0; +} + static int mkv_write_tags(AVFormatContext *s) { + MatroskaMuxContext *mkv = s->priv_data; ebml_master tags = {0}; int i, ret; ff_metadata_conv_ctx(s, ff_mkv_metadata_conv, NULL); - if (av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + if (mkv_check_tag(s->metadata)) { ret = mkv_write_tag(s, s->metadata, 0, 0, &tags); if (ret < 0) return ret; } @@ -830,7 +962,7 @@ static int mkv_write_tags(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - if (!av_dict_get(st->metadata, "", 0, AV_DICT_IGNORE_SUFFIX)) + if (!mkv_check_tag(st->metadata)) continue; ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags); @@ -840,10 +972,10 @@ static int mkv_write_tags(AVFormatContext *s) for (i = 0; i < s->nb_chapters; i++) { AVChapter *ch = s->chapters[i]; - if (!av_dict_get(ch->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) + if (!mkv_check_tag(ch->metadata)) continue; - ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id, &tags); + ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset, &tags); if (ret < 0) return ret; } @@ -968,7 +1100,7 @@ static int mkv_write_header(AVFormatContext *s) put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4); put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8); put_ebml_string (pb, EBML_ID_DOCTYPE , s->oformat->name); - put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2); + put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 4); put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2); end_ebml_master(pb, ebml_header); @@ -1003,6 +1135,10 @@ static int mkv_write_header(AVFormatContext *s) put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , LIBAVFORMAT_IDENT); put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT); put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16); + } else { + const char *ident = "Lavf"; + put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , ident); + put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, ident); } if (tag = av_dict_get(s->metadata, "creation_time", NULL, 0)) { @@ -1022,6 +1158,9 @@ static int mkv_write_header(AVFormatContext *s) ret = mkv_write_tracks(s); if (ret < 0) return ret; + for (i = 0; i < s->nb_chapters; i++) + mkv->chapter_id_offset = FFMAX(mkv->chapter_id_offset, 1LL - s->chapters[i]->id); + if (mkv->mode != MODE_WEBM) { ret = mkv_write_chapters(s); if (ret < 0) return ret; @@ -1040,11 +1179,31 @@ static int mkv_write_header(AVFormatContext *s) if (mkv->cues == NULL) return AVERROR(ENOMEM); + if (pb->seekable && mkv->reserve_cues_space) { + mkv->cues_pos = avio_tell(pb); + put_ebml_void(pb, mkv->reserve_cues_space); + } + av_init_packet(&mkv->cur_audio_pkt); mkv->cur_audio_pkt.size = 0; mkv->cluster_pos = -1; avio_flush(pb); + + // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or + // after 4k and on a keyframe + if (pb->seekable) { + if (mkv->cluster_time_limit < 0) + mkv->cluster_time_limit = 5000; + if (mkv->cluster_size_limit < 0) + mkv->cluster_size_limit = 5 * 1024 * 1024; + } else { + if (mkv->cluster_time_limit < 0) + mkv->cluster_time_limit = 1000; + if (mkv->cluster_size_limit < 0) + mkv->cluster_size_limit = 32 * 1024; + } + return 0; } @@ -1072,6 +1231,7 @@ static int ass_get_duration(const uint8_t *p) return end - start; } +#if FF_API_ASS_SSA static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) { MatroskaMuxContext *mkv = s->priv_data; @@ -1116,15 +1276,72 @@ static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p return max_duration; } +#endif + +static int mkv_strip_wavpack(const uint8_t *src, uint8_t **pdst, int *size) +{ + uint8_t *dst; + int srclen = *size; + int offset = 0; + int ret; + + dst = av_malloc(srclen); + if (!dst) + return AVERROR(ENOMEM); + + while (srclen >= WV_HEADER_SIZE) { + WvHeader header; + + ret = ff_wv_parse_header(&header, src); + if (ret < 0) + goto fail; + src += WV_HEADER_SIZE; + srclen -= WV_HEADER_SIZE; + + if (srclen < header.blocksize) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (header.initial) { + AV_WL32(dst + offset, header.samples); + offset += 4; + } + AV_WL32(dst + offset, header.flags); + AV_WL32(dst + offset + 4, header.crc); + offset += 8; + + if (!(header.initial && header.final)) { + AV_WL32(dst + offset, header.blocksize); + offset += 4; + } + + memcpy(dst + offset, src, header.blocksize); + src += header.blocksize; + srclen -= header.blocksize; + offset += header.blocksize; + } + + *pdst = dst; + *size = offset; + + return 0; +fail: + av_freep(&dst); + return ret; +} static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, unsigned int blockid, AVPacket *pkt, int flags) { MatroskaMuxContext *mkv = s->priv_data; AVCodecContext *codec = s->streams[pkt->stream_index]->codec; - uint8_t *data = NULL; - int offset = 0, size = pkt->size; + uint8_t *data = NULL, *side_data = NULL; + int offset = 0, size = pkt->size, side_data_size = 0; int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; + uint64_t additional_id = 0; + int64_t discard_padding = 0; + ebml_master block_group, block_additions, block_more; av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n", @@ -1132,7 +1349,13 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, if (codec->codec_id == AV_CODEC_ID_H264 && codec->extradata_size > 0 && (AV_RB24(codec->extradata) == 1 || AV_RB32(codec->extradata) == 1)) ff_avc_parse_nal_units_buf(pkt->data, &data, &size); - else + else if (codec->codec_id == AV_CODEC_ID_WAVPACK) { + int ret = mkv_strip_wavpack(pkt->data, &data, &size); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Error stripping a WavPack packet.\n"); + return; + } + } else data = pkt->data; if (codec->codec_id == AV_CODEC_ID_PRORES) { @@ -1142,6 +1365,30 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, offset = 8; } + side_data = av_packet_get_side_data(pkt, + AV_PKT_DATA_SKIP_SAMPLES, + &side_data_size); + + if (side_data && side_data_size >= 10) { + discard_padding = av_rescale_q(AV_RL32(side_data + 4), + (AVRational){1, codec->sample_rate}, + (AVRational){1, 1000000000}); + } + + side_data = av_packet_get_side_data(pkt, + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + &side_data_size); + if (side_data) { + additional_id = AV_RB64(side_data); + side_data += 8; + side_data_size -= 8; + } + + if ((side_data_size && additional_id == 1) || discard_padding) { + block_group = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, 0); + blockid = MATROSKA_ID_BLOCK; + } + put_ebml_id(pb, blockid); put_ebml_num(pb, size+4, 0); avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126 @@ -1150,6 +1397,24 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, avio_write(pb, data + offset, size); if (data != pkt->data) av_free(data); + + if (discard_padding) { + put_ebml_sint(pb, MATROSKA_ID_DISCARDPADDING, discard_padding); + } + + if (side_data_size && additional_id == 1) { + block_additions = start_ebml_master(pb, MATROSKA_ID_BLOCKADDITIONS, 0); + block_more = start_ebml_master(pb, MATROSKA_ID_BLOCKMORE, 0); + put_ebml_uint(pb, MATROSKA_ID_BLOCKADDID, 1); + put_ebml_id(pb, MATROSKA_ID_BLOCKADDITIONAL); + put_ebml_num(pb, side_data_size, 0); + avio_write(pb, side_data, side_data_size); + end_ebml_master(pb, block_more); + end_ebml_master(pb, block_additions); + } + if ((side_data_size && additional_id == 1) || discard_padding) { + end_ebml_master(pb, block_group); + } } static int srt_get_duration(uint8_t **buf) @@ -1166,7 +1431,7 @@ static int srt_get_duration(uint8_t **buf) s_hsec += 1000*s_sec; e_hsec += 1000*e_sec; duration = e_hsec - s_hsec; } - *buf += strcspn(*buf, "\n") + 1; + *buf += ff_subtitles_next_line(*buf); } return duration; } @@ -1187,6 +1452,44 @@ static int mkv_write_srt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p return duration; } +static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) +{ + MatroskaMuxContext *mkv = s->priv_data; + ebml_master blockgroup; + int id_size, settings_size, size; + uint8_t *id, *settings; + int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; + const int flags = 0; + + id_size = 0; + id = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_IDENTIFIER, + &id_size); + + settings_size = 0; + settings = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_SETTINGS, + &settings_size); + + size = id_size + 1 + settings_size + 1 + pkt->size; + + av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " + "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n", + avio_tell(pb), size, pkt->pts, pkt->dts, pkt->duration, flags); + + blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(size)); + + put_ebml_id(pb, MATROSKA_ID_BLOCK); + put_ebml_num(pb, size+4, 0); + avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126 + avio_wb16(pb, ts - mkv->cluster_pts); + avio_w8(pb, flags); + avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data); + + put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, pkt->duration); + end_ebml_master(pb, blockgroup); + + return pkt->duration; +} + static void mkv_flush_dynbuf(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; @@ -1211,6 +1514,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt) int duration = pkt->duration; int ret; int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; + int64_t relative_packet_pos; if (ts == AV_NOPTS_VALUE) { av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n"); @@ -1234,12 +1538,18 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt) mkv->cluster_pts = FFMAX(0, ts); } + relative_packet_pos = avio_tell(s->pb) - mkv->cluster.pos; + if (codec->codec_type != AVMEDIA_TYPE_SUBTITLE) { mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7); +#if FF_API_ASS_SSA } else if (codec->codec_id == AV_CODEC_ID_SSA) { duration = mkv_write_ass_blocks(s, pb, pkt); +#endif } else if (codec->codec_id == AV_CODEC_ID_SRT) { duration = mkv_write_srt_blocks(s, pb, pkt); + } else if (codec->codec_id == AV_CODEC_ID_WEBVTT) { + duration = mkv_write_vtt_blocks(s, pb, pkt); } else { ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(pkt->size)); /* For backward compatibility, prefer convergence_duration. */ @@ -1251,8 +1561,9 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt) end_ebml_master(pb, blockgroup); } - if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) { - ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos); + if ((codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) || codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts, mkv->cluster_pos, relative_packet_pos, + codec->codec_type == AVMEDIA_TYPE_SUBTITLE ? duration : -1); if (ret < 0) return ret; } @@ -1263,24 +1574,41 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt) static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) { MatroskaMuxContext *mkv = s->priv_data; - AVIOContext *pb = s->pb->seekable ? s->pb : mkv->dyn_bc; - AVCodecContext *codec = s->streams[pkt->stream_index]->codec; - int ret, keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY); - int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; - int cluster_size = avio_tell(pb) - (s->pb->seekable ? mkv->cluster_pos : 0); + int codec_type = s->streams[pkt->stream_index]->codec->codec_type; + int keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY); + int cluster_size; + int64_t cluster_time; + AVIOContext *pb; + int ret; + + if (mkv->tracks[pkt->stream_index].write_dts) + cluster_time = pkt->dts - mkv->cluster_pts; + else + cluster_time = pkt->pts - mkv->cluster_pts; // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or // after 4k and on a keyframe + if (s->pb->seekable) { + pb = s->pb; + cluster_size = avio_tell(pb) - mkv->cluster_pos; + } else { + pb = mkv->dyn_bc; + cluster_size = avio_tell(pb); + } + if (mkv->cluster_pos != -1 && - ((!s->pb->seekable && (cluster_size > 32*1024 || ts > mkv->cluster_pts + 1000)) - || cluster_size > 5*1024*1024 || ts > mkv->cluster_pts + 5000 - || (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe && cluster_size > 4*1024))) { + (cluster_size > mkv->cluster_size_limit || + cluster_time > mkv->cluster_time_limit || + (codec_type == AVMEDIA_TYPE_VIDEO && keyframe && + cluster_size > 4 * 1024))) { av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64 - " bytes, pts %" PRIu64 "\n", avio_tell(pb), ts); + " bytes, pts %" PRIu64 "dts %" PRIu64 "\n", + avio_tell(pb), pkt->pts, pkt->dts); end_ebml_master(pb, mkv->cluster); mkv->cluster_pos = -1; if (mkv->dyn_bc) mkv_flush_dynbuf(s); + avio_flush(s->pb); } // check if we have an audio packet cached @@ -1295,15 +1623,44 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) // buffer an audio packet to ensure the packet containing the video // keyframe's timecode is contained in the same cluster for WebM - if (codec->codec_type == AVMEDIA_TYPE_AUDIO) { + if (codec_type == AVMEDIA_TYPE_AUDIO) { mkv->cur_audio_pkt = *pkt; - mkv->cur_audio_pkt.buf = av_buffer_ref(pkt->buf); - ret = mkv->cur_audio_pkt.buf ? 0 : AVERROR(ENOMEM); + if (pkt->buf) { + mkv->cur_audio_pkt.buf = av_buffer_ref(pkt->buf); + ret = mkv->cur_audio_pkt.buf ? 0 : AVERROR(ENOMEM); + } else + ret = av_dup_packet(&mkv->cur_audio_pkt); + if (mkv->cur_audio_pkt.side_data_elems > 0) { + ret = av_copy_packet_side_data(&mkv->cur_audio_pkt, &mkv->cur_audio_pkt); + } } else ret = mkv_write_packet_internal(s, pkt); return ret; } +static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt) +{ + MatroskaMuxContext *mkv = s->priv_data; + AVIOContext *pb; + if (s->pb->seekable) + pb = s->pb; + else + pb = mkv->dyn_bc; + if (!pkt) { + if (mkv->cluster_pos != -1) { + av_log(s, AV_LOG_DEBUG, "Flushing cluster at offset %" PRIu64 + " bytes\n", avio_tell(pb)); + end_ebml_master(pb, mkv->cluster); + mkv->cluster_pos = -1; + if (mkv->dyn_bc) + mkv_flush_dynbuf(s); + avio_flush(s->pb); + } + return 0; + } + return mkv_write_packet(s, pkt); +} + static int mkv_write_trailer(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; @@ -1328,9 +1685,35 @@ static int mkv_write_trailer(AVFormatContext *s) end_ebml_master(pb, mkv->cluster); } + if (mkv->mode != MODE_WEBM) { + ret = mkv_write_chapters(s); + if (ret < 0) return ret; + } + if (pb->seekable) { if (mkv->cues->num_entries) { - cuespos = mkv_write_cues(pb, mkv->cues, mkv->tracks, s->nb_streams); + if (mkv->reserve_cues_space) { + int64_t cues_end; + + currentpos = avio_tell(pb); + avio_seek(pb, mkv->cues_pos, SEEK_SET); + + cuespos = mkv_write_cues(pb, mkv->cues, mkv->tracks, s->nb_streams); + cues_end = avio_tell(pb); + if (cues_end > cuespos + mkv->reserve_cues_space) { + av_log(s, AV_LOG_ERROR, "Insufficient space reserved for cues: %d " + "(needed: %"PRId64").\n", mkv->reserve_cues_space, + cues_end - cuespos); + return AVERROR(EINVAL); + } + + if (cues_end < cuespos + mkv->reserve_cues_space) + put_ebml_void(pb, mkv->reserve_cues_space - (cues_end - cuespos)); + + avio_seek(pb, currentpos, SEEK_SET); + } else { + cuespos = mkv_write_cues(pb, mkv->cues, mkv->tracks, s->nb_streams); + } ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES, cuespos); if (ret < 0) return ret; @@ -1348,7 +1731,7 @@ static int mkv_write_trailer(AVFormatContext *s) } end_ebml_master(pb, mkv->segment); - av_free(mkv->tracks); + av_freep(&mkv->tracks); av_freep(&mkv->cues->entries); av_freep(&mkv->cues); @@ -1371,7 +1754,7 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance) return 0; } -const AVCodecTag additional_audio_tags[] = { +static const AVCodecTag additional_audio_tags[] = { { AV_CODEC_ID_ALAC, 0XFFFFFFFF }, { AV_CODEC_ID_EAC3, 0XFFFFFFFF }, { AV_CODEC_ID_MLP, 0xFFFFFFFF }, @@ -1384,12 +1767,10 @@ const AVCodecTag additional_audio_tags[] = { { AV_CODEC_ID_RA_288, 0xFFFFFFFF }, { AV_CODEC_ID_COOK, 0xFFFFFFFF }, { AV_CODEC_ID_TRUEHD, 0xFFFFFFFF }, - { AV_CODEC_ID_WAVPACK, 0xFFFFFFFF }, { AV_CODEC_ID_NONE, 0xFFFFFFFF } }; -const AVCodecTag additional_video_tags[] = { - { AV_CODEC_ID_PRORES, 0xFFFFFFFF }, +static const AVCodecTag additional_video_tags[] = { { AV_CODEC_ID_RV10, 0xFFFFFFFF }, { AV_CODEC_ID_RV20, 0xFFFFFFFF }, { AV_CODEC_ID_RV30, 0xFFFFFFFF }, @@ -1398,7 +1779,23 @@ const AVCodecTag additional_video_tags[] = { { AV_CODEC_ID_NONE, 0xFFFFFFFF } }; +#define OFFSET(x) offsetof(MatroskaMuxContext, x) +#define FLAGS AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "reserve_index_space", "Reserve a given amount of space (in bytes) at the beginning of the file for the index (cues).", OFFSET(reserve_cues_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { "cluster_size_limit", "Store at most the provided amount of bytes in a cluster. ", OFFSET(cluster_size_limit), AV_OPT_TYPE_INT , { .i64 = -1 }, -1, INT_MAX, FLAGS }, + { "cluster_time_limit", "Store at most the provided number of milliseconds in a cluster.", OFFSET(cluster_time_limit), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, + { NULL }, +}; + #if CONFIG_MATROSKA_MUXER +static const AVClass matroska_class = { + .class_name = "matroska muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_matroska_muxer = { .name = "matroska", .long_name = NULL_IF_CONFIG_SMALL("Matroska"), @@ -1410,20 +1807,32 @@ AVOutputFormat ff_matroska_muxer = { .video_codec = CONFIG_LIBX264_ENCODER ? AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4, .write_header = mkv_write_header, - .write_packet = mkv_write_packet, + .write_packet = mkv_write_flush_packet, .write_trailer = mkv_write_trailer, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | - AVFMT_TS_NONSTRICT, + AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH, .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags, ff_codec_wav_tags, additional_audio_tags, additional_video_tags, 0 }, +#if FF_API_ASS_SSA .subtitle_codec = AV_CODEC_ID_SSA, +#else + .subtitle_codec = AV_CODEC_ID_ASS, +#endif .query_codec = mkv_query_codec, + .priv_class = &matroska_class, }; #endif #if CONFIG_WEBM_MUXER +static const AVClass webm_class = { + .class_name = "webm muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_webm_muxer = { .name = "webm", .long_name = NULL_IF_CONFIG_SMALL("WebM"), @@ -1432,18 +1841,26 @@ AVOutputFormat ff_webm_muxer = { .priv_data_size = sizeof(MatroskaMuxContext), .audio_codec = AV_CODEC_ID_VORBIS, .video_codec = AV_CODEC_ID_VP8, + .subtitle_codec = AV_CODEC_ID_WEBVTT, .write_header = mkv_write_header, - .write_packet = mkv_write_packet, + .write_packet = mkv_write_flush_packet, .write_trailer = mkv_write_trailer, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | - AVFMT_TS_NONSTRICT, + AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH, + .priv_class = &webm_class, }; #endif #if CONFIG_MATROSKA_AUDIO_MUXER +static const AVClass mka_class = { + .class_name = "matroska audio muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; AVOutputFormat ff_matroska_audio_muxer = { .name = "matroska", - .long_name = NULL_IF_CONFIG_SMALL("Matroska"), + .long_name = NULL_IF_CONFIG_SMALL("Matroska Audio"), .mime_type = "audio/x-matroska", .extensions = "mka", .priv_data_size = sizeof(MatroskaMuxContext), @@ -1451,11 +1868,13 @@ AVOutputFormat ff_matroska_audio_muxer = { AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3, .video_codec = AV_CODEC_ID_NONE, .write_header = mkv_write_header, - .write_packet = mkv_write_packet, + .write_packet = mkv_write_flush_packet, .write_trailer = mkv_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT, + .flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT | + AVFMT_ALLOW_FLUSH, .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, additional_audio_tags, 0 }, + .priv_class = &mka_class, }; #endif diff --git a/ffmpeg/libavformat/md5enc.c b/ffmpeg/libavformat/md5enc.c index 050efb1..8b14fba 100644 --- a/ffmpeg/libavformat/md5enc.c +++ b/ffmpeg/libavformat/md5enc.c @@ -19,21 +19,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/md5.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/hash.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" struct MD5Context { - struct AVMD5 *md5; + const AVClass *avclass; + struct AVHashContext *hash; + char *hash_name; }; static void md5_finish(struct AVFormatContext *s, char *buf) { struct MD5Context *c = s->priv_data; - uint8_t md5[16]; + uint8_t md5[AV_HASH_MAX_SIZE]; int i, offset = strlen(buf); - av_md5_final(c->md5, md5); - for (i = 0; i < sizeof(md5); i++) { + int len = av_hash_get_size(c->hash); + av_assert0(len > 0 && len <= sizeof(md5)); + av_hash_final(c->hash, md5); + for (i = 0; i < len; i++) { snprintf(buf + offset, 3, "%02"PRIx8, md5[i]); offset += 2; } @@ -44,32 +51,48 @@ static void md5_finish(struct AVFormatContext *s, char *buf) avio_flush(s->pb); } +#define OFFSET(x) offsetof(struct MD5Context, x) +#define ENC AV_OPT_FLAG_ENCODING_PARAM +static const AVOption hash_options[] = { + { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = "md5"}, 0, 0, ENC }, + { NULL }, +}; + +static const AVClass md5enc_class = { + .class_name = "hash encoder class", + .item_name = av_default_item_name, + .option = hash_options, + .version = LIBAVUTIL_VERSION_INT, +}; + #if CONFIG_MD5_MUXER static int write_header(struct AVFormatContext *s) { struct MD5Context *c = s->priv_data; - c->md5 = av_md5_alloc(); - if (!c->md5) - return AVERROR(ENOMEM); - av_md5_init(c->md5); + int res = av_hash_alloc(&c->hash, c->hash_name); + if (res < 0) + return res; + av_hash_init(c->hash); return 0; } static int write_packet(struct AVFormatContext *s, AVPacket *pkt) { struct MD5Context *c = s->priv_data; - av_md5_update(c->md5, pkt->data, pkt->size); + av_hash_update(c->hash, pkt->data, pkt->size); return 0; } static int write_trailer(struct AVFormatContext *s) { struct MD5Context *c = s->priv_data; - char buf[64] = "MD5="; + char buf[256]; + av_strlcpy(buf, av_hash_get_name(c->hash), sizeof(buf) - 200); + av_strlcat(buf, "=", sizeof(buf) - 200); md5_finish(s, buf); - av_freep(&c->md5); + av_hash_freep(&c->hash); return 0; } @@ -83,6 +106,7 @@ AVOutputFormat ff_md5_muxer = { .write_packet = write_packet, .write_trailer = write_trailer, .flags = AVFMT_NOTIMESTAMPS, + .priv_class = &md5enc_class, }; #endif @@ -90,18 +114,23 @@ AVOutputFormat ff_md5_muxer = { static int framemd5_write_header(struct AVFormatContext *s) { struct MD5Context *c = s->priv_data; - c->md5 = av_md5_alloc(); - if (!c->md5) - return AVERROR(ENOMEM); - return ff_framehash_write_header(s); + int res = av_hash_alloc(&c->hash, c->hash_name); + if (res < 0) + return res; + avio_printf(s->pb, "#format: frame checksums\n"); + avio_printf(s->pb, "#version: 1\n"); + avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hash)); + ff_framehash_write_header(s); + avio_printf(s->pb, "#stream#, dts, pts, duration, size, hash\n"); + return 0; } static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt) { struct MD5Context *c = s->priv_data; char buf[256]; - av_md5_init(c->md5); - av_md5_update(c->md5, pkt->data, pkt->size); + av_hash_init(c->hash); + av_hash_update(c->hash, pkt->data, pkt->size); snprintf(buf, sizeof(buf) - 64, "%d, %10"PRId64", %10"PRId64", %8d, %8d, ", pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size); @@ -112,10 +141,17 @@ static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt) static int framemd5_write_trailer(struct AVFormatContext *s) { struct MD5Context *c = s->priv_data; - av_freep(&c->md5); + av_hash_freep(&c->hash); return 0; } +static const AVClass framemd5_class = { + .class_name = "frame hash encoder class", + .item_name = av_default_item_name, + .option = hash_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_framemd5_muxer = { .name = "framemd5", .long_name = NULL_IF_CONFIG_SMALL("Per-frame MD5 testing"), @@ -125,6 +161,8 @@ AVOutputFormat ff_framemd5_muxer = { .write_header = framemd5_write_header, .write_packet = framemd5_write_packet, .write_trailer = framemd5_write_trailer, - .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, + .priv_class = &framemd5_class, }; #endif diff --git a/ffmpeg/libavformat/microdvddec.c b/ffmpeg/libavformat/microdvddec.c index 4b42846..7b49e43 100644 --- a/ffmpeg/libavformat/microdvddec.c +++ b/ffmpeg/libavformat/microdvddec.c @@ -1,7 +1,7 @@ /* * MicroDVD subtitle demuxer * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org> - * Copyright (c) 2012 Clément BÅ“sch <ubitux@gmail.com> + * Copyright (c) 2012 Clément BÅ“sch <u pkh me> * * This file is part of FFmpeg. * @@ -47,7 +47,7 @@ static int microdvd_probe(AVProbeData *p) sscanf(ptr, "{%*d}{%*d}%c", &c) != 1 && sscanf(ptr, "{DEFAULT}{}%c", &c) != 1) return 0; - ptr += strcspn(ptr, "\n") + 1; + ptr += ff_subtitles_next_line(ptr); } return AVPROBE_SCORE_MAX; } diff --git a/ffmpeg/libavformat/microdvdenc.c b/ffmpeg/libavformat/microdvdenc.c index 30fd0ea..4d84384 100644 --- a/ffmpeg/libavformat/microdvdenc.c +++ b/ffmpeg/libavformat/microdvdenc.c @@ -52,7 +52,6 @@ static int microdvd_write_packet(AVFormatContext *avf, AVPacket *pkt) avio_printf(avf->pb, "{%"PRId64"}", pkt->pts + pkt->duration); avio_write(avf->pb, pkt->data, pkt->size); avio_write(avf->pb, "\n", 1); - avio_flush(avf->pb); return 0; } diff --git a/ffmpeg/libavformat/mkvtimestamp_v2.c b/ffmpeg/libavformat/mkvtimestamp_v2.c index 3ed195a..7ba6691 100644 --- a/ffmpeg/libavformat/mkvtimestamp_v2.c +++ b/ffmpeg/libavformat/mkvtimestamp_v2.c @@ -37,7 +37,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_WARNING, "More than one stream unsupported\n"); snprintf(buf, sizeof(buf), "%" PRId64 "\n", pkt->dts); avio_write(s->pb, buf, strlen(buf)); - avio_flush(s->pb); return 0; } diff --git a/ffmpeg/libavformat/mm.c b/ffmpeg/libavformat/mm.c index 12a11ac..4315802 100644 --- a/ffmpeg/libavformat/mm.c +++ b/ffmpeg/libavformat/mm.c @@ -79,7 +79,7 @@ static int probe(AVProbeData *p) return 0; /* only return half certainty since this check is a bit sketchy */ - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; } static int read_header(AVFormatContext *s) diff --git a/ffmpeg/libavformat/mmf.c b/ffmpeg/libavformat/mmf.c index d074d7c..cb87a6d 100644 --- a/ffmpeg/libavformat/mmf.c +++ b/ffmpeg/libavformat/mmf.c @@ -21,8 +21,8 @@ #include "libavutil/channel_layout.h" #include "avformat.h" -#include "internal.h" #include "avio_internal.h" +#include "internal.h" #include "pcm.h" #include "rawenc.h" #include "riff.h" @@ -37,7 +37,7 @@ static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 }; static int mmf_rate(int code) { - if((code < 0) || (code > 4)) + if ((code < 0) || (code > 4)) return -1; return mmf_rates[code]; } @@ -46,8 +46,8 @@ static int mmf_rate(int code) static int mmf_rate_code(int rate) { int i; - for(i = 0; i < 5; i++) - if(mmf_rates[i] == rate) + for (i = 0; i < 5; i++) + if (mmf_rates[i] == rate) return i; return -1; } @@ -74,8 +74,9 @@ static int mmf_write_header(AVFormatContext *s) "VN:"LIBAVFORMAT_IDENT","; rate = mmf_rate_code(s->streams[0]->codec->sample_rate); - if(rate < 0) { - av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d, supported are 4000, 8000, 11025, 22050 and 44100\n", s->streams[0]->codec->sample_rate); + if (rate < 0) { + av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d, supported are 4000, 8000, 11025, 22050 and 44100\n", + s->streams[0]->codec->sample_rate); return AVERROR(EINVAL); } @@ -97,6 +98,7 @@ static int mmf_write_header(AVFormatContext *s) avio_w8(pb, 0); /* status */ avio_w8(pb, 0); /* counts */ end_tag_be(pb, pos); + pos = ff_start_tag(pb, "OPDA"); avio_write(pb, version, strlen(version)); /* metadata ("ST:songtitle,VN:version,...") */ end_tag_be(pb, pos); @@ -129,7 +131,7 @@ static int mmf_write_header(AVFormatContext *s) /* Write a variable-length symbol */ static void put_varlength(AVIOContext *pb, int val) { - if(val < 128) + if (val < 128) avio_w8(pb, val); else { val -= 128; @@ -151,7 +153,7 @@ static int mmf_write_trailer(AVFormatContext *s) end_tag_be(pb, mmf->atrpos); end_tag_be(pb, 8); - pos = avio_tell(pb); + pos = avio_tell(pb); size = pos - mmf->awapos; /* Fill Atsq chunk */ @@ -206,11 +208,13 @@ static int mmf_read_header(AVFormatContext *s) avio_skip(pb, 4); /* file_size */ /* Skip some unused chunks that may or may not be present */ - for(;; avio_skip(pb, size)) { - tag = avio_rl32(pb); + for (;; avio_skip(pb, size)) { + tag = avio_rl32(pb); size = avio_rb32(pb); - if(tag == MKTAG('C','N','T','I')) continue; - if(tag == MKTAG('O','P','D','A')) continue; + if (tag == MKTAG('C', 'N', 'T', 'I')) + continue; + if (tag == MKTAG('O', 'P', 'D', 'A')) + continue; break; } @@ -227,8 +231,8 @@ static int mmf_read_header(AVFormatContext *s) avio_r8(pb); /* format type */ avio_r8(pb); /* sequence type */ params = avio_r8(pb); /* (channel << 7) | (format << 4) | rate */ - rate = mmf_rate(params & 0x0f); - if(rate < 0) { + rate = mmf_rate(params & 0x0f); + if (rate < 0) { av_log(s, AV_LOG_ERROR, "Invalid sample rate\n"); return AVERROR_INVALIDDATA; } @@ -237,11 +241,13 @@ static int mmf_read_header(AVFormatContext *s) avio_r8(pb); /* time base g */ /* Skip some unused chunks that may or may not be present */ - for(;; avio_skip(pb, size)) { - tag = avio_rl32(pb); + for (;; avio_skip(pb, size)) { + tag = avio_rl32(pb); size = avio_rb32(pb); - if(tag == MKTAG('A','t','s','q')) continue; - if(tag == MKTAG('A','s','p','I')) continue; + if (tag == MKTAG('A', 't', 's', 'q')) + continue; + if (tag == MKTAG('A', 's', 'p', 'I')) + continue; break; } @@ -256,13 +262,14 @@ static int mmf_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = AV_CODEC_ID_ADPCM_YAMAHA; - st->codec->sample_rate = rate; - st->codec->channels = (params >> 7) + 1; - st->codec->channel_layout = params >> 7 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = AV_CODEC_ID_ADPCM_YAMAHA; + st->codec->sample_rate = rate; + st->codec->channels = (params >> 7) + 1; + st->codec->channel_layout = params >> 7 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; st->codec->bits_per_coded_sample = 4; - st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample; + st->codec->bit_rate = st->codec->sample_rate * + st->codec->bits_per_coded_sample; avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); @@ -271,8 +278,7 @@ static int mmf_read_header(AVFormatContext *s) #define MAX_SIZE 4096 -static int mmf_read_packet(AVFormatContext *s, - AVPacket *pkt) +static int mmf_read_packet(AVFormatContext *s, AVPacket *pkt) { MMFContext *mmf = s->priv_data; int64_t left, size; @@ -303,17 +309,18 @@ AVInputFormat ff_mmf_demuxer = { .flags = AVFMT_GENERIC_INDEX, }; #endif + #if CONFIG_MMF_MUXER AVOutputFormat ff_mmf_muxer = { - .name = "mmf", - .long_name = NULL_IF_CONFIG_SMALL("Yamaha SMAF"), - .mime_type = "application/vnd.smaf", - .extensions = "mmf", - .priv_data_size = sizeof(MMFContext), - .audio_codec = AV_CODEC_ID_ADPCM_YAMAHA, - .video_codec = AV_CODEC_ID_NONE, - .write_header = mmf_write_header, - .write_packet = ff_raw_write_packet, - .write_trailer = mmf_write_trailer, + .name = "mmf", + .long_name = NULL_IF_CONFIG_SMALL("Yamaha SMAF"), + .mime_type = "application/vnd.smaf", + .extensions = "mmf", + .priv_data_size = sizeof(MMFContext), + .audio_codec = AV_CODEC_ID_ADPCM_YAMAHA, + .video_codec = AV_CODEC_ID_NONE, + .write_header = mmf_write_header, + .write_packet = ff_raw_write_packet, + .write_trailer = mmf_write_trailer, }; #endif diff --git a/ffmpeg/libavformat/mms.c b/ffmpeg/libavformat/mms.c index 46fbede..7e60b3b 100644 --- a/ffmpeg/libavformat/mms.c +++ b/ffmpeg/libavformat/mms.c @@ -1,7 +1,7 @@ /* * MMS protocol common definitions. * Copyright (c) 2006,2007 Ryan Martell - * Copyright (c) 2007 Björn Axelsson + * Copyright (c) 2007 Björn Axelsson * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com> * * This file is part of FFmpeg. diff --git a/ffmpeg/libavformat/mmsh.c b/ffmpeg/libavformat/mmsh.c index 86a0575..482ece4 100644 --- a/ffmpeg/libavformat/mmsh.c +++ b/ffmpeg/libavformat/mmsh.c @@ -66,9 +66,9 @@ static int mmsh_close(URLContext *h) MMSHContext *mmsh = (MMSHContext *)h->priv_data; MMSContext *mms = &mmsh->mms; if (mms->mms_hd) - ffurl_close(mms->mms_hd); - av_free(mms->streams); - av_free(mms->asf_header); + ffurl_closep(&mms->mms_hd); + av_freep(&mms->streams); + av_freep(&mms->asf_header); return 0; } @@ -368,23 +368,26 @@ static int mmsh_read(URLContext *h, uint8_t *buf, int size) static int64_t mmsh_read_seek(URLContext *h, int stream_index, int64_t timestamp, int flags) { - MMSHContext *mmsh = h->priv_data; - MMSContext *mms = &mmsh->mms; + MMSHContext *mmsh_old = h->priv_data; + MMSHContext *mmsh = av_mallocz(sizeof(*mmsh)); int ret; - ret= mmsh_open_internal(h, mmsh->location, 0, FFMAX(timestamp, 0), 0); + if (!mmsh) + return AVERROR(ENOMEM); + h->priv_data = mmsh; + ret= mmsh_open_internal(h, mmsh_old->location, 0, FFMAX(timestamp, 0), 0); if(ret>=0){ - if (mms->mms_hd) - ffurl_close(mms->mms_hd); - av_freep(&mms->streams); - av_freep(&mms->asf_header); + h->priv_data = mmsh_old; + mmsh_close(h); + h->priv_data = mmsh; + av_free(mmsh_old); + mmsh->mms.asf_header_read_size = mmsh->mms.asf_header_size; + }else { + h->priv_data = mmsh_old; av_free(mmsh); - mmsh = h->priv_data; - mms = &mmsh->mms; - mms->asf_header_read_size= mms->asf_header_size; - }else - h->priv_data= mmsh; + } + return ret; } diff --git a/ffmpeg/libavformat/mmst.c b/ffmpeg/libavformat/mmst.c index c3d2ebb..ebef3ef 100644 --- a/ffmpeg/libavformat/mmst.c +++ b/ffmpeg/libavformat/mmst.c @@ -1,7 +1,7 @@ /* * MMS protocol over TCP * Copyright (c) 2006,2007 Ryan Martell - * Copyright (c) 2007 Björn Axelsson + * Copyright (c) 2007 Björn Axelsson * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com> * * This file is part of FFmpeg. @@ -152,7 +152,7 @@ static int send_command_packet(MMSTContext *mmst) return 0; } -static void mms_put_utf16(MMSContext *mms, const uint8_t *src) +static int mms_put_utf16(MMSContext *mms, const uint8_t *src) { AVIOContext bic; int size = mms->write_out_ptr - mms->out_buffer; @@ -161,7 +161,10 @@ static void mms_put_utf16(MMSContext *mms, const uint8_t *src) sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL); len = avio_put_str16le(&bic, src); + if (len < 0) + return len; mms->write_out_ptr += len; + return 0; } static int send_time_test_data(MMSTContext *mmst) @@ -173,6 +176,7 @@ static int send_time_test_data(MMSTContext *mmst) static int send_protocol_select(MMSTContext *mmst) { + int ret; char data_string[256]; MMSContext *mms = &mmst->mms; @@ -189,18 +193,21 @@ static int send_protocol_select(MMSTContext *mmst) "TCP", // or UDP LOCAL_PORT); - mms_put_utf16(mms, data_string); + if ((ret = mms_put_utf16(mms, data_string)) < 0) + return ret; return send_command_packet(mmst); } static int send_media_file_request(MMSTContext *mmst) { + int ret; MMSContext *mms = &mmst->mms; start_command_packet(mmst, CS_PKT_MEDIA_FILE_REQUEST); insert_command_prefixes(mms, 1, 0xffffffff); bytestream_put_le32(&mms->write_out_ptr, 0); bytestream_put_le32(&mms->write_out_ptr, 0); - mms_put_utf16(mms, mmst->path + 1); // +1 for skip "/" + if ((ret = mms_put_utf16(mms, mmst->path + 1)) < 0) // +1 for skip "/" + return ret; return send_command_packet(mmst); } @@ -331,16 +338,16 @@ static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst) // if we successfully read everything. if(packet_id_type == mmst->header_packet_id) { + int err; packet_type = SC_PKT_ASF_HEADER; // Store the asf header if(!mms->header_parsed) { - void *p = av_realloc(mms->asf_header, - mms->asf_header_size + mms->remaining_in_len); - if (!p) { - av_freep(&mms->asf_header); - return AVERROR(ENOMEM); + if ((err = av_reallocp(&mms->asf_header, + mms->asf_header_size + + mms->remaining_in_len)) < 0) { + mms->asf_header_size = 0; + return err; } - mms->asf_header = p; memcpy(mms->asf_header + mms->asf_header_size, mms->read_in_ptr, mms->remaining_in_len); mms->asf_header_size += mms->remaining_in_len; @@ -417,6 +424,7 @@ static int send_media_header_request(MMSTContext *mmst) static int send_startup_packet(MMSTContext *mmst) { char data_string[256]; + int ret; MMSContext *mms = &mmst->mms; // SubscriberName is defined in MS specification linked below. // The guid value can be any valid value. @@ -429,7 +437,8 @@ static int send_startup_packet(MMSTContext *mmst) start_command_packet(mmst, CS_PKT_INITIAL); insert_command_prefixes(mms, 0, 0x0004000b); bytestream_put_le32(&mms->write_out_ptr, 0x0003001c); - mms_put_utf16(mms, data_string); + if ((ret = mms_put_utf16(mms, data_string)) < 0) + return ret; return send_command_packet(mmst); } diff --git a/ffmpeg/libavformat/mov.c b/ffmpeg/libavformat/mov.c index 577c0e9..8dc6062 100644 --- a/ffmpeg/libavformat/mov.c +++ b/ffmpeg/libavformat/mov.c @@ -3,6 +3,9 @@ * Copyright (c) 2001 Fabrice Bellard * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com> * + * first version by Francois Revol <revol@free.fr> + * seek function by Gael Chardon <gael.dev@4now.net> + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -21,8 +24,8 @@ */ #include <limits.h> +#include <stdint.h> -//#define DEBUG //#define MOV_EXPORT_ALL_METADATA #include "libavutil/attributes.h" @@ -48,11 +51,6 @@ #include <zlib.h> #endif -/* - * First version by Francois Revol revol@free.fr - * Seek function by Gael Chardon gael.dev@4now.net - */ - #include "qtpalette.h" @@ -539,7 +537,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) dref->dir = av_malloc(len+1); if (!dref->dir) return AVERROR(ENOMEM); - avio_read(pb, dref->dir, len); + if (avio_read(pb, dref->dir, len) != len) + return AVERROR_INVALIDDATA; dref->dir[len] = 0; for (j = 0; j < len; j++) if (dref->dir[j] == ':') @@ -788,6 +787,12 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom) { int ret; + if (c->found_moov) { + av_log(c->fc, AV_LOG_WARNING, "Found duplicated MOOV Atom. Skipped it\n"); + avio_skip(pb, atom.size); + return 0; + } + if ((ret = mov_read_default(c, pb, atom)) < 0) return ret; /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */ @@ -833,6 +838,11 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) st = c->fc->streams[c->fc->nb_streams-1]; sc = st->priv_data; + if (sc->time_scale) { + av_log(c->fc, AV_LOG_ERROR, "Multiple mdhd?\n"); + return AVERROR_INVALIDDATA; + } + version = avio_r8(pb); if (version > 1) { avpriv_request_sample(c->fc, "Version %d", version); @@ -880,7 +890,7 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */ // set the AVCodecContext duration because the duration of individual tracks // may be inaccurate - if (c->time_scale > 0) + if (c->time_scale > 0 && !c->trex_data) c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale); avio_rb32(pb); /* preferred scale */ @@ -973,6 +983,7 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom, AVStream *st; uint64_t size; uint8_t *buf; + int err; if (c->fc->nb_streams < 1) // will happen with jp2 files return 0; @@ -984,15 +995,22 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom, size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE; if (size > INT_MAX || (uint64_t)atom.size > INT_MAX) return AVERROR_INVALIDDATA; - buf= av_realloc(st->codec->extradata, size); - if (!buf) - return AVERROR(ENOMEM); - st->codec->extradata= buf; - buf+= st->codec->extradata_size; + if ((err = av_reallocp(&st->codec->extradata, size)) < 0) { + st->codec->extradata_size = 0; + return err; + } + buf = st->codec->extradata + st->codec->extradata_size; st->codec->extradata_size= size - FF_INPUT_BUFFER_PADDING_SIZE; AV_WB32( buf , atom.size + 8); AV_WL32( buf + 4, atom.type); - avio_read(pb, buf + 8, atom.size); + err = avio_read(pb, buf + 8, atom.size); + if (err < 0) { + return err; + } else if (err < atom.size) { + av_log(c->fc, AV_LOG_WARNING, "truncated extradata\n"); + st->codec->extradata_size -= atom.size - err; + } + memset(buf + 8 + err, 0, FF_INPUT_BUFFER_PADDING_SIZE); return 0; } @@ -1017,6 +1035,38 @@ static int mov_read_avid(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI); } +static int mov_read_targa_y216(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + int ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_TARGA_Y216); + + if (!ret && c->fc->nb_streams >= 1) { + AVCodecContext *avctx = c->fc->streams[c->fc->nb_streams-1]->codec; + if (avctx->extradata_size >= 40) { + avctx->height = AV_RB16(&avctx->extradata[36]); + avctx->width = AV_RB16(&avctx->extradata[38]); + } + } + return ret; +} + +static int mov_read_ares(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + if (c->fc->nb_streams >= 1) { + AVCodecContext *codec = c->fc->streams[c->fc->nb_streams-1]->codec; + if (codec->codec_tag == MKTAG('A', 'V', 'i', 'n') && + codec->codec_id == AV_CODEC_ID_H264 && + atom.size > 11) { + avio_skip(pb, 10); + /* For AVID AVCI50, force width of 1440 to be able to select the correct SPS and PPS */ + if (avio_rb16(pb) == 0xd4d) + codec->width = 1440; + return 0; + } + } + + return mov_read_avid(c, pb, atom); +} + static int mov_read_svq3(MOVContext *c, AVIOContext *pb, MOVAtom atom) { return mov_read_extradata(c, pb, atom, AV_CODEC_ID_SVQ3); @@ -1033,15 +1083,13 @@ static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((uint64_t)atom.size > (1<<30)) return AVERROR_INVALIDDATA; - if (st->codec->codec_id == AV_CODEC_ID_QDM2 || st->codec->codec_id == AV_CODEC_ID_QDMC) { + if (st->codec->codec_id == AV_CODEC_ID_QDM2 || + st->codec->codec_id == AV_CODEC_ID_QDMC || + st->codec->codec_id == AV_CODEC_ID_SPEEX) { // pass all frma atom to codec, needed at least for QDMC and QDM2 av_free(st->codec->extradata); - st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, pb, atom.size) < 0) return AVERROR(ENOMEM); - st->codec->extradata_size = atom.size; - avio_read(pb, st->codec->extradata, atom.size); } else if (atom.size > 8) { /* to read frma, esds atoms */ int ret; if ((ret = mov_read_default(c, pb, atom)) < 0) @@ -1076,12 +1124,9 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_default(c, pb, atom); } av_free(st->codec->extradata); - st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, pb, atom.size) < 0) return AVERROR(ENOMEM); - st->codec->extradata_size = atom.size; - avio_read(pb, st->codec->extradata, atom.size); + return 0; } @@ -1089,6 +1134,7 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; uint8_t profile_level; + int ret; if (c->fc->nb_streams < 1) return 0; @@ -1101,14 +1147,11 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((profile_level & 0xf0) != 0xc0) return 0; - av_free(st->codec->extradata); - st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - st->codec->extradata_size = atom.size - 7; avio_seek(pb, 6, SEEK_CUR); - avio_read(pb, st->codec->extradata, st->codec->extradata_size); + av_free(st->codec->extradata); + if ((ret = ff_get_extradata(st->codec, pb, atom.size - 7)) < 0) + return ret; + return 0; } @@ -1130,14 +1173,10 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((uint64_t)atom.size > (1<<30)) return AVERROR_INVALIDDATA; + avio_skip(pb, 40); av_free(st->codec->extradata); - st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_get_extradata(st->codec, pb, atom.size - 40) < 0) return AVERROR(ENOMEM); - st->codec->extradata_size = atom.size - 40; - avio_skip(pb, 40); - avio_read(pb, st->codec->extradata, atom.size - 40); return 0; } @@ -1198,342 +1237,306 @@ enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags) return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0); } -int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) +static int mov_codec_id(AVStream *st, uint32_t format) { - AVStream *st; - MOVStreamContext *sc; - int j, pseudo_stream_id; - - if (c->fc->nb_streams < 1) - return 0; - st = c->fc->streams[c->fc->nb_streams-1]; - sc = st->priv_data; - - for (pseudo_stream_id = 0; - pseudo_stream_id < entries && !pb->eof_reached; - pseudo_stream_id++) { - //Parsing Sample description table - enum AVCodecID id; - int dref_id = 1; - MOVAtom a = { AV_RL32("stsd") }; - int64_t start_pos = avio_tell(pb); - int64_t size = avio_rb32(pb); /* size */ - uint32_t format = avio_rl32(pb); /* data format */ - - if (size >= 16) { - avio_rb32(pb); /* reserved */ - avio_rb16(pb); /* reserved */ - dref_id = avio_rb16(pb); - }else if (size <= 7){ - av_log(c->fc, AV_LOG_ERROR, "invalid size %"PRId64" in stsd\n", size); - return AVERROR_INVALIDDATA; - } + int id = ff_codec_get_id(ff_codec_movaudio_tags, format); - if (st->codec->codec_tag && - st->codec->codec_tag != format && - (c->fc->video_codec_id ? ff_codec_get_id(ff_codec_movvideo_tags, format) != c->fc->video_codec_id - : st->codec->codec_tag != MKTAG('j','p','e','g')) - ){ - /* Multiple fourcc, we skip JPEG. This is not correct, we should - * export it as a separate AVStream but this needs a few changes - * in the MOV demuxer, patch welcome. */ - av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n"); - avio_skip(pb, size - (avio_tell(pb) - start_pos)); - continue; - } - /* we cannot demux concatenated h264 streams because of different extradata */ - if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1")) - av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play corrently.\n"); - sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id; - sc->dref_id= dref_id; + if (id <= 0 && + ((format & 0xFFFF) == 'm' + ('s' << 8) || + (format & 0xFFFF) == 'T' + ('S' << 8))) + id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format) & 0xFFFF); - st->codec->codec_tag = format; - id = ff_codec_get_id(ff_codec_movaudio_tags, format); - if (id<=0 && ((format&0xFFFF) == 'm'+('s'<<8) || (format&0xFFFF) == 'T'+('S'<<8))) - id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format)&0xFFFF); - - if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO && id > 0) { - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - } else if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO && /* do not overwrite codec type */ - format && format != MKTAG('m','p','4','s')) { /* skip old asf mpeg4 tag */ - id = ff_codec_get_id(ff_codec_movvideo_tags, format); - if (id <= 0) - id = ff_codec_get_id(ff_codec_bmp_tags, format); + if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO && id > 0) { + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + } else if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO && + /* skip old asf mpeg4 tag */ + format && format != MKTAG('m','p','4','s')) { + id = ff_codec_get_id(ff_codec_movvideo_tags, format); + if (id <= 0) + id = ff_codec_get_id(ff_codec_bmp_tags, format); + if (id > 0) + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + else if (st->codec->codec_type == AVMEDIA_TYPE_DATA || + (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE && + st->codec->codec_id == AV_CODEC_ID_NONE)) { + id = ff_codec_get_id(ff_codec_movsubtitle_tags, format); if (id > 0) - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - else if (st->codec->codec_type == AVMEDIA_TYPE_DATA || - (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE && - st->codec->codec_id == AV_CODEC_ID_NONE)){ - id = ff_codec_get_id(ff_codec_movsubtitle_tags, format); - if (id > 0) - st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - } + st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; } + } - av_dlog(c->fc, "size=%"PRId64" 4CC= %c%c%c%c codec_type=%d\n", size, - (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, - (format >> 24) & 0xff, st->codec->codec_type); + st->codec->codec_tag = format; + + return id; +} + +static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, + AVStream *st, MOVStreamContext *sc) +{ + unsigned int color_depth, len, j; + int color_greyscale; + int color_table_id; + + avio_rb16(pb); /* version */ + avio_rb16(pb); /* revision level */ + avio_rb32(pb); /* vendor */ + avio_rb32(pb); /* temporal quality */ + avio_rb32(pb); /* spatial quality */ + + st->codec->width = avio_rb16(pb); /* width */ + st->codec->height = avio_rb16(pb); /* height */ + + avio_rb32(pb); /* horiz resolution */ + avio_rb32(pb); /* vert resolution */ + avio_rb32(pb); /* data size, always 0 */ + avio_rb16(pb); /* frames per samples */ + + len = avio_r8(pb); /* codec name, pascal string */ + if (len > 31) + len = 31; + mov_read_mac_string(c, pb, len, st->codec->codec_name, 32); + if (len < 31) + avio_skip(pb, 31 - len); + /* codec_tag YV12 triggers an UV swap in rawdec.c */ + if (!memcmp(st->codec->codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) { + st->codec->codec_tag = MKTAG('I', '4', '2', '0'); + st->codec->width &= ~1; + st->codec->height &= ~1; + } + /* Flash Media Server uses tag H263 with Sorenson Spark */ + if (st->codec->codec_tag == MKTAG('H','2','6','3') && + !memcmp(st->codec->codec_name, "Sorenson H263", 13)) + st->codec->codec_id = AV_CODEC_ID_FLV1; + + st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */ + color_table_id = avio_rb16(pb); /* colortable id */ + av_dlog(c->fc, "depth %d, ctab id %d\n", + st->codec->bits_per_coded_sample, color_table_id); + /* figure out the palette situation */ + color_depth = st->codec->bits_per_coded_sample & 0x1F; + color_greyscale = st->codec->bits_per_coded_sample & 0x20; + /* Do not create a greyscale palette for cinepak */ + if (color_greyscale && st->codec->codec_id == AV_CODEC_ID_CINEPAK) + return; - if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) { - unsigned int color_depth, len; - int color_greyscale; - int color_table_id; + /* if the depth is 2, 4, or 8 bpp, file is palettized */ + if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) { + /* for palette traversal */ + unsigned int color_start, color_count, color_end; + unsigned char a, r, g, b; + + if (color_greyscale) { + int color_index, color_dec; + /* compute the greyscale palette */ + color_count = 1 << color_depth; + color_index = 255; + color_dec = 256 / (color_count - 1); + for (j = 0; j < color_count; j++) { + r = g = b = color_index; + sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); + color_index -= color_dec; + if (color_index < 0) + color_index = 0; + } + } else if (color_table_id) { + const uint8_t *color_table; + /* if flag bit 3 is set, use the default palette */ + color_count = 1 << color_depth; + if (color_depth == 2) + color_table = ff_qt_default_palette_4; + else if (color_depth == 4) + color_table = ff_qt_default_palette_16; + else + color_table = ff_qt_default_palette_256; - st->codec->codec_id = id; - avio_rb16(pb); /* version */ - avio_rb16(pb); /* revision level */ - avio_rb32(pb); /* vendor */ - avio_rb32(pb); /* temporal quality */ - avio_rb32(pb); /* spatial quality */ - - st->codec->width = avio_rb16(pb); /* width */ - st->codec->height = avio_rb16(pb); /* height */ - - avio_rb32(pb); /* horiz resolution */ - avio_rb32(pb); /* vert resolution */ - avio_rb32(pb); /* data size, always 0 */ - avio_rb16(pb); /* frames per samples */ - - len = avio_r8(pb); /* codec name, pascal string */ - if (len > 31) - len = 31; - mov_read_mac_string(c, pb, len, st->codec->codec_name, 32); - if (len < 31) - avio_skip(pb, 31 - len); - /* codec_tag YV12 triggers an UV swap in rawdec.c */ - if (!memcmp(st->codec->codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)){ - st->codec->codec_tag=MKTAG('I', '4', '2', '0'); - st->codec->width &= ~1; - st->codec->height &= ~1; + for (j = 0; j < color_count; j++) { + r = color_table[j * 3 + 0]; + g = color_table[j * 3 + 1]; + b = color_table[j * 3 + 2]; + sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); } - /* Flash Media Server uses tag H263 with Sorenson Spark */ - if (format == MKTAG('H','2','6','3') && - !memcmp(st->codec->codec_name, "Sorenson H263", 13)) - st->codec->codec_id = AV_CODEC_ID_FLV1; - - st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */ - color_table_id = avio_rb16(pb); /* colortable id */ - av_dlog(c->fc, "depth %d, ctab id %d\n", - st->codec->bits_per_coded_sample, color_table_id); - /* figure out the palette situation */ - color_depth = st->codec->bits_per_coded_sample & 0x1F; - color_greyscale = st->codec->bits_per_coded_sample & 0x20; - - /* if the depth is 2, 4, or 8 bpp, file is palettized */ - if ((color_depth == 2) || (color_depth == 4) || - (color_depth == 8)) { - /* for palette traversal */ - unsigned int color_start, color_count, color_end; - unsigned char a, r, g, b; - - if (color_greyscale) { - int color_index, color_dec; - /* compute the greyscale palette */ - st->codec->bits_per_coded_sample = color_depth; - color_count = 1 << color_depth; - color_index = 255; - color_dec = 256 / (color_count - 1); - for (j = 0; j < color_count; j++) { - if (id == AV_CODEC_ID_CINEPAK){ - r = g = b = color_count - 1 - color_index; - }else - r = g = b = color_index; - sc->palette[j] = - (0xFFU << 24) | (r << 16) | (g << 8) | (b); - color_index -= color_dec; - if (color_index < 0) - color_index = 0; - } - } else if (color_table_id) { - const uint8_t *color_table; - /* if flag bit 3 is set, use the default palette */ - color_count = 1 << color_depth; - if (color_depth == 2) - color_table = ff_qt_default_palette_4; - else if (color_depth == 4) - color_table = ff_qt_default_palette_16; - else - color_table = ff_qt_default_palette_256; - - for (j = 0; j < color_count; j++) { - r = color_table[j * 3 + 0]; - g = color_table[j * 3 + 1]; - b = color_table[j * 3 + 2]; - sc->palette[j] = - (0xFFU << 24) | (r << 16) | (g << 8) | (b); - } - } else { - /* load the palette from the file */ - color_start = avio_rb32(pb); - color_count = avio_rb16(pb); - color_end = avio_rb16(pb); - if ((color_start <= 255) && - (color_end <= 255)) { - for (j = color_start; j <= color_end; j++) { - /* each A, R, G, or B component is 16 bits; - * only use the top 8 bits */ - a = avio_r8(pb); - avio_r8(pb); - r = avio_r8(pb); - avio_r8(pb); - g = avio_r8(pb); - avio_r8(pb); - b = avio_r8(pb); - avio_r8(pb); - sc->palette[j] = - (a << 24 ) | (r << 16) | (g << 8) | (b); - } - } + } else { + /* load the palette from the file */ + color_start = avio_rb32(pb); + color_count = avio_rb16(pb); + color_end = avio_rb16(pb); + if ((color_start <= 255) && (color_end <= 255)) { + for (j = color_start; j <= color_end; j++) { + /* each A, R, G, or B component is 16 bits; + * only use the top 8 bits */ + a = avio_r8(pb); + avio_r8(pb); + r = avio_r8(pb); + avio_r8(pb); + g = avio_r8(pb); + avio_r8(pb); + b = avio_r8(pb); + avio_r8(pb); + sc->palette[j] = (a << 24 ) | (r << 16) | (g << 8) | (b); } - sc->has_palette = 1; } - } else if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO) { - int bits_per_sample, flags; - uint16_t version = avio_rb16(pb); - AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE); + } + sc->has_palette = 1; + } +} - st->codec->codec_id = id; - avio_rb16(pb); /* revision level */ - avio_rb32(pb); /* vendor */ - - st->codec->channels = avio_rb16(pb); /* channel count */ - av_dlog(c->fc, "audio channels %d\n", st->codec->channels); - st->codec->bits_per_coded_sample = avio_rb16(pb); /* sample size */ - - sc->audio_cid = avio_rb16(pb); - avio_rb16(pb); /* packet size = 0 */ - - st->codec->sample_rate = ((avio_rb32(pb) >> 16)); - - //Read QT version 1 fields. In version 0 these do not exist. - av_dlog(c->fc, "version =%d, isom =%d\n",version,c->isom); - if (!c->isom || - (compatible_brands && strstr(compatible_brands->value, "qt "))) { - if (version==1) { - sc->samples_per_frame = avio_rb32(pb); - avio_rb32(pb); /* bytes per packet */ - sc->bytes_per_frame = avio_rb32(pb); - avio_rb32(pb); /* bytes per sample */ - } else if (version==2) { - avio_rb32(pb); /* sizeof struct only */ - st->codec->sample_rate = av_int2double(avio_rb64(pb)); /* float 64 */ - st->codec->channels = avio_rb32(pb); - avio_rb32(pb); /* always 0x7F000000 */ - st->codec->bits_per_coded_sample = avio_rb32(pb); /* bits per channel if sound is uncompressed */ - flags = avio_rb32(pb); /* lpcm format specific flag */ - sc->bytes_per_frame = avio_rb32(pb); /* bytes per audio packet if constant */ - sc->samples_per_frame = avio_rb32(pb); /* lpcm frames per audio packet if constant */ - if (format == MKTAG('l','p','c','m')) - st->codec->codec_id = ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, flags); - } - } +static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, + AVStream *st, MOVStreamContext *sc) +{ + int bits_per_sample, flags; + uint16_t version = avio_rb16(pb); + AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE); - switch (st->codec->codec_id) { - case AV_CODEC_ID_PCM_S8: - case AV_CODEC_ID_PCM_U8: - if (st->codec->bits_per_coded_sample == 16) - st->codec->codec_id = AV_CODEC_ID_PCM_S16BE; - break; - case AV_CODEC_ID_PCM_S16LE: - case AV_CODEC_ID_PCM_S16BE: - if (st->codec->bits_per_coded_sample == 8) - st->codec->codec_id = AV_CODEC_ID_PCM_S8; - else if (st->codec->bits_per_coded_sample == 24) - st->codec->codec_id = - st->codec->codec_id == AV_CODEC_ID_PCM_S16BE ? - AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE; - break; - /* set values for old format before stsd version 1 appeared */ - case AV_CODEC_ID_MACE3: - sc->samples_per_frame = 6; - sc->bytes_per_frame = 2*st->codec->channels; - break; - case AV_CODEC_ID_MACE6: - sc->samples_per_frame = 6; - sc->bytes_per_frame = 1*st->codec->channels; - break; - case AV_CODEC_ID_ADPCM_IMA_QT: - sc->samples_per_frame = 64; - sc->bytes_per_frame = 34*st->codec->channels; - break; - case AV_CODEC_ID_GSM: - sc->samples_per_frame = 160; - sc->bytes_per_frame = 33; - break; - default: - break; - } + avio_rb16(pb); /* revision level */ + avio_rb32(pb); /* vendor */ - bits_per_sample = av_get_bits_per_sample(st->codec->codec_id); - if (bits_per_sample) { - st->codec->bits_per_coded_sample = bits_per_sample; - sc->sample_size = (bits_per_sample >> 3) * st->codec->channels; - } - } else if (st->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){ - // ttxt stsd contains display flags, justification, background - // color, fonts, and default styles, so fake an atom to read it - MOVAtom fake_atom = { .size = size - (avio_tell(pb) - start_pos) }; - if (format != AV_RL32("mp4s")) // mp4s contains a regular esds atom - mov_read_glbl(c, pb, fake_atom); - st->codec->codec_id= id; - st->codec->width = sc->width; - st->codec->height = sc->height; - } else { - if (st->codec->codec_tag == MKTAG('t','m','c','d')) { - MOVStreamContext *tmcd_ctx = st->priv_data; - int val; - avio_rb32(pb); /* reserved */ - val = avio_rb32(pb); /* flags */ - tmcd_ctx->tmcd_flags = val; - if (val & 1) - st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE; - avio_rb32(pb); /* time scale */ - avio_rb32(pb); /* frame duration */ - st->codec->time_base.den = avio_r8(pb); /* number of frame */ - st->codec->time_base.num = 1; - } - /* other codec type, just skip (rtp, mp4s, ...) */ - avio_skip(pb, size - (avio_tell(pb) - start_pos)); + st->codec->channels = avio_rb16(pb); /* channel count */ + st->codec->bits_per_coded_sample = avio_rb16(pb); /* sample size */ + av_dlog(c->fc, "audio channels %d\n", st->codec->channels); + + sc->audio_cid = avio_rb16(pb); + avio_rb16(pb); /* packet size = 0 */ + + st->codec->sample_rate = ((avio_rb32(pb) >> 16)); + + // Read QT version 1 fields. In version 0 these do not exist. + av_dlog(c->fc, "version =%d, isom =%d\n", version, c->isom); + if (!c->isom || + (compatible_brands && strstr(compatible_brands->value, "qt "))) { + + if (version == 1) { + sc->samples_per_frame = avio_rb32(pb); + avio_rb32(pb); /* bytes per packet */ + sc->bytes_per_frame = avio_rb32(pb); + avio_rb32(pb); /* bytes per sample */ + } else if (version == 2) { + avio_rb32(pb); /* sizeof struct only */ + st->codec->sample_rate = av_int2double(avio_rb64(pb)); + st->codec->channels = avio_rb32(pb); + avio_rb32(pb); /* always 0x7F000000 */ + st->codec->bits_per_coded_sample = avio_rb32(pb); + + flags = avio_rb32(pb); /* lpcm format specific flag */ + sc->bytes_per_frame = avio_rb32(pb); + sc->samples_per_frame = avio_rb32(pb); + if (st->codec->codec_tag == MKTAG('l','p','c','m')) + st->codec->codec_id = + ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, + flags); } - /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ - a.size = size - (avio_tell(pb) - start_pos); - if (a.size > 8) { - int ret; - if ((ret = mov_read_default(c, pb, a)) < 0) - return ret; - } else if (a.size > 0) - avio_skip(pb, a.size); } - if (pb->eof_reached) - return AVERROR_EOF; + switch (st->codec->codec_id) { + case AV_CODEC_ID_PCM_S8: + case AV_CODEC_ID_PCM_U8: + if (st->codec->bits_per_coded_sample == 16) + st->codec->codec_id = AV_CODEC_ID_PCM_S16BE; + break; + case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S16BE: + if (st->codec->bits_per_coded_sample == 8) + st->codec->codec_id = AV_CODEC_ID_PCM_S8; + else if (st->codec->bits_per_coded_sample == 24) + st->codec->codec_id = + st->codec->codec_id == AV_CODEC_ID_PCM_S16BE ? + AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE; + break; + /* set values for old format before stsd version 1 appeared */ + case AV_CODEC_ID_MACE3: + sc->samples_per_frame = 6; + sc->bytes_per_frame = 2 * st->codec->channels; + break; + case AV_CODEC_ID_MACE6: + sc->samples_per_frame = 6; + sc->bytes_per_frame = 1 * st->codec->channels; + break; + case AV_CODEC_ID_ADPCM_IMA_QT: + sc->samples_per_frame = 64; + sc->bytes_per_frame = 34 * st->codec->channels; + break; + case AV_CODEC_ID_GSM: + sc->samples_per_frame = 160; + sc->bytes_per_frame = 33; + break; + default: + break; + } + + bits_per_sample = av_get_bits_per_sample(st->codec->codec_id); + if (bits_per_sample) { + st->codec->bits_per_coded_sample = bits_per_sample; + sc->sample_size = (bits_per_sample >> 3) * st->codec->channels; + } +} - if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) - st->codec->sample_rate= sc->time_scale; +static void mov_parse_stsd_subtitle(MOVContext *c, AVIOContext *pb, + AVStream *st, MOVStreamContext *sc, + int size) +{ + // ttxt stsd contains display flags, justification, background + // color, fonts, and default styles, so fake an atom to read it + MOVAtom fake_atom = { .size = size }; + // mp4s contains a regular esds atom + if (st->codec->codec_tag != AV_RL32("mp4s")) + mov_read_glbl(c, pb, fake_atom); + st->codec->width = sc->width; + st->codec->height = sc->height; +} + +static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb, + AVStream *st, MOVStreamContext *sc, + int size) +{ + if (st->codec->codec_tag == MKTAG('t','m','c','d')) { + if (ff_get_extradata(st->codec, pb, size) < 0) + return AVERROR(ENOMEM); + if (size > 16) { + MOVStreamContext *tmcd_ctx = st->priv_data; + int val; + val = AV_RB32(st->codec->extradata + 4); + tmcd_ctx->tmcd_flags = val; + if (val & 1) + st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE; + st->codec->time_base.den = st->codec->extradata[16]; /* number of frame */ + st->codec->time_base.num = 1; + } + } else { + /* other codec type, just skip (rtp, mp4s ...) */ + avio_skip(pb, size); + } + return 0; +} + +static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, + AVStream *st, MOVStreamContext *sc) +{ + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && + !st->codec->sample_rate && sc->time_scale > 1) + st->codec->sample_rate = sc->time_scale; /* special codec parameters handling */ switch (st->codec->codec_id) { #if CONFIG_DV_DEMUXER case AV_CODEC_ID_DVAUDIO: - c->dv_fctx = avformat_alloc_context(); + c->dv_fctx = avformat_alloc_context(); c->dv_demux = avpriv_dv_init_demux(c->dv_fctx); if (!c->dv_demux) { av_log(c->fc, AV_LOG_ERROR, "dv demux context init error\n"); return AVERROR(ENOMEM); } sc->dv_audio_container = 1; - st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; break; #endif /* no ifdef since parameters are always those */ case AV_CODEC_ID_QCELP: + st->codec->channels = 1; // force sample rate for qcelp when not stored in mov if (st->codec->codec_tag != MKTAG('Q','c','l','p')) st->codec->sample_rate = 8000; - st->codec->channels= 1; /* really needed */ break; case AV_CODEC_ID_AMR_NB: - st->codec->channels= 1; /* really needed */ + st->codec->channels = 1; /* force sample rate for amr, stsd in 3gp does not store sample rate */ st->codec->sample_rate = 8000; break; @@ -1543,19 +1546,23 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) break; case AV_CODEC_ID_MP2: case AV_CODEC_ID_MP3: - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; /* force type after stsd for m1a hdlr */ - st->need_parsing = AVSTREAM_PARSE_FULL; + /* force type after stsd for m1a hdlr */ + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->need_parsing = AVSTREAM_PARSE_FULL; break; case AV_CODEC_ID_GSM: case AV_CODEC_ID_ADPCM_MS: case AV_CODEC_ID_ADPCM_IMA_WAV: case AV_CODEC_ID_ILBC: + case AV_CODEC_ID_MACE3: + case AV_CODEC_ID_MACE6: + case AV_CODEC_ID_QDM2: st->codec->block_align = sc->bytes_per_frame; break; case AV_CODEC_ID_ALAC: if (st->codec->extradata_size == 36) { - st->codec->channels = AV_RB8 (st->codec->extradata+21); - st->codec->sample_rate = AV_RB32(st->codec->extradata+32); + st->codec->channels = AV_RB8 (st->codec->extradata + 21); + st->codec->sample_rate = AV_RB32(st->codec->extradata + 32); } break; case AV_CODEC_ID_AC3: @@ -1570,10 +1577,111 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) default: break; } + return 0; +} + +static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb, + int codec_tag, int format, + int size) +{ + int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format); + + if (codec_tag && + (codec_tag != format && + (c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id + : codec_tag != MKTAG('j','p','e','g')))) { + /* Multiple fourcc, we skip JPEG. This is not correct, we should + * export it as a separate AVStream but this needs a few changes + * in the MOV demuxer, patch welcome. */ + + av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n"); + avio_skip(pb, size); + return 1; + } + if ( codec_tag == AV_RL32("avc1") || + codec_tag == AV_RL32("hvc1") || + codec_tag == AV_RL32("hev1") + ) + av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n"); return 0; } +int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) +{ + AVStream *st; + MOVStreamContext *sc; + int pseudo_stream_id; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + sc = st->priv_data; + + for (pseudo_stream_id = 0; + pseudo_stream_id < entries && !pb->eof_reached; + pseudo_stream_id++) { + //Parsing Sample description table + enum AVCodecID id; + int ret, dref_id = 1; + MOVAtom a = { AV_RL32("stsd") }; + int64_t start_pos = avio_tell(pb); + int64_t size = avio_rb32(pb); /* size */ + uint32_t format = avio_rl32(pb); /* data format */ + + if (size >= 16) { + avio_rb32(pb); /* reserved */ + avio_rb16(pb); /* reserved */ + dref_id = avio_rb16(pb); + }else if (size <= 7){ + av_log(c->fc, AV_LOG_ERROR, "invalid size %"PRId64" in stsd\n", size); + return AVERROR_INVALIDDATA; + } + + if (mov_skip_multiple_stsd(c, pb, st->codec->codec_tag, format, + size - (avio_tell(pb) - start_pos))) + continue; + + sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id; + sc->dref_id= dref_id; + + id = mov_codec_id(st, format); + + av_dlog(c->fc, "size=%"PRId64" 4CC= %c%c%c%c codec_type=%d\n", size, + (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, + (format >> 24) & 0xff, st->codec->codec_type); + + if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) { + st->codec->codec_id = id; + mov_parse_stsd_video(c, pb, st, sc); + } else if (st->codec->codec_type==AVMEDIA_TYPE_AUDIO) { + st->codec->codec_id = id; + mov_parse_stsd_audio(c, pb, st, sc); + } else if (st->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){ + st->codec->codec_id = id; + mov_parse_stsd_subtitle(c, pb, st, sc, + size - (avio_tell(pb) - start_pos)); + } else { + ret = mov_parse_stsd_data(c, pb, st, sc, + size - (avio_tell(pb) - start_pos)); + if (ret < 0) + return ret; + } + /* this will read extra atoms at the end (wave, alac, damr, avcC, hvcC, SMI ...) */ + a.size = size - (avio_tell(pb) - start_pos); + if (a.size > 8) { + if ((ret = mov_read_default(c, pb, a)) < 0) + return ret; + } else if (a.size > 0) + avio_skip(pb, a.size); + } + + if (pb->eof_reached) + return AVERROR_EOF; + + return mov_finalize_stsd_codec(c, pb, st, sc); +} + static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { int entries; @@ -1679,6 +1787,8 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!entries) { sc->keyframe_absent = 1; + if (!st->need_parsing && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + st->need_parsing = AVSTREAM_PARSE_HEADERS; return 0; } if (entries >= UINT_MAX / sizeof(int)) @@ -1720,7 +1830,7 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) sample_size = avio_rb32(pb); if (!sc->sample_size) /* do not overwrite value computed in stsd */ sc->sample_size = sample_size; - sc->alt_sample_size = sample_size; + sc->stsz_sample_size = sample_size; field_size = 32; } else { sample_size = 0; @@ -1811,11 +1921,16 @@ 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\n", sample_duration); sample_duration = 1; } + if (sample_count < 0) { + av_log(c->fc, AV_LOG_ERROR, "Invalid sample_count=%d\n", sample_count); + return AVERROR_INVALIDDATA; + } sc->stts_data[i].count= sample_count; sc->stts_data[i].duration= sample_duration; @@ -1838,6 +1953,13 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static void mov_update_dts_shift(MOVStreamContext *sc, int duration) +{ + if (duration < 0) { + sc->dts_shift = FFMAX(sc->dts_shift, -duration); + } +} + static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -1880,8 +2002,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } - if (duration < 0 && i+2<entries) - sc->dts_shift = FFMAX(sc->dts_shift, -duration); + if (i+2<entries) + mov_update_dts_shift(sc, duration); } sc->ctts_count = i; @@ -1945,7 +2067,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int stps_index = 0; unsigned int i, j; uint64_t stream_size = 0; - AVIndexEntry *mem; /* adjust first dts according to edit list */ if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) { @@ -1980,17 +2101,31 @@ static void mov_build_index(MOVContext *mov, AVStream *st) return; if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries) return; - mem = av_realloc(st->index_entries, (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries)); - if (!mem) + if (av_reallocp_array(&st->index_entries, + st->nb_index_entries + sc->sample_count, + sizeof(*st->index_entries)) < 0) { + st->nb_index_entries = 0; return; - st->index_entries = mem; + } st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries); for (i = 0; i < sc->chunk_count; i++) { + int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX; current_offset = sc->chunk_offsets[i]; while (stsc_index + 1 < sc->stsc_count && i + 1 == sc->stsc_data[stsc_index + 1].first) stsc_index++; + + if (next_offset > current_offset && sc->sample_size>0 && sc->sample_size < sc->stsz_sample_size && + sc->stsc_data[stsc_index].count * (int64_t)sc->stsz_sample_size > next_offset - current_offset) { + av_log(mov->fc, AV_LOG_WARNING, "STSZ sample size %d invalid (too large), ignoring\n", sc->stsz_sample_size); + sc->stsz_sample_size = sc->sample_size; + } + if (sc->stsz_sample_size>0 && sc->stsz_sample_size < sc->sample_size) { + av_log(mov->fc, AV_LOG_WARNING, "STSZ sample size %d invalid (too small), ignoring\n", sc->stsz_sample_size); + sc->stsz_sample_size = sc->sample_size; + } + for (j = 0; j < sc->stsc_data[stsc_index].count; j++) { int keyframe = 0; if (current_sample >= sc->sample_count) { @@ -2017,7 +2152,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } if (keyframe) distance = 0; - sample_size = sc->alt_sample_size > 0 ? sc->alt_sample_size : sc->sample_sizes[current_sample]; + sample_size = sc->stsz_sample_size > 0 ? sc->stsz_sample_size : sc->sample_sizes[current_sample]; if (sc->pseudo_stream_id == -1 || sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) { AVIndexEntry *e = &st->index_entries[st->nb_index_entries++]; @@ -2029,6 +2164,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) av_dlog(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " "size %d, distance %d, keyframe %d\n", st->index, current_sample, current_offset, current_dts, sample_size, distance, keyframe); + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->nb_index_entries < 100) + ff_rfps_add_frame(mov->fc, st, current_dts); } current_offset += sample_size; @@ -2078,10 +2215,12 @@ static void mov_build_index(MOVContext *mov, AVStream *st) av_dlog(mov->fc, "chunk count %d\n", total); if (total >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries) return; - mem = av_realloc(st->index_entries, (st->nb_index_entries + total) * sizeof(*st->index_entries)); - if (!mem) + if (av_reallocp_array(&st->index_entries, + st->nb_index_entries + total, + sizeof(*st->index_entries)) < 0) { + st->nb_index_entries = 0; return; - st->index_entries = mem; + } st->index_entries_allocated_size = (st->nb_index_entries + total) * sizeof(*st->index_entries); // populate index @@ -2258,8 +2397,10 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) // done for ai5q, ai52, ai55, ai1q, ai12 and ai15. if (!st->codec->extradata_size && st->codec->codec_id == AV_CODEC_ID_H264 && - st->codec->codec_tag != MKTAG('a', 'v', 'c', '1')) { - ff_generate_avci_extradata(st); + TAG_IS_AVCI(st->codec->codec_tag)) { + ret = ff_generate_avci_extradata(st); + if (ret < 0) + return ret; } switch (st->codec->codec_id) { @@ -2322,6 +2463,7 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st; MOVStreamContext *sc; int version; + int flags; if (c->fc->nb_streams < 1) return 0; @@ -2329,13 +2471,8 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc = st->priv_data; version = avio_r8(pb); - avio_rb24(pb); /* flags */ - /* - MOV_TRACK_ENABLED 0x0001 - MOV_TRACK_IN_MOVIE 0x0002 - MOV_TRACK_IN_PREVIEW 0x0004 - MOV_TRACK_IN_POSTER 0x0008 - */ + flags = avio_rb24(pb); + st->disposition |= (flags & MOV_TKHD_FLAG_ENABLED) ? AV_DISPOSITION_DEFAULT : 0; if (version == 1) { avio_rb64(pb); @@ -2456,16 +2593,18 @@ static int mov_read_chap(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_trex(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVTrackExt *trex; + int err; if ((uint64_t)c->trex_count+1 >= UINT_MAX / sizeof(*c->trex_data)) return AVERROR_INVALIDDATA; - trex = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data)); - if (!trex) - return AVERROR(ENOMEM); + if ((err = av_reallocp_array(&c->trex_data, c->trex_count + 1, + sizeof(*c->trex_data))) < 0) { + c->trex_count = 0; + return err; + } c->fc->duration = AV_NOPTS_VALUE; // the duration from mvhd is not representing the whole file when fragments are used. - c->trex_data = trex; trex = &c->trex_data[c->trex_count++]; avio_r8(pb); /* version */ avio_rb24(pb); /* flags */ @@ -2487,7 +2626,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) int64_t dts; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; - int flags, distance, i, found_keyframe = 0; + int flags, distance, i, found_keyframe = 0, err; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -2500,7 +2639,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; } sc = st->priv_data; - if (sc->pseudo_stream_id+1 != frag->stsd_id) + if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1) return 0; avio_r8(pb); /* version */ flags = avio_rb24(pb); @@ -2515,7 +2654,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!sc->ctts_count && sc->sample_count) { /* Complement ctts table if moov atom doesn't have ctts atom. */ - ctts_data = av_malloc(sizeof(*sc->ctts_data)); + ctts_data = av_realloc(NULL, sizeof(*sc->ctts_data)); if (!ctts_data) return AVERROR(ENOMEM); sc->ctts_data = ctts_data; @@ -2525,12 +2664,11 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) } if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data)) return AVERROR_INVALIDDATA; - ctts_data = av_realloc(sc->ctts_data, - (entries+sc->ctts_count)*sizeof(*sc->ctts_data)); - if (!ctts_data) - return AVERROR(ENOMEM); - sc->ctts_data = ctts_data; - + if ((err = av_reallocp_array(&sc->ctts_data, entries + sc->ctts_count, + sizeof(*sc->ctts_data))) < 0) { + sc->ctts_count = 0; + return err; + } if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb); if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); dts = sc->track_end - sc->time_offset; @@ -2549,6 +2687,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->ctts_data[sc->ctts_count].count = 1; sc->ctts_data[sc->ctts_count].duration = (flags & MOV_TRUN_SAMPLE_CTS) ? avio_rb32(pb) : 0; + mov_update_dts_shift(sc, sc->ctts_data[sc->ctts_count].duration); sc->ctts_count++; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) keyframe = 1; @@ -2709,11 +2848,77 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + int ret; + uint8_t uuid[16]; + static const uint8_t uuid_isml_manifest[] = { + 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd, + 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 + }; + + if (atom.size < sizeof(uuid) || atom.size == INT64_MAX) + return AVERROR_INVALIDDATA; + + ret = avio_read(pb, uuid, sizeof(uuid)); + if (ret < 0) { + return ret; + } else if (ret != sizeof(uuid)) { + return AVERROR_INVALIDDATA; + } + if (!memcmp(uuid, uuid_isml_manifest, sizeof(uuid))) { + uint8_t *buffer, *ptr; + char *endptr; + size_t len = atom.size - sizeof(uuid); + + if (len < 4) { + return AVERROR_INVALIDDATA; + } + ret = avio_skip(pb, 4); // zeroes + len -= 4; + + buffer = av_mallocz(len + 1); + if (!buffer) { + return AVERROR(ENOMEM); + } + ret = avio_read(pb, buffer, len); + if (ret < 0) { + av_free(buffer); + return ret; + } else if (ret != len) { + av_free(buffer); + return AVERROR_INVALIDDATA; + } + + ptr = buffer; + while ((ptr = av_stristr(ptr, "systemBitrate=\"")) != NULL) { + ptr += sizeof("systemBitrate=\"") - 1; + c->bitrates_count++; + c->bitrates = av_realloc_f(c->bitrates, c->bitrates_count, sizeof(*c->bitrates)); + if (!c->bitrates) { + c->bitrates_count = 0; + av_free(buffer); + return AVERROR(ENOMEM); + } + errno = 0; + ret = strtol(ptr, &endptr, 10); + if (ret < 0 || errno || *endptr != '"') { + c->bitrates[c->bitrates_count - 1] = 0; + } else { + c->bitrates[c->bitrates_count - 1] = ret; + } + } + + av_free(buffer); + } + return 0; +} + static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('A','C','L','R'), mov_read_avid }, { MKTAG('A','P','R','G'), mov_read_avid }, { MKTAG('A','A','L','P'), mov_read_avid }, -{ MKTAG('A','R','E','S'), mov_read_avid }, +{ MKTAG('A','R','E','S'), mov_read_ares }, { MKTAG('a','v','s','s'), mov_read_avss }, { MKTAG('c','h','p','l'), mov_read_chpl }, { MKTAG('c','o','6','4'), mov_read_stco }, @@ -2772,6 +2977,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */ { MKTAG('d','v','c','1'), mov_read_dvc1 }, { MKTAG('s','b','g','p'), mov_read_sbgp }, +{ MKTAG('h','v','c','C'), mov_read_glbl }, +{ MKTAG('u','u','i','d'), mov_read_uuid }, +{ MKTAG('C','i','n', 0x8e), mov_read_targa_y216 }, { 0, NULL } }; @@ -2845,8 +3053,10 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) left = a.size - avio_tell(pb) + start_pos; if (left > 0) /* skip garbage at atom end */ avio_skip(pb, left); - else if(left < 0) { - av_log(c->fc, AV_LOG_DEBUG, "undoing overread of %"PRId64" in '%.4s'\n", -left, (char*)&a.type); + else if (left < 0) { + av_log(c->fc, AV_LOG_WARNING, + "overread end of atom '%.4s' by %"PRId64" bytes\n", + (char*)&a.type, -left); avio_seek(pb, left, SEEK_CUR); } } @@ -2887,7 +3097,7 @@ static int mov_probe(AVProbeData *p) (AV_RB32(p->buf+offset) != 1 || offset + 12 > (unsigned int)p->buf_size || AV_RB64(p->buf+offset + 8) == 0)) { - score = FFMAX(score, AVPROBE_SCORE_MAX - 50); + score = FFMAX(score, AVPROBE_SCORE_EXTENSION); } else { score = AVPROBE_SCORE_MAX; } @@ -2907,7 +3117,7 @@ static int mov_probe(AVProbeData *p) case MKTAG('u','u','i','d'): case MKTAG('p','r','f','l'): /* if we only find those cause probedata is too small at least rate them */ - score = FFMAX(score, AVPROBE_SCORE_MAX - 50); + score = FFMAX(score, AVPROBE_SCORE_EXTENSION); offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset; break; default: @@ -3088,6 +3298,7 @@ static int mov_read_close(AVFormatContext *s) } av_freep(&mov->trex_data); + av_freep(&mov->bitrates); return 0; } @@ -3195,11 +3406,19 @@ static int mov_read_header(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; MOVStreamContext *sc = st->priv_data; - if (st->duration) + if (st->duration > 0) st->codec->bit_rate = sc->data_size * 8 * sc->time_scale / st->duration; } } + for (i = 0; i < mov->bitrates_count && i < s->nb_streams; i++) { + if (mov->bitrates[i]) { + s->streams[i]->codec->bit_rate = mov->bitrates[i]; + } + } + + ff_rfps_calculate(s); + return 0; } @@ -3255,6 +3474,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) /* must be done just before reading, to avoid infinite loop on sample */ sc->current_sample++; + if (mov->next_root_atom) { + sample->pos = FFMIN(sample->pos, mov->next_root_atom); + sample->size = FFMIN(sample->size, (mov->next_root_atom - sample->pos)); + } + if (st->discard != AVDISCARD_ALL) { if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n", @@ -3387,7 +3611,7 @@ static const AVOption options[] = { {NULL} }; -static const AVClass class = { +static const AVClass mov_class = { .class_name = "mov,mp4,m4a,3gp,3g2,mj2", .item_name = av_default_item_name, .option = options, @@ -3403,6 +3627,6 @@ AVInputFormat ff_mov_demuxer = { .read_packet = mov_read_packet, .read_close = mov_read_close, .read_seek = mov_read_seek, - .priv_class = &class, + .priv_class = &mov_class, .flags = AVFMT_NO_BYTE_SEEK, }; diff --git a/ffmpeg/libavformat/mov_chan.c b/ffmpeg/libavformat/mov_chan.c index 7078b4a..e7b5221 100644 --- a/ffmpeg/libavformat/mov_chan.c +++ b/ffmpeg/libavformat/mov_chan.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2011 Justin Ruggles * - * 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 */ diff --git a/ffmpeg/libavformat/mov_chan.h b/ffmpeg/libavformat/mov_chan.h index 3fae939..ca28345 100644 --- a/ffmpeg/libavformat/mov_chan.h +++ b/ffmpeg/libavformat/mov_chan.h @@ -1,20 +1,20 @@ /* * Copyright (c) 2011 Justin Ruggles * - * 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 */ diff --git a/ffmpeg/libavformat/movenc.c b/ffmpeg/libavformat/movenc.c index 42496b5..a886ab0 100644 --- a/ffmpeg/libavformat/movenc.c +++ b/ffmpeg/libavformat/movenc.c @@ -21,6 +21,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "movenc.h" #include "avformat.h" #include "avio_internal.h" @@ -52,7 +54,8 @@ static const AVOption options[] = { { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, - { "faststart", "Run a second pass to put the moov at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, @@ -62,6 +65,7 @@ static const AVOption options[] = { { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM}, + { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, { NULL }, }; @@ -73,6 +77,8 @@ static const AVClass flavor ## _muxer_class = {\ .version = LIBAVUTIL_VERSION_INT,\ }; +static int get_moov_size(AVFormatContext *s); + //FIXME support 64 bit variant with wide placeholders static int64_t update_size(AVIOContext *pb, int64_t pos) { @@ -86,20 +92,14 @@ static int64_t update_size(AVIOContext *pb, int64_t pos) static int supports_edts(MOVMuxContext *mov) { - // EDTS with fragments is tricky as we dont know the duration when its written + // EDTS with fragments is tricky as we don't know the duration when its written return (mov->use_editlist<0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) || mov->use_editlist>0; } -static int is_co64_required(const MOVTrack *track) +static int co64_required(const MOVTrack *track) { - int i; - - for (i = 0; i < track->entry; i++) { - if (!track->cluster[i].chunkNum) - continue; - if (track->cluster[i].pos + track->data_offset > UINT32_MAX) - return 1; - } + if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX) + return 1; return 0; } @@ -107,7 +107,7 @@ static int is_co64_required(const MOVTrack *track) static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) { int i; - int mode64 = is_co64_required(track); // use 32 bit size variant if possible + int mode64 = co64_required(track); // use 32 bit size variant if possible int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ if (mode64) @@ -116,10 +116,10 @@ static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "stco"); avio_wb32(pb, 0); /* version & flags */ avio_wb32(pb, track->chunkCount); /* entry count */ - for (i=0; i<track->entry; i++) { - if(!track->cluster[i].chunkNum) + for (i = 0; i < track->entry; i++) { + if (!track->cluster[i].chunkNum) continue; - if(mode64 == 1) + if (mode64 == 1) avio_wb64(pb, track->cluster[i].pos + track->data_offset); else avio_wb32(pb, track->cluster[i].pos + track->data_offset); @@ -138,27 +138,25 @@ static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "stsz"); avio_wb32(pb, 0); /* version & flags */ - for (i=0; i<track->entry; i++) { - tst = track->cluster[i].size/track->cluster[i].entries; - if(oldtst != -1 && tst != oldtst) { + for (i = 0; i < track->entry; i++) { + tst = track->cluster[i].size / track->cluster[i].entries; + if (oldtst != -1 && tst != oldtst) equalChunks = 0; - } oldtst = tst; entries += track->cluster[i].entries; } if (equalChunks && track->entry) { - int sSize = track->entry ? track->cluster[0].size/track->cluster[0].entries : 0; + int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0; sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0 avio_wb32(pb, sSize); // sample size avio_wb32(pb, entries); // sample count - } - else { + } else { avio_wb32(pb, 0); // sample size avio_wb32(pb, entries); // sample count - for (i=0; i<track->entry; i++) { - for (j=0; j<track->cluster[i].entries; j++) { + for (i = 0; i < track->entry; i++) { + for (j = 0; j < track->cluster[i].entries; j++) { avio_wb32(pb, track->cluster[i].size / - track->cluster[i].entries); + track->cluster[i].entries); } } } @@ -177,9 +175,8 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) avio_wb32(pb, 0); // version & flags entryPos = avio_tell(pb); avio_wb32(pb, track->chunkCount); // entry count - for (i=0; i<track->entry; i++) { - if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) - { + for (i = 0; i < track->entry; i++) { + if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) { avio_wb32(pb, track->cluster[i].chunkNum); // first chunk avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk avio_wb32(pb, 0x1); // sample description index @@ -206,9 +203,9 @@ static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag) avio_wb32(pb, 0); // version & flags entryPos = avio_tell(pb); avio_wb32(pb, track->entry); // entry count - for (i=0; i<track->entry; i++) { + for (i = 0; i < track->entry; i++) { if (track->cluster[i].flags & flag) { - avio_wb32(pb, i+1); + avio_wb32(pb, i + 1); index++; } } @@ -268,7 +265,7 @@ static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track) put_bits(&pbc, 3, bsmod); put_bits(&pbc, 3, acmod); put_bits(&pbc, 1, lfeon); - put_bits(&pbc, 5, frmsizecod>>1); // bit_rate_code + put_bits(&pbc, 5, frmsizecod >> 1); // bit_rate_code put_bits(&pbc, 5, 0); // reserved flush_put_bits(&pbc); @@ -307,8 +304,8 @@ static void put_descr(AVIOContext *pb, int tag, unsigned int size) { int i = 3; avio_w8(pb, tag); - for(; i>0; i--) - avio_w8(pb, (size>>(7*i)) | 0x80); + for (; i > 0; i--) + avio_w8(pb, (size >> (7 * i)) | 0x80); avio_w8(pb, size & 0x7F); } @@ -351,7 +348,7 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio) // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved) - if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO) + if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_w8(pb, 0x15); // flags (= Audiostream) else avio_w8(pb, 0x11); // flags (= Visualstream) @@ -707,7 +704,7 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) avio_wb16(pb, 0); /* Reserved */ } - if(version == 1) { /* SoundDescription V1 extended info */ + if (version == 1) { /* SoundDescription V1 extended info */ if (mov_pcm_le_gt16(track->enc->codec_id) || mov_pcm_be_gt16(track->enc->codec_id)) avio_wb32(pb, 1); /* must be 1 for uncompressed formats */ @@ -718,24 +715,24 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) avio_wb32(pb, 2); /* Bytes per sample */ } - if(track->mode == MODE_MOV && - (track->enc->codec_id == AV_CODEC_ID_AAC || - track->enc->codec_id == AV_CODEC_ID_AC3 || - track->enc->codec_id == AV_CODEC_ID_AMR_NB || - track->enc->codec_id == AV_CODEC_ID_ALAC || - track->enc->codec_id == AV_CODEC_ID_ADPCM_MS || - track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV || - track->enc->codec_id == AV_CODEC_ID_QDM2 || - (mov_pcm_le_gt16(track->enc->codec_id) && version==1) || - (mov_pcm_be_gt16(track->enc->codec_id) && version==1))) + if (track->mode == MODE_MOV && + (track->enc->codec_id == AV_CODEC_ID_AAC || + track->enc->codec_id == AV_CODEC_ID_AC3 || + track->enc->codec_id == AV_CODEC_ID_AMR_NB || + track->enc->codec_id == AV_CODEC_ID_ALAC || + track->enc->codec_id == AV_CODEC_ID_ADPCM_MS || + track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV || + track->enc->codec_id == AV_CODEC_ID_QDM2 || + (mov_pcm_le_gt16(track->enc->codec_id) && version==1) || + (mov_pcm_be_gt16(track->enc->codec_id) && version==1))) mov_write_wave_tag(pb, track); - else if(track->tag == MKTAG('m','p','4','a')) + else if (track->tag == MKTAG('m','p','4','a')) mov_write_esds_tag(pb, track); - else if(track->enc->codec_id == AV_CODEC_ID_AMR_NB) + else if (track->enc->codec_id == AV_CODEC_ID_AMR_NB) mov_write_amr_tag(pb, track); - else if(track->enc->codec_id == AV_CODEC_ID_AC3) + else if (track->enc->codec_id == AV_CODEC_ID_AC3) mov_write_ac3_tag(pb, track); - else if(track->enc->codec_id == AV_CODEC_ID_ALAC) + else if (track->enc->codec_id == AV_CODEC_ID_ALAC) mov_write_extradata_tag(pb, track); else if (track->enc->codec_id == AV_CODEC_ID_WMAPRO) mov_write_wfex_tag(pb, track); @@ -796,7 +793,7 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) avio_wb32(pb, track->enc->width); /* values below are based on samples created with quicktime and avid codecs */ if (track->vos_data[5] & 2) { // interlaced - avio_wb32(pb, track->enc->height/2); + avio_wb32(pb, track->enc->height / 2); avio_wb32(pb, 2); /* unknown */ avio_wb32(pb, 0); /* unknown */ avio_wb32(pb, 4); /* unknown */ @@ -830,18 +827,18 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track) else if (track->enc->codec_id == AV_CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c'); else if (track->enc->codec_id == AV_CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g'); else if (track->enc->codec_id == AV_CODEC_ID_VC1) tag = MKTAG('v','c','-','1'); - else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); - else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); + else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); + else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); return tag; } static const AVCodecTag codec_ipod_tags[] = { - { AV_CODEC_ID_H264, MKTAG('a','v','c','1') }, - { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, - { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') }, - { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') }, - { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') }, + { AV_CODEC_ID_H264, MKTAG('a','v','c','1') }, + { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, + { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') }, + { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') }, + { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') }, { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') }, { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') }, { AV_CODEC_ID_NONE, 0 }, @@ -853,8 +850,8 @@ static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track) // keep original tag for subs, ipod supports both formats if (!(track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE && - (tag == MKTAG('t','x','3','g') || - tag == MKTAG('t','e','x','t')))) + (tag == MKTAG('t', 'x', '3', 'g') || + tag == MKTAG('t', 'e', 'x', 't')))) tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id); if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v")) @@ -871,16 +868,16 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track) if (track->enc->width == 720) { /* SD */ if (track->enc->height == 480) { /* NTSC */ if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n'); - else tag = MKTAG('d','v','c',' '); + else tag = MKTAG('d','v','c',' '); }else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p'); else if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p'); - else tag = MKTAG('d','v','p','p'); + else tag = MKTAG('d','v','p','p'); } else if (track->enc->height == 720) { /* HD 720 line */ - if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q'); - else tag = MKTAG('d','v','h','p'); + if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q'); + else tag = MKTAG('d','v','h','p'); } else if (track->enc->height == 1080) { /* HD 1080 line */ - if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5'); - else tag = MKTAG('d','v','h','6'); + if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5'); + else tag = MKTAG('d','v','h','6'); } else { av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n"); return 0; @@ -889,6 +886,78 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track) return tag; } +static AVRational find_fps(AVFormatContext *s, AVStream *st) +{ + AVRational rate = {st->codec->time_base.den, st->codec->time_base.num}; + /* if the codec time base makes no sense, try to fallback on stream frame rate */ + if (av_timecode_check_frame_rate(rate) < 0) { + av_log(s, AV_LOG_DEBUG, "timecode: tbc=%d/%d invalid, fallback on %d/%d\n", + rate.num, rate.den, st->avg_frame_rate.num, st->avg_frame_rate.den); + rate = st->avg_frame_rate; + } + + return rate; +} + +static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track) +{ + int tag = MKTAG('m', '2', 'v', '1'); //fallback tag + int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE; + AVStream *st = track->st; + int rate = av_q2d(find_fps(s, st)); + + if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) { + if (track->enc->width == 1280 && track->enc->height == 720) { + if (!interlaced) { + if (rate == 24) tag = MKTAG('x','d','v','4'); + else if (rate == 25) tag = MKTAG('x','d','v','5'); + else if (rate == 30) tag = MKTAG('x','d','v','1'); + else if (rate == 50) tag = MKTAG('x','d','v','a'); + else if (rate == 60) tag = MKTAG('x','d','v','9'); + } + } else if (track->enc->width == 1440 && track->enc->height == 1080) { + if (!interlaced) { + if (rate == 24) tag = MKTAG('x','d','v','6'); + else if (rate == 25) tag = MKTAG('x','d','v','7'); + else if (rate == 30) tag = MKTAG('x','d','v','8'); + } else { + if (rate == 25) tag = MKTAG('x','d','v','3'); + else if (rate == 30) tag = MKTAG('x','d','v','2'); + } + } else if (track->enc->width == 1920 && track->enc->height == 1080) { + if (!interlaced) { + if (rate == 24) tag = MKTAG('x','d','v','d'); + else if (rate == 25) tag = MKTAG('x','d','v','e'); + else if (rate == 30) tag = MKTAG('x','d','v','f'); + } else { + if (rate == 25) tag = MKTAG('x','d','v','c'); + else if (rate == 30) tag = MKTAG('x','d','v','b'); + } + } + } else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) { + if (track->enc->width == 1280 && track->enc->height == 720) { + if (!interlaced) { + if (rate == 24) tag = MKTAG('x','d','5','4'); + else if (rate == 25) tag = MKTAG('x','d','5','5'); + else if (rate == 30) tag = MKTAG('x','d','5','1'); + else if (rate == 50) tag = MKTAG('x','d','5','a'); + else if (rate == 60) tag = MKTAG('x','d','5','9'); + } + } else if (track->enc->width == 1920 && track->enc->height == 1080) { + if (!interlaced) { + if (rate == 24) tag = MKTAG('x','d','5','d'); + else if (rate == 25) tag = MKTAG('x','d','5','e'); + else if (rate == 30) tag = MKTAG('x','d','5','f'); + } else { + if (rate == 25) tag = MKTAG('x','d','5','c'); + else if (rate == 30) tag = MKTAG('x','d','5','b'); + } + } + } + + return tag; +} + static const struct { enum AVPixelFormat pix_fmt; uint32_t tag; @@ -936,11 +1005,14 @@ static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track) (track->enc->codec_id == AV_CODEC_ID_DVVIDEO || track->enc->codec_id == AV_CODEC_ID_RAWVIDEO || track->enc->codec_id == AV_CODEC_ID_H263 || + track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO || av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio if (track->enc->codec_id == AV_CODEC_ID_DVVIDEO) tag = mov_get_dv_codec_tag(s, track); else if (track->enc->codec_id == AV_CODEC_ID_RAWVIDEO) tag = mov_get_rawvideo_codec_tag(s, track); + else if (track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO) + tag = mov_get_mpeg2_xdcam_codec_tag(s, track); else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) { tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->enc->codec_id); if (!tag) { // if no mac fcc found, try with Microsoft tags @@ -967,12 +1039,12 @@ static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track) } static const AVCodecTag codec_3gp_tags[] = { - { AV_CODEC_ID_H263, MKTAG('s','2','6','3') }, - { AV_CODEC_ID_H264, MKTAG('a','v','c','1') }, - { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, - { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') }, - { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, - { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') }, + { AV_CODEC_ID_H263, MKTAG('s','2','6','3') }, + { AV_CODEC_ID_H264, MKTAG('a','v','c','1') }, + { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, + { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') }, + { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, + { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') }, { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') }, { AV_CODEC_ID_NONE, 0 }, }; @@ -981,6 +1053,7 @@ static const AVCodecTag codec_f4v_tags[] = { // XXX: add GIF/PNG/JPEG? { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') }, { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') }, { AV_CODEC_ID_H264, MKTAG('a','v','c','1') }, + { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') }, { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') }, { AV_CODEC_ID_NONE, 0 }, }; @@ -999,7 +1072,7 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) tag = ipod_get_codec_tag(s, track); else if (track->mode & MODE_3GP) tag = ff_codec_get_tag(codec_3gp_tags, track->enc->codec_id); - else if (track->mode & MODE_F4V) + else if (track->mode == MODE_F4V) tag = ff_codec_get_tag(codec_f4v_tags, track->enc->codec_id); else tag = mov_get_codec_tag(s, track); @@ -1068,6 +1141,32 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) return 16; } +static void find_compressor(char * compressor_name, int len, MOVTrack *track) +{ + int xdcam_res = (track->enc->width == 1280 && track->enc->height == 720) + || (track->enc->width == 1440 && track->enc->height == 1080) + || (track->enc->width == 1920 && track->enc->height == 1080); + + if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name) { + av_strlcpy(compressor_name, track->enc->codec->name, 32); + } else if (track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) { + int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE; + AVStream *st = track->st; + int rate = av_q2d(find_fps(NULL, st)); + av_strlcatf(compressor_name, len, "XDCAM"); + if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) { + av_strlcatf(compressor_name, len, " HD422"); + } else if(track->enc->width == 1440) { + av_strlcatf(compressor_name, len, " HD"); + } else + av_strlcatf(compressor_name, len, " EX"); + + av_strlcatf(compressor_name, len, " %d%c", track->enc->height, interlaced ? 'i' : 'p'); + + av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1)); + } +} + static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); @@ -1083,7 +1182,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) avio_wb16(pb, 0); /* Codec stream revision (=0) */ if (track->mode == MODE_MOV) { ffio_wfourcc(pb, "FFMP"); /* Vendor */ - if(track->enc->codec_id == AV_CODEC_ID_RAWVIDEO) { + if (track->enc->codec_id == AV_CODEC_ID_RAWVIDEO) { avio_wb32(pb, 0); /* Temporal Quality */ avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/ } else { @@ -1103,8 +1202,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) avio_wb16(pb, 1); /* Frame count (= 1) */ /* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */ - if (track->mode == MODE_MOV && track->enc->codec && track->enc->codec->name) - av_strlcpy(compressor_name,track->enc->codec->name,32); + find_compressor(compressor_name, 32, track); avio_w8(pb, strlen(compressor_name)); avio_write(pb, compressor_name, 31); @@ -1113,23 +1211,27 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) else avio_wb16(pb, 0x18); /* Reserved */ avio_wb16(pb, 0xffff); /* Reserved */ - if(track->tag == MKTAG('m','p','4','v')) + if (track->tag == MKTAG('m','p','4','v')) mov_write_esds_tag(pb, track); - else if(track->enc->codec_id == AV_CODEC_ID_H263) + else if (track->enc->codec_id == AV_CODEC_ID_H263) mov_write_d263_tag(pb); - else if(track->enc->codec_id == AV_CODEC_ID_AVUI || + else if (track->enc->codec_id == AV_CODEC_ID_AVUI || track->enc->codec_id == AV_CODEC_ID_SVQ3) { mov_write_extradata_tag(pb, track); avio_wb32(pb, 0); - } else if(track->enc->codec_id == AV_CODEC_ID_DNXHD) + } else if (track->enc->codec_id == AV_CODEC_ID_DNXHD) mov_write_avid_tag(pb, track); - else if(track->enc->codec_id == AV_CODEC_ID_H264) { + else if (track->enc->codec_id == AV_CODEC_ID_H264) { mov_write_avcc_tag(pb, track); - if(track->mode == MODE_IPOD) + if (track->mode == MODE_IPOD) mov_write_uuid_tag_ipod(pb); } else if (track->enc->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0) mov_write_dvc1_tag(pb, track); - else if (track->vos_len > 0) + else if (track->enc->codec_id == AV_CODEC_ID_VP6F || + track->enc->codec_id == AV_CODEC_ID_VP6A) { + /* Don't write any potential extradata here - the cropping + * is signalled via the normal width/height fields. */ + } else if (track->vos_len > 0) mov_write_glbl_tag(pb, track); if (track->enc->codec_id != AV_CODEC_ID_H264 && @@ -1146,9 +1248,30 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } +static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track) +{ + int64_t pos = avio_tell(pb); + avio_wb32(pb, 0); /* size */ + ffio_wfourcc(pb, "rtp "); + avio_wb32(pb, 0); /* Reserved */ + avio_wb16(pb, 0); /* Reserved */ + avio_wb16(pb, 1); /* Data-reference index */ + + avio_wb16(pb, 1); /* Hint track version */ + avio_wb16(pb, 1); /* Highest compatible version */ + avio_wb32(pb, track->max_packet_size); /* Max packet size */ + + avio_wb32(pb, 12); /* size */ + ffio_wfourcc(pb, "tims"); + avio_wb32(pb, track->timescale); + + return update_size(pb, pos); +} + static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); +#if 1 int frame_duration = av_rescale(track->timescale, track->enc->time_base.num, track->enc->time_base.den); int nb_frames = 1.0/av_q2d(track->enc->time_base) + 0.5; @@ -1168,26 +1291,15 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track) avio_w8(pb, nb_frames); /* Number of frames */ avio_wb24(pb, 0); /* Reserved */ /* TODO: source reference string */ - return update_size(pb, pos); -} +#else -static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track) -{ - int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ - ffio_wfourcc(pb, "rtp "); - avio_wb32(pb, 0); /* Reserved */ - avio_wb16(pb, 0); /* Reserved */ - avio_wb16(pb, 1); /* Data-reference index */ - - avio_wb16(pb, 1); /* Hint track version */ - avio_wb16(pb, 1); /* Highest compatible version */ - avio_wb32(pb, track->max_packet_size); /* Max packet size */ - - avio_wb32(pb, 12); /* size */ - ffio_wfourcc(pb, "tims"); - avio_wb32(pb, track->timescale); - + ffio_wfourcc(pb, "tmcd"); /* Data format */ + avio_wb32(pb, 0); /* Reserved */ + avio_wb32(pb, 1); /* Data reference index */ + if (track->enc->extradata_size) + avio_write(pb, track->enc->extradata, track->enc->extradata_size); +#endif return update_size(pb, pos); } @@ -1221,7 +1333,7 @@ static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track) ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */ ctts_entries[0].count = 1; ctts_entries[0].duration = track->cluster[0].cts; - for (i=1; i<track->entry; i++) { + for (i = 1; i < track->entry; i++) { if (track->cluster[i].cts == ctts_entries[entries].duration) { ctts_entries[entries].count++; /* compress */ } else { @@ -1236,7 +1348,7 @@ static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "ctts"); avio_wb32(pb, 0); /* version & flags */ avio_wb32(pb, entries); /* entry count */ - for (i=0; i<entries; i++) { + for (i = 0; i < entries; i++) { avio_wb32(pb, ctts_entries[i].count); avio_wb32(pb, ctts_entries[i].duration); } @@ -1261,7 +1373,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track) stts_entries = track->entry ? av_malloc(track->entry * sizeof(*stts_entries)) : /* worst case */ NULL; - for (i=0; i<track->entry; i++) { + for (i = 0; i < track->entry; i++) { int duration = get_cluster_duration(track, i); if (i && duration == stts_entries[entries].duration) { stts_entries[entries].count++; /* compress */ @@ -1278,7 +1390,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "stts"); avio_wb32(pb, 0); /* version & flags */ avio_wb32(pb, entries); /* entry count */ - for (i=0; i<entries; i++) { + for (i = 0; i < entries; i++) { avio_wb32(pb, stts_entries[i].count); avio_wb32(pb, stts_entries[i].duration); } @@ -1432,18 +1544,18 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) const char *hdlr, *descr = NULL, *hdlr_type = NULL; int64_t pos = avio_tell(pb); - if (!track) { /* no media --> data handler */ - hdlr = "dhlr"; - hdlr_type = "url "; - descr = "DataHandler"; - } else { + hdlr = "dhlr"; + hdlr_type = "url "; + descr = "DataHandler"; + + if (track) { hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0"; if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) { hdlr_type = "vide"; - descr = "VideoHandler"; + descr = "VideoHandler"; } else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) { hdlr_type = "soun"; - descr = "SoundHandler"; + descr = "SoundHandler"; } else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) { if (track->tag == MKTAG('c','6','0','8')) { hdlr_type = "clcp"; @@ -1453,16 +1565,20 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) else hdlr_type = "text"; descr = "SubtitleHandler"; } + } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) { + hdlr_type = "hint"; + descr = "HintHandler"; } else if (track->enc->codec_tag == MKTAG('t','m','c','d')) { hdlr_type = "tmcd"; descr = "TimeCodeHandler"; - } else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) { - hdlr_type = "hint"; - descr = "HintHandler"; } else { - hdlr = "dhlr"; - hdlr_type = "url "; - descr = "DataHandler"; + char tag_buf[32]; + av_get_codec_tag_string(tag_buf, sizeof(tag_buf), + track->enc->codec_tag); + + av_log(track->enc, AV_LOG_WARNING, + "Unknown hldr_type for %s / 0x%04X, writing dummy values\n", + tag_buf, track->enc->codec_tag); } } @@ -1471,9 +1587,9 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track) avio_wb32(pb, 0); /* Version & flags */ avio_write(pb, hdlr, 4); /* handler */ ffio_wfourcc(pb, hdlr_type); /* handler type */ - avio_wb32(pb ,0); /* reserved */ - avio_wb32(pb ,0); /* reserved */ - avio_wb32(pb ,0); /* reserved */ + avio_wb32(pb, 0); /* reserved */ + avio_wb32(pb, 0); /* reserved */ + avio_wb32(pb, 0); /* reserved */ if (!track || track->mode == MODE_MOV) avio_w8(pb, strlen(descr)); /* pascal string */ avio_write(pb, descr, strlen(descr)); /* handler description */ @@ -1502,7 +1618,7 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track) int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "minf"); - if(track->enc->codec_type == AVMEDIA_TYPE_VIDEO) + if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) mov_write_vmhd_tag(pb); else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) mov_write_smhd_tag(pb); @@ -1512,10 +1628,10 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track) } else { mov_write_nmhd_tag(pb); } - } else if (track->tag == MKTAG('t','m','c','d')) { - mov_write_gmhd_tag(pb, track); } else if (track->tag == MKTAG('r','t','p',' ')) { mov_write_hmhd_tag(pb); + } else if (track->tag == MKTAG('t','m','c','d')) { + mov_write_gmhd_tag(pb, track); } if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ mov_write_hdlr_tag(pb, NULL); @@ -1550,11 +1666,11 @@ static int mov_write_mdhd_tag(AVIOContext *pb, MOVTrack *track) avio_wb16(pb, track->language); /* language */ avio_wb16(pb, 0); /* reserved (quality) */ - if(version!=0 && track->mode == MODE_MOV){ + if (version != 0 && track->mode == MODE_MOV) { av_log(NULL, AV_LOG_ERROR, - "FATAL error, file duration too long for timebase, this file will not be\n" - "playable with quicktime. Choose a different timebase or a different\n" - "container format\n"); + "FATAL error, file duration too long for timebase, this file will not be\n" + "playable with quicktime. Choose a different timebase or a different\n" + "container format\n"); } return 32; @@ -1602,7 +1718,9 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */ ffio_wfourcc(pb, "tkhd"); avio_w8(pb, version); - avio_wb24(pb, track->secondary ? 0x2 : 0xf); /* flags (first track enabled) */ + avio_wb24(pb, (track->flags & MOV_TRACK_ENABLED) ? + MOV_TKHD_FLAG_ENABLED | MOV_TKHD_FLAG_IN_MOVIE : + MOV_TKHD_FLAG_IN_MOVIE); if (version == 1) { avio_wb64(pb, track->time); avio_wb64(pb, track->time); @@ -1622,7 +1740,7 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) avio_wb16(pb, 0); /* layer */ avio_wb16(pb, st ? st->codec->codec_type : 0); /* alternate group) */ /* Volume, only for audio */ - if(track->enc->codec_type == AVMEDIA_TYPE_AUDIO) + if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO) avio_wb16(pb, 0x0100); else avio_wb16(pb, 0); @@ -1643,20 +1761,19 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) write_matrix(pb, 1, 0, 0, 1, 0, 0); } /* Track width and height, for visual only */ - if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO || - track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) { - if(track->mode == MODE_MOV) { + if (st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO || + track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) { + if (track->mode == MODE_MOV) { avio_wb32(pb, track->enc->width << 16); avio_wb32(pb, track->height << 16); } else { double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); - if(!sample_aspect_ratio || track->height != track->enc->height) + if (!sample_aspect_ratio || track->height != track->enc->height) sample_aspect_ratio = 1; - avio_wb32(pb, sample_aspect_ratio * track->enc->width*0x10000); - avio_wb32(pb, track->height*0x10000); + avio_wb32(pb, sample_aspect_ratio * track->enc->width * 0x10000); + avio_wb32(pb, track->height * 0x10000); } - } - else { + } else { avio_wb32(pb, 0); avio_wb32(pb, 0); } @@ -1777,7 +1894,6 @@ static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov) static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track) { - AVFormatContext *ctx = track->rtp_ctx; char buf[1000] = ""; int len; @@ -1810,14 +1926,14 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_tref_tag(pb, track); mov_write_mdia_tag(pb, track); if (track->mode == MODE_PSP) - mov_write_uuid_tag_psp(pb,track); // PSP Movies require this uuid box + mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box if (track->tag == MKTAG('r','t','p',' ')) mov_write_udta_sdp(pb, track); if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO && track->mode == MODE_MOV) { double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) mov_write_tapt_tag(pb, track); - }; + } return update_size(pb, pos); } @@ -1828,7 +1944,7 @@ static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov) int audio_profile = mov->iods_audio_profile; int video_profile = mov->iods_video_profile; for (i = 0; i < mov->nb_streams; i++) { - if(mov->tracks[i].entry > 0) { + if (mov->tracks[i].entry > 0) { has_audio |= mov->tracks[i].enc->codec_type == AVMEDIA_TYPE_AUDIO; has_video |= mov->tracks[i].enc->codec_type == AVMEDIA_TYPE_VIDEO; } @@ -1880,8 +1996,8 @@ static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov) int64_t max_track_len_temp, max_track_len = 0; int version; - for (i=0; i<mov->nb_streams; i++) { - if(mov->tracks[i].entry > 0) { + for (i = 0; i < mov->nb_streams; i++) { + if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) { max_track_len_temp = av_rescale_rnd(mov->tracks[i].track_duration, MOV_TIMESCALE, mov->tracks[i].timescale, @@ -1945,7 +2061,7 @@ static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov, /* helper function to write a data tag with the specified string as data */ static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style) { - if(long_style){ + if (long_style) { int size = 16 + strlen(data); avio_wb32(pb, size); /* size */ ffio_wfourcc(pb, "data"); @@ -1953,7 +2069,7 @@ static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang avio_wb32(pb, 0); avio_write(pb, data, strlen(data)); return size; - }else{ + } else { if (!lang) lang = ff_mov_iso639_to_lang("und", 1); avio_wb16(pb, strlen(data)); /* string length */ @@ -1963,7 +2079,9 @@ static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang } } -static int mov_write_string_tag(AVIOContext *pb, const char *name, const char *value, int lang, int long_style){ +static int mov_write_string_tag(AVIOContext *pb, const char *name, + const char *value, int lang, int long_style) +{ int size = 0; if (value && value[0]) { int64_t pos = avio_tell(pb); @@ -1990,8 +2108,8 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb, snprintf(tag2, sizeof(tag2), "%s-", tag); while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) { len2 = strlen(t2->key); - if (len2 == len+4 && !strcmp(t->value, t2->value) - && (l=ff_mov_iso639_to_lang(&t2->key[len2-3], 1)) >= 0) { + if (len2 == len + 4 && !strcmp(t->value, t2->value) + && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) { lang = l; break; } @@ -2017,23 +2135,29 @@ static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s) return size; } -/* iTunes track number */ +/* iTunes track or disc number */ static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov, - AVFormatContext *s) + AVFormatContext *s, int disc) { - AVDictionaryEntry *t = av_dict_get(s->metadata, "track", NULL, 0); + AVDictionaryEntry *t = av_dict_get(s->metadata, + disc ? "disc" : "track", + NULL, 0); int size = 0, track = t ? atoi(t->value) : 0; if (track) { + int tracks = 0; + char *slash = strchr(t->value, '/'); + if (slash) + tracks = atoi(slash + 1); avio_wb32(pb, 32); /* size */ - ffio_wfourcc(pb, "trkn"); - avio_wb32(pb, 24); /* size */ - ffio_wfourcc(pb, "data"); - avio_wb32(pb, 0); // 8 bytes empty - avio_wb32(pb, 0); - avio_wb16(pb, 0); // empty - avio_wb16(pb, track); // track number - avio_wb16(pb, 0); // total track number - avio_wb16(pb, 0); // empty + ffio_wfourcc(pb, disc ? "disk" : "trkn"); + avio_wb32(pb, 24); /* size */ + ffio_wfourcc(pb, "data"); + avio_wb32(pb, 0); // 8 bytes empty + avio_wb32(pb, 0); + avio_wb16(pb, 0); // empty + avio_wb16(pb, track); // track / disc number + avio_wb16(pb, tracks); // total track / disc number + avio_wb16(pb, 0); // empty size = 32; } return size; @@ -2045,16 +2169,25 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb, { AVDictionaryEntry *t = NULL; uint8_t num; + int size = 24 + len; + + if (len != 1 && len != 4) + return -1; if (!(t = av_dict_get(s->metadata, tag, NULL, 0))) return 0; num = atoi(t->value); - avio_wb32(pb, len+8); + avio_wb32(pb, size); ffio_wfourcc(pb, name); + avio_wb32(pb, size - 8); + ffio_wfourcc(pb, "data"); + avio_wb32(pb, 0x15); + avio_wb32(pb, 0); if (len==4) avio_wb32(pb, num); else avio_w8 (pb, num); - return len+8; + + return size; } /* iTunes meta data list */ @@ -2086,7 +2219,8 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_int8_metadata (s, pb, "stik", "media_type",1); mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1); mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1); - mov_write_trkn_tag(pb, mov, s); + mov_write_trkn_tag(pb, mov, s, 0); // track number + mov_write_trkn_tag(pb, mov, s, 1); // disc number mov_write_tmpo_tag(pb, s); return update_size(pb, pos); } @@ -2108,9 +2242,9 @@ static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov, static int utf8len(const uint8_t *b) { - int len=0; + int len = 0; int val; - while(*b){ + while (*b) { GET_UTF8(val, *b++, return -1;) len++; } @@ -2120,7 +2254,7 @@ static int utf8len(const uint8_t *b) static int ascii_to_wc(AVIOContext *pb, const uint8_t *b) { int val; - while(*b){ + while (*b) { GET_UTF8(val, *b++, return -1;) avio_wb16(pb, val); } @@ -2130,7 +2264,9 @@ static int ascii_to_wc(AVIOContext *pb, const uint8_t *b) static uint16_t language_code(const char *str) { - return (((str[0]-0x60) & 0x1F) << 10) + (((str[1]-0x60) & 0x1F) << 5) + ((str[2]-0x60) & 0x1F); + return (((str[0] - 0x60) & 0x1F) << 10) + + (((str[1] - 0x60) & 0x1F) << 5) + + (( str[2] - 0x60) & 0x1F); } static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, @@ -2147,7 +2283,7 @@ static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, avio_wb16(pb, atoi(t->value)); else { avio_wb16(pb, language_code("eng")); /* language */ - avio_write(pb, t->value, strlen(t->value)+1); /* UTF8 string value */ + avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */ if (!strcmp(tag, "albm") && (t = av_dict_get(s->metadata, "track", NULL, 0))) avio_w8(pb, atoi(t->value)); @@ -2194,7 +2330,7 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, } ret = avio_open_dyn_buf(&pb_buf); - if(ret < 0) + if (ret < 0) return ret; if (mov->mode & MODE_3GP) { @@ -2207,18 +2343,18 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright"); mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date"); } else if (mov->mode == MODE_MOV) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4 - mov_write_string_metadata(s, pb_buf, "\251ART", "artist" , 0); - mov_write_string_metadata(s, pb_buf, "\251nam", "title" , 0); - mov_write_string_metadata(s, pb_buf, "\251aut", "author" , 0); - mov_write_string_metadata(s, pb_buf, "\251alb", "album" , 0); - mov_write_string_metadata(s, pb_buf, "\251day", "date" , 0); - mov_write_string_metadata(s, pb_buf, "\251swr", "encoder" , 0); + mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0); + mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0); + mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0); + mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0); + mov_write_string_metadata(s, pb_buf, "\251day", "date", 0); + mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0); // currently ignored by mov.c - mov_write_string_metadata(s, pb_buf, "\251des", "comment" , 0); + mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0); // add support for libquicktime, this atom is also actually read by mov.c - mov_write_string_metadata(s, pb_buf, "\251cmt", "comment" , 0); - mov_write_string_metadata(s, pb_buf, "\251gen", "genre" , 0); - mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright" , 0); + mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0); + mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0); + mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0); } else { /* iTunes meta data */ mov_write_meta_tag(pb_buf, mov, s); @@ -2228,7 +2364,7 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_chpl_tag(pb_buf, s); if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) { - avio_wb32(pb, size+8); + avio_wb32(pb, size + 8); ffio_wfourcc(pb, "udta"); avio_write(pb, buf, size); } @@ -2238,12 +2374,12 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, } static void mov_write_psp_udta_tag(AVIOContext *pb, - const char *str, const char *lang, int type) + const char *str, const char *lang, int type) { - int len = utf8len(str)+1; - if(len<=0) + int len = utf8len(str) + 1; + if (len <= 0) return; - avio_wb16(pb, len*2+10); /* size */ + avio_wb16(pb, len * 2 + 10); /* size */ avio_wb32(pb, type); /* type */ avio_wb16(pb, language_code(lang)); /* language */ avio_wb16(pb, 0x01); /* ? */ @@ -2290,18 +2426,18 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) static void build_chunks(MOVTrack *trk) { int i; - MOVIentry *chunk= &trk->cluster[0]; + MOVIentry *chunk = &trk->cluster[0]; uint64_t chunkSize = chunk->size; - chunk->chunkNum= 1; + chunk->chunkNum = 1; if (trk->chunkCount) return; - trk->chunkCount= 1; - for(i=1; i<trk->entry; i++){ - if(chunk->pos + chunkSize == trk->cluster[i].pos && + trk->chunkCount = 1; + for (i = 1; i<trk->entry; i++){ + if (chunk->pos + chunkSize == trk->cluster[i].pos && chunkSize + trk->cluster[i].size < (1<<20)){ chunkSize += trk->cluster[i].size; chunk->samples_in_chunk += trk->cluster[i].entries; - }else{ + } else { trk->cluster[i].chunkNum = chunk->chunkNum+1; chunk=&trk->cluster[i]; chunkSize = chunk->size; @@ -2315,25 +2451,24 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, { int i; int64_t pos = avio_tell(pb); - int not_first[AVMEDIA_TYPE_NB]={0}; avio_wb32(pb, 0); /* size placeholder*/ ffio_wfourcc(pb, "moov"); - for (i=0; i<mov->nb_streams; i++) { + for (i = 0; i < mov->nb_streams; i++) { if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) continue; - mov->tracks[i].time = mov->time; - mov->tracks[i].track_id = i+1; + mov->tracks[i].time = mov->time; + mov->tracks[i].track_id = i + 1; if (mov->tracks[i].entry) build_chunks(&mov->tracks[i]); } if (mov->chapter_track) - for (i=0; i<s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; i++) { mov->tracks[i].tref_tag = MKTAG('c','h','a','p'); - mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id; + mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id; } for (i = 0; i < mov->nb_streams; i++) { if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) { @@ -2354,15 +2489,8 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_mvhd_tag(pb, mov); if (mov->mode != MODE_MOV && !mov->iods_skip) mov_write_iods_tag(pb, mov); - for (i=0; i<mov->nb_streams; i++) { + for (i = 0; i < mov->nb_streams; i++) { if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT) { - if(i < s->nb_streams){ - int codec_type= s->streams[i]->codec->codec_type; - if(codec_type==AVMEDIA_TYPE_AUDIO || codec_type==AVMEDIA_TYPE_SUBTITLE){ - mov->tracks[i].secondary= not_first[codec_type]; - not_first[codec_type]= 1; - } - } mov_write_trak_tag(pb, mov, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL); } } @@ -2390,9 +2518,9 @@ static void param_write_string(AVIOContext *pb, const char *name, const char *va static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len) { char buf[150]; - len = FFMIN(sizeof(buf)/2 - 1, len); + len = FFMIN(sizeof(buf) / 2 - 1, len); ff_data_to_hex(buf, value, len, 0); - buf[2*len] = '\0'; + buf[2 * len] = '\0'; avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf); } @@ -2400,7 +2528,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov) { int64_t pos = avio_tell(pb); int i; - const uint8_t uuid[] = { + static const uint8_t uuid[] = { 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd, 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 }; @@ -2466,7 +2594,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov) param_write_hex(pb, "CodecPrivateData", track->enc->extradata, track->enc->extradata_size); param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags, - track->enc->codec_id)); + track->enc->codec_id)); param_write_int(pb, "Channels", track->enc->channels); param_write_int(pb, "SamplingRate", track->enc->sample_rate); param_write_int(pb, "BitsPerSample", 16); @@ -2491,8 +2619,8 @@ static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov) return 0; } -static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track, - int64_t moof_offset) +static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov, + MOVTrack *track, int64_t moof_offset) { int64_t pos = avio_tell(pb); uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION | @@ -2502,12 +2630,16 @@ static int mov_write_tfhd_tag(AVIOContext *pb, MOVTrack *track, } else { flags |= MOV_TFHD_DEFAULT_FLAGS; } + if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET) + flags &= ~MOV_TFHD_BASE_DATA_OFFSET; /* Don't set a default sample size, the silverlight player refuses * to play files with that set. Don't set a default sample duration, - * WMP freaks out if it is set. */ + * WMP freaks out if it is set. Don't set a base data offset, PIFF + * file format says it MUST NOT be set. */ if (track->mode == MODE_ISM) - flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION); + flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION | + MOV_TFHD_BASE_DATA_OFFSET); avio_wb32(pb, 0); /* size placeholder */ ffio_wfourcc(pb, "tfhd"); @@ -2544,7 +2676,8 @@ static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry) (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC); } -static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track) +static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov, + MOVTrack *track, int moof_size) { int64_t pos = avio_tell(pb); uint32_t flags = MOV_TRUN_DATA_OFFSET; @@ -2569,8 +2702,13 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track) avio_wb24(pb, flags); avio_wb32(pb, track->entry); /* sample count */ - track->moof_size_offset = avio_tell(pb); - avio_wb32(pb, 0); /* data offset */ + if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET && + !(mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) && + track->track_id != 1) + avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */ + else + avio_wb32(pb, moof_size + 8 + track->data_offset + + track->cluster[0].pos); /* data offset */ if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) avio_wb32(pb, get_sample_flags(track, &track->cluster[0])); @@ -2591,7 +2729,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVTrack *track) static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); - const uint8_t uuid[] = { + static const uint8_t uuid[] = { 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6, 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2 }; @@ -2613,7 +2751,7 @@ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov, { int n = track->nb_frag_info - 1 - entry, i; int size = 8 + 16 + 4 + 1 + 16*n; - const uint8_t uuid[] = { + static const uint8_t uuid[] = { 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95, 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f }; @@ -2634,11 +2772,10 @@ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov, avio_wb64(pb, track->frag_info[index].duration); } if (n < mov->ism_lookahead) { - int free_size = 16*(mov->ism_lookahead - n); + int free_size = 16 * (mov->ism_lookahead - n); avio_wb32(pb, free_size); ffio_wfourcc(pb, "free"); - for (i = 0; i < free_size - 8; i++) - avio_w8(pb, 0); + ffio_fill(pb, 0, free_size - 8); } return 0; @@ -2659,19 +2796,20 @@ static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov, } static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov, - MOVTrack *track, int64_t moof_offset) + MOVTrack *track, int64_t moof_offset, + int moof_size) { int64_t pos = avio_tell(pb); avio_wb32(pb, 0); /* size placeholder */ ffio_wfourcc(pb, "traf"); - mov_write_tfhd_tag(pb, track, moof_offset); - mov_write_trun_tag(pb, track); + mov_write_tfhd_tag(pb, mov, track, moof_offset); + mov_write_trun_tag(pb, mov, track, moof_size); if (mov->mode == MODE_ISM) { mov_write_tfxd_tag(pb, track); if (mov->ism_lookahead) { - int i, size = 16 + 4 + 1 + 16*mov->ism_lookahead; + int i, size = 16 + 4 + 1 + 16 * mov->ism_lookahead; track->tfrf_offset = avio_tell(pb); avio_wb32(pb, 8 + size); @@ -2684,10 +2822,11 @@ static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov, return update_size(pb, pos); } -static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks) +static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov, + int tracks, int moof_size) { - int64_t pos = avio_tell(pb), end; - int i, moof_size; + int64_t pos = avio_tell(pb); + int i; avio_wb32(pb, 0); /* size placeholder */ ffio_wfourcc(pb, "moof"); @@ -2699,25 +2838,24 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks) continue; if (!track->entry) continue; - mov_write_traf_tag(pb, mov, track, pos); + mov_write_traf_tag(pb, mov, track, pos, moof_size); } - end = avio_tell(pb); - moof_size = end - pos; - for (i = 0; i < mov->nb_streams; i++) { - MOVTrack *track = &mov->tracks[i]; - if (tracks >= 0 && i != tracks) - continue; - if (!track->entry) - continue; - avio_seek(pb, mov->tracks[i].moof_size_offset, SEEK_SET); - avio_wb32(pb, moof_size + 8 + mov->tracks[i].data_offset); - } - avio_seek(pb, end, SEEK_SET); - return update_size(pb, pos); } +static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks) +{ + AVIOContext *avio_buf; + int ret, moof_size; + + if ((ret = ffio_open_null_buf(&avio_buf)) < 0) + return ret; + mov_write_moof_tag_internal(avio_buf, mov, tracks, 0); + moof_size = ffio_close_null_buf(avio_buf); + return mov_write_moof_tag_internal(pb, mov, tracks, moof_size); +} + static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); @@ -2805,7 +2943,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) } else if (mov->mode & MODE_3G2) { ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a"); minor = has_h264 ? 0x20000 : 0x10000; - }else if (mov->mode == MODE_PSP) + } else if (mov->mode == MODE_PSP) ffio_wfourcc(pb, "MSNV"); else if (mov->mode == MODE_MP4) ffio_wfourcc(pb, "isom"); @@ -2820,7 +2958,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) avio_wb32(pb, minor); - if(mov->mode == MODE_MOV) + if (mov->mode == MODE_MOV) ffio_wfourcc(pb, "qt "); else if (mov->mode == MODE_ISM) { ffio_wfourcc(pb, "piff"); @@ -2828,7 +2966,7 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) } else { ffio_wfourcc(pb, "isom"); ffio_wfourcc(pb, "iso2"); - if(has_h264) + if (has_h264) ffio_wfourcc(pb, "avc1"); } @@ -2848,7 +2986,7 @@ static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s) AVCodecContext *video_codec = s->streams[0]->codec; AVCodecContext *audio_codec = s->streams[1]->codec; int audio_rate = audio_codec->sample_rate; - int frame_rate = ((video_codec->time_base.den) * (0x10000))/ (video_codec->time_base.num); + int frame_rate = ((video_codec->time_base.den) * (0x10000)) / (video_codec->time_base.num); int audio_kbitrate = audio_codec->bit_rate / 1000; int video_kbitrate = FFMIN(video_codec->bit_rate / 1000, 800 - audio_kbitrate); @@ -2870,7 +3008,7 @@ static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s) avio_wb32(pb, 0x0); /* ? */ avio_wb32(pb, 0x2c); /* size */ - ffio_wfourcc(pb, "APRF");/* audio */ + ffio_wfourcc(pb, "APRF"); /* audio */ avio_wb32(pb, 0x0); avio_wb32(pb, 0x2); /* TrackID */ ffio_wfourcc(pb, "mp4a"); @@ -2910,11 +3048,11 @@ static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags) int i, closed_gop = 0; for (i = 0; i < pkt->size - 4; i++) { - c = (c<<8) + pkt->data[i]; + c = (c << 8) + pkt->data[i]; if (c == 0x1b8) { // gop - closed_gop = pkt->data[i+4]>>6 & 0x01; + closed_gop = pkt->data[i + 4] >> 6 & 0x01; } else if (c == 0x100) { // pic - int temp_ref = (pkt->data[i+1]<<2) | (pkt->data[i+2]>>6); + int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6); if (!temp_ref || closed_gop) // I picture is not reordered *flags = MOV_SYNC_SAMPLE; else @@ -2982,21 +3120,6 @@ static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk, int fragment) } } -static int get_moov_size(AVFormatContext *s) -{ - int ret; - uint8_t *buf; - AVIOContext *moov_buf; - MOVMuxContext *mov = s->priv_data; - - if ((ret = avio_open_dyn_buf(&moov_buf)) < 0) - return ret; - mov_write_moov_tag(moov_buf, mov, s); - ret = avio_close_dyn_buf(moov_buf, &buf); - av_free(buf); - return ret; -} - static int mov_flush_fragment(AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; @@ -3082,9 +3205,14 @@ static int mov_flush_fragment(AVFormatContext *s) MOVFragmentInfo *info; avio_flush(s->pb); track->nb_frag_info++; - track->frag_info = av_realloc(track->frag_info, - sizeof(*track->frag_info) * - track->nb_frag_info); + if (track->nb_frag_info >= track->frag_info_capacity) { + unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT; + if (av_reallocp_array(&track->frag_info, + new_capacity, + sizeof(*track->frag_info))) + return AVERROR(ENOMEM); + track->frag_info_capacity = new_capacity; + } info = &track->frag_info[track->nb_frag_info - 1]; info->offset = avio_tell(s->pb); info->time = mov->tracks[i].frag_start; @@ -3124,7 +3252,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) MOVTrack *trk = &mov->tracks[pkt->stream_index]; AVCodecContext *enc = trk->enc; unsigned int samples_in_chunk = 0; - int size= pkt->size; + int size = pkt->size; uint8_t *reformatted_data = NULL; if (mov->flags & FF_MOV_FLAG_FRAGMENT) { @@ -3168,11 +3296,21 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) /* copy extradata if it exists */ if (trk->vos_len == 0 && enc->extradata_size > 0) { - trk->vos_len = enc->extradata_size; + trk->vos_len = enc->extradata_size; trk->vos_data = av_malloc(trk->vos_len); memcpy(trk->vos_data, enc->extradata, trk->vos_len); } + if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && + (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { + if (!s->streams[pkt->stream_index]->nb_frames) { + av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: " + "use audio bitstream filter 'aac_adtstoasc' to fix it " + "('-bsf:a aac_adtstoasc' option with ffmpeg)\n"); + return -1; + } + av_log(s, AV_LOG_WARNING, "aac bitstream error\n"); + } if (enc->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1) { /* from x264 or from bytestream h264 */ /* nal reformating needed */ @@ -3183,10 +3321,6 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } else { size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size); } - } else if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 && - (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) { - av_log(s, AV_LOG_ERROR, "malformated aac bitstream, use -absf aac_adtstoasc\n"); - return -1; } else { avio_write(pb, pkt->data, size); } @@ -3194,25 +3328,27 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) if ((enc->codec_id == AV_CODEC_ID_DNXHD || enc->codec_id == AV_CODEC_ID_AC3) && !trk->vos_len) { /* copy frame to create needed atoms */ - trk->vos_len = size; + trk->vos_len = size; trk->vos_data = av_malloc(size); if (!trk->vos_data) return AVERROR(ENOMEM); memcpy(trk->vos_data, pkt->data, size); } - if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) { - trk->cluster = av_realloc_f(trk->cluster, sizeof(*trk->cluster), (trk->entry + MOV_INDEX_CLUSTER_SIZE)); - if (!trk->cluster) - return -1; + if (trk->entry >= trk->cluster_capacity) { + unsigned new_capacity = 2 * (trk->entry + MOV_INDEX_CLUSTER_SIZE); + if (av_reallocp_array(&trk->cluster, new_capacity, + sizeof(*trk->cluster))) + return AVERROR(ENOMEM); + trk->cluster_capacity = new_capacity; } - trk->cluster[trk->entry].pos = avio_tell(pb) - size; + trk->cluster[trk->entry].pos = avio_tell(pb) - size; trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk; - trk->cluster[trk->entry].chunkNum = 0; - trk->cluster[trk->entry].size = size; - trk->cluster[trk->entry].entries = samples_in_chunk; - trk->cluster[trk->entry].dts = pkt->dts; + trk->cluster[trk->entry].chunkNum = 0; + trk->cluster[trk->entry].size = size; + trk->cluster[trk->entry].entries = samples_in_chunk; + trk->cluster[trk->entry].dts = pkt->dts; if (!trk->entry && trk->start_dts != AV_NOPTS_VALUE) { /* First packet of a new fragment. We already wrote the duration * of the last packet of the previous fragment based on track_duration, @@ -3234,7 +3370,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } if (pkt->dts != pkt->pts) trk->flags |= MOV_TRACK_CTTS; - trk->cluster[trk->entry].cts = pkt->pts - pkt->dts; + trk->cluster[trk->entry].cts = pkt->pts - pkt->dts; trk->cluster[trk->entry].flags = 0; if (enc->codec_id == AV_CODEC_ID_VC1) { mov_parse_vc1_frame(pkt, trk, mov->fragments); @@ -3252,9 +3388,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } trk->entry++; trk->sample_count += samples_in_chunk; - mov->mdat_size += size; - - avio_flush(pb); + mov->mdat_size += size; if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry, @@ -3271,7 +3405,8 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) int64_t frag_duration = 0; int size = pkt->size; - if (!pkt->size) return 0; /* Discard 0 sized packets */ + if (!pkt->size) + return 0; /* Discard 0 sized packets */ if (trk->entry && pkt->stream_index < s->nb_streams) frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts, @@ -3360,7 +3495,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) // QuickTime chapters involve an additional text track with the chapter names // as samples, and a tref pointing from the other tracks to the chapter one. -static void mov_create_chapter_track(AVFormatContext *s, int tracknum) +static int mov_create_chapter_track(AVFormatContext *s, int tracknum) { AVIOContext *pb; @@ -3373,8 +3508,16 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum) track->tag = MKTAG('t','e','x','t'); track->timescale = MOV_TIMESCALE; track->enc = avcodec_alloc_context3(NULL); + if (!track->enc) + return AVERROR(ENOMEM); track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE; - +#if 0 + // These properties are required to make QT recognize the chapter track + uint8_t chapter_properties[43] = { 0, 0, 0, 0, 0, 0, 0, 1, }; + if (ff_alloc_extradata(track->enc, sizeof(chapter_properties))) + return AVERROR(ENOMEM); + memcpy(track->enc->extradata, chapter_properties, sizeof(chapter_properties)); +#else if (avio_open_dyn_buf(&pb) >= 0) { int size; uint8_t *buf; @@ -3418,6 +3561,7 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum) av_free(&buf); } } +#endif for (i = 0; i < s->nb_chapters; i++) { AVChapter *c = s->chapters[i]; @@ -3428,15 +3572,19 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum) pkt.duration = end - pkt.dts; if ((t = av_dict_get(c->metadata, "title", NULL, 0))) { - len = strlen(t->value); - pkt.size = len+2; + len = strlen(t->value); + pkt.size = len + 2; pkt.data = av_malloc(pkt.size); + if (!pkt.data) + return AVERROR(ENOMEM); AV_WB16(pkt.data, len); - memcpy(pkt.data+2, t->value, len); + memcpy(pkt.data + 2, t->value, len); ff_mov_write_packet(s, &pkt); av_freep(&pkt.data); } } + + return 0; } static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, const char *tcstr) @@ -3447,14 +3595,7 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde AVStream *src_st = s->streams[src_index]; AVTimecode tc; AVPacket pkt = {.stream_index = index, .flags = AV_PKT_FLAG_KEY, .size = 4}; - AVRational rate = {src_st->codec->time_base.den, src_st->codec->time_base.num}; - - /* if the codec time base makes no sense, try to fallback on stream frame rate */ - if (av_timecode_check_frame_rate(rate) < 0) { - av_log(s, AV_LOG_DEBUG, "timecode: tbc=%d/%d invalid, fallback on %d/%d\n", - rate.num, rate.den, src_st->avg_frame_rate.num, src_st->avg_frame_rate.den); - rate = src_st->avg_frame_rate; - } + AVRational rate = find_fps(s, src_st); /* compute the frame number */ ret = av_timecode_init_from_string(&tc, rate, tcstr, s); @@ -3473,7 +3614,7 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde track->enc = avcodec_alloc_context3(NULL); track->enc->codec_type = AVMEDIA_TYPE_DATA; track->enc->codec_tag = track->tag; - track->enc->time_base = src_st->codec->time_base; + track->enc->time_base = av_inv_q(rate); /* the tmcd track just contains one packet with the frame number */ pkt.data = av_malloc(pkt.size); @@ -3483,12 +3624,101 @@ static int mov_create_timecode_track(AVFormatContext *s, int index, int src_inde return ret; } +/* + * st->disposition controls the "enabled" flag in the tkhd tag. + * QuickTime will not play a track if it is not enabled. So make sure + * that one track of each type (audio, video, subtitle) is enabled. + * + * Subtitles are special. For audio and video, setting "enabled" also + * makes the track "default" (i.e. it is rendered when played). For + * subtitles, an "enabled" subtitle is not rendered by default, but + * if no subtitle is enabled, the subtitle menu in QuickTime will be + * empty! + */ +static void enable_tracks(AVFormatContext *s) +{ + MOVMuxContext *mov = s->priv_data; + int i; + uint8_t enabled[AVMEDIA_TYPE_NB]; + int first[AVMEDIA_TYPE_NB]; + + for (i = 0; i < AVMEDIA_TYPE_NB; i++) { + enabled[i] = 0; + first[i] = -1; + } + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + + if (st->codec->codec_type <= AVMEDIA_TYPE_UNKNOWN || + st->codec->codec_type >= AVMEDIA_TYPE_NB) + continue; + + if (first[st->codec->codec_type] < 0) + first[st->codec->codec_type] = i; + if (st->disposition & AV_DISPOSITION_DEFAULT) { + mov->tracks[i].flags |= MOV_TRACK_ENABLED; + enabled[st->codec->codec_type] = 1; + } + } + + for (i = 0; i < AVMEDIA_TYPE_NB; i++) { + switch (i) { + case AVMEDIA_TYPE_VIDEO: + case AVMEDIA_TYPE_AUDIO: + case AVMEDIA_TYPE_SUBTITLE: + if (!enabled[i] && first[i] >= 0) + mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED; + break; + } + } +} + +static void mov_free(AVFormatContext *s) +{ + MOVMuxContext *mov = s->priv_data; + int i; + + if (mov->chapter_track) { + if (mov->tracks[mov->chapter_track].enc) + av_freep(&mov->tracks[mov->chapter_track].enc->extradata); + av_freep(&mov->tracks[mov->chapter_track].enc); + } + + for (i = 0; i < mov->nb_streams; i++) { + if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) + ff_mov_close_hinting(&mov->tracks[i]); + else if (mov->tracks[i].tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) + av_freep(&mov->tracks[i].enc); + av_freep(&mov->tracks[i].cluster); + av_freep(&mov->tracks[i].frag_info); + + if (mov->tracks[i].vos_len) + av_freep(&mov->tracks[i].vos_data); + } + + av_freep(&mov->tracks); +} + static int mov_write_header(AVFormatContext *s) { AVIOContext *pb = s->pb; MOVMuxContext *mov = s->priv_data; AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata, "timecode", NULL, 0); - int i, hint_track = 0, tmcd_track = 0; + int i, ret, hint_track = 0, tmcd_track = 0; + + /* Default mode == MP4 */ + mov->mode = MODE_MP4; + + if (s->oformat != NULL) { + if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP; + else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2; + else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV; + else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; + else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD; + else if (!strcmp("ismv",s->oformat->name)) mov->mode = MODE_ISM; + else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V; + } /* Set the FRAGMENT flag if any of the fragmentation methods are * enabled. */ @@ -3498,11 +3728,19 @@ static int mov_write_header(AVFormatContext *s) FF_MOV_FLAG_FRAG_CUSTOM)) mov->flags |= FF_MOV_FLAG_FRAGMENT; + /* Set other implicit flags immediately */ + if (mov->mode == MODE_ISM) + mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF | + FF_MOV_FLAG_FRAGMENT; + /* faststart: moov at the beginning of the file, if supported */ if (mov->flags & FF_MOV_FLAG_FASTSTART) { - if (mov->flags & FF_MOV_FLAG_FRAGMENT) + if ((mov->flags & FF_MOV_FLAG_FRAGMENT) || + (s->flags & AVFMT_FLAG_CUSTOM_IO)) { + av_log(s, AV_LOG_WARNING, "The faststart flag is incompatible " + "with fragmentation and custom IO, disabling faststart\n"); mov->flags &= ~FF_MOV_FLAG_FASTSTART; - else + } else mov->reserved_moov_size = -1; } @@ -3513,37 +3751,33 @@ static int mov_write_header(AVFormatContext *s) /* Non-seekable output is ok if using fragmentation. If ism_lookahead * is enabled, we don't support non-seekable output at all. */ if (!s->pb->seekable && - ((!(mov->flags & FF_MOV_FLAG_FRAGMENT) && - !(s->oformat && !strcmp(s->oformat->name, "ismv"))) - || mov->ism_lookahead)) { + (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead)) { av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); - return -1; + return AVERROR(EINVAL); } - /* Default mode == MP4 */ - mov->mode = MODE_MP4; - - if (s->oformat != NULL) { - if (!strcmp("3gp", s->oformat->name)) mov->mode = MODE_3GP; - else if (!strcmp("3g2", s->oformat->name)) mov->mode = MODE_3GP|MODE_3G2; - else if (!strcmp("mov", s->oformat->name)) mov->mode = MODE_MOV; - else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; - else if (!strcmp("ipod",s->oformat->name)) mov->mode = MODE_IPOD; - else if (!strcmp("ismv",s->oformat->name)) mov->mode = MODE_ISM; - else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V; - - mov_write_ftyp_tag(pb,s); - if (mov->mode == MODE_PSP) { - if (s->nb_streams != 2) { - av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n"); - return -1; + mov_write_ftyp_tag(pb,s); + if (mov->mode == MODE_PSP) { + int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + video_streams_nb++; + else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) + audio_streams_nb++; + else + other_streams_nb++; } - mov_write_uuidprof_tag(pb,s); + + if (video_streams_nb != 1 || audio_streams_nb != 1 || other_streams_nb) { + av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n"); + return AVERROR(EINVAL); } + mov_write_uuidprof_tag(pb, s); } mov->nb_streams = s->nb_streams; - if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters) + if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) mov->chapter_track = mov->nb_streams++; if (mov->flags & FF_MOV_FLAG_RTP_HINT) { @@ -3584,75 +3818,93 @@ static int mov_write_header(AVFormatContext *s) mov->nb_streams += mov->nb_meta_tmcd; } - mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks)); + // Reserve an extra stream for chapters for the case where chapters + // are written in the trailer + mov->tracks = av_mallocz((mov->nb_streams + 1) * sizeof(*mov->tracks)); if (!mov->tracks) return AVERROR(ENOMEM); - for(i=0; i<s->nb_streams; i++){ + for (i = 0; i < s->nb_streams; i++) { AVStream *st= s->streams[i]; MOVTrack *track= &mov->tracks[i]; AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0); track->enc = st->codec; + track->st = st; track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV); if (track->language < 0) track->language = 0; track->mode = mov->mode; - track->tag = mov_find_codec_tag(s, track); + track->tag = mov_find_codec_tag(s, track); if (!track->tag) { - av_log(s, AV_LOG_ERROR, "track %d: could not find tag, " - "codec not currently supported in container\n", i); + av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, " + "codec not currently supported in container\n", + avcodec_get_name(st->codec->codec_id), i); + ret = AVERROR(EINVAL); goto error; } /* If hinting of this track is enabled by a later hint track, * this is updated. */ track->hint_track = -1; - track->start_dts = AV_NOPTS_VALUE; - if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ + track->start_dts = AV_NOPTS_VALUE; + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') || track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') || track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) { if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) { av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n"); + ret = AVERROR(EINVAL); goto error; } - track->height = track->tag>>24 == 'n' ? 486 : 576; + track->height = track->tag >> 24 == 'n' ? 486 : 576; + } + if (mov->video_track_timescale) { + track->timescale = mov->video_track_timescale; + } else { + track->timescale = st->codec->time_base.den; + while(track->timescale < 10000) + track->timescale *= 2; } - track->timescale = st->codec->time_base.den; - while(track->timescale < 10000) - track->timescale *= 2; if (track->mode == MODE_MOV && track->timescale > 100000) av_log(s, AV_LOG_WARNING, "WARNING codec timebase is very high. If duration is too long,\n" "file may not be playable by quicktime. Specify a shorter timebase\n" "or choose different container.\n"); - }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO){ + } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { track->timescale = st->codec->sample_rate; - if(!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) { + if (!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) { av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i); track->audio_vbr = 1; - }else if(st->codec->codec_id == AV_CODEC_ID_ADPCM_MS || + }else if (st->codec->codec_id == AV_CODEC_ID_ADPCM_MS || st->codec->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV || st->codec->codec_id == AV_CODEC_ID_ILBC){ if (!st->codec->block_align) { av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i); + ret = AVERROR(EINVAL); goto error; } track->sample_size = st->codec->block_align; - }else if(st->codec->frame_size > 1){ /* assume compressed audio */ + }else if (st->codec->frame_size > 1){ /* assume compressed audio */ track->audio_vbr = 1; }else{ track->sample_size = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels; } + if (st->codec->codec_id == AV_CODEC_ID_ILBC || + st->codec->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) { + track->audio_vbr = 1; + } if (track->mode != MODE_MOV && track->enc->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) { av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n", i, track->enc->sample_rate); + ret = AVERROR(EINVAL); goto error; } - }else if(st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE){ + } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + track->timescale = st->codec->time_base.den; + } else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) { track->timescale = st->codec->time_base.den; - }else{ + } else { track->timescale = MOV_TIMESCALE; } if (!track->height) @@ -3672,24 +3924,27 @@ static int mov_write_header(AVFormatContext *s) } } + enable_tracks(s); + if (mov->mode == MODE_ISM) { /* If no fragmentation options have been set, set a default. */ if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME | FF_MOV_FLAG_FRAG_CUSTOM)) && !mov->max_fragment_duration && !mov->max_fragment_size) - mov->max_fragment_duration = 5000000; - mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF | - FF_MOV_FLAG_FRAGMENT; + mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME; } - if(mov->reserved_moov_size){ + if (mov->reserved_moov_size){ mov->reserved_moov_pos= avio_tell(pb); if (mov->reserved_moov_size > 0) avio_skip(pb, mov->reserved_moov_size); } - if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) + if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + if (mov->flags & FF_MOV_FLAG_FASTSTART) + mov->reserved_moov_pos = avio_tell(pb); mov_write_mdat_tag(pb, mov); + } if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) mov->time = ff_iso8601_to_unix_time(t->value); @@ -3697,7 +3952,8 @@ static int mov_write_header(AVFormatContext *s) mov->time += 0x7C25B080; // 1970 based -> 1904 based if (mov->chapter_track) - mov_create_chapter_track(s, mov->chapter_track); + if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0) + goto error; if (mov->flags & FF_MOV_FLAG_RTP_HINT) { /* Initialize the hint tracks for each audio and video stream */ @@ -3705,7 +3961,8 @@ static int mov_write_header(AVFormatContext *s) AVStream *st = s->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - ff_mov_init_hinting(s, hint_track, i); + if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0) + goto error; hint_track++; } } @@ -3722,7 +3979,7 @@ static int mov_write_header(AVFormatContext *s) t = av_dict_get(st->metadata, "timecode", NULL, 0); if (!t) continue; - if (mov_create_timecode_track(s, tmcd_track, i, t->value) < 0) + if ((ret = mov_create_timecode_track(s, tmcd_track, i, t->value)) < 0) goto error; tmcd_track++; } @@ -3741,15 +3998,27 @@ static int mov_write_header(AVFormatContext *s) return 0; error: - av_freep(&mov->tracks); - return -1; + mov_free(s); + return ret; } -/** +static int get_moov_size(AVFormatContext *s) +{ + int ret; + AVIOContext *moov_buf; + MOVMuxContext *mov = s->priv_data; + + if ((ret = ffio_open_null_buf(&moov_buf)) < 0) + return ret; + mov_write_moov_tag(moov_buf, mov, s); + return ffio_close_null_buf(moov_buf); +} + +/* * This function gets the moov size if moved to the top of the file: the chunk * offset table can switch between stco (32-bit entries) to co64 (64-bit - * entries) when the moov is moved to the top, so the size of the moov would - * change. It also updates the chunk offset tables. + * entries) when the moov is moved to the beginning, so the size of the moov + * would change. It also updates the chunk offset tables. */ static int compute_moov_size(AVFormatContext *s) { @@ -3767,7 +4036,7 @@ static int compute_moov_size(AVFormatContext *s) if (moov_size2 < 0) return moov_size2; - /* if the size changed, we just switched from stco to co64 and needs to + /* if the size changed, we just switched from stco to co64 and need to * update the offsets */ if (moov_size2 != moov_size) for (i = 0; i < mov->nb_streams; i++) @@ -3843,9 +4112,9 @@ static int mov_write_trailer(AVFormatContext *s) { MOVMuxContext *mov = s->priv_data; AVIOContext *pb = s->pb; - int64_t moov_pos; int res = 0; int i; + int64_t moov_pos; /* * Before actually writing the trailer, make sure that there are no @@ -3860,9 +4129,20 @@ static int mov_write_trailer(AVFormatContext *s) } } - moov_pos = avio_tell(pb); + // If there were no chapters when the header was written, but there + // are chapters now, write them in the trailer. This only works + // when we are not doing fragments. + if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) { + mov->chapter_track = mov->nb_streams++; + if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0) + goto error; + } + } if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + moov_pos = avio_tell(pb); + /* Write size of mdat tag */ if (mov->mdat_size + 8 <= UINT32_MAX) { avio_seek(pb, mov->mdat_pos, SEEK_SET); @@ -3878,8 +4158,8 @@ static int mov_write_trailer(AVFormatContext *s) } avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_moov_pos : moov_pos, SEEK_SET); - if (mov->reserved_moov_size == -1) { - av_log(s, AV_LOG_INFO, "Starting second pass: moving header on top of the file\n"); + if (mov->flags & FF_MOV_FLAG_FASTSTART) { + av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n"); res = shift_data(s); if (res == 0) { avio_seek(s->pb, mov->reserved_moov_pos, SEEK_SET); @@ -3889,13 +4169,13 @@ static int mov_write_trailer(AVFormatContext *s) int64_t size; mov_write_moov_tag(pb, mov, s); size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos); - if(size < 8){ + if (size < 8){ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size); return -1; } avio_wb32(pb, size); ffio_wfourcc(pb, "free"); - for(i=0; i<size; i++) + for (i = 0; i < size; i++) avio_w8(pb, 0); avio_seek(pb, moov_pos, SEEK_SET); } else { @@ -3906,14 +4186,7 @@ static int mov_write_trailer(AVFormatContext *s) mov_write_mfra_tag(pb, mov); } - if (mov->chapter_track) - av_freep(&mov->tracks[mov->chapter_track].enc); - - for (i=0; i<mov->nb_streams; i++) { - if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) - ff_mov_close_hinting(&mov->tracks[i]); - else if (mov->tracks[i].tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) - av_freep(&mov->tracks[i].enc); + for (i = 0; i < mov->nb_streams; i++) { if (mov->flags & FF_MOV_FLAG_FRAGMENT && mov->tracks[i].vc1_info.struct_offset && s->pb->seekable) { int64_t off = avio_tell(pb); @@ -3924,15 +4197,10 @@ static int mov_write_trailer(AVFormatContext *s) avio_seek(pb, off, SEEK_SET); } } - av_freep(&mov->tracks[i].cluster); - av_freep(&mov->tracks[i].frag_info); - - if (mov->tracks[i].vos_len) - av_free(mov->tracks[i].vos_data); - } - av_freep(&mov->tracks); +error: + mov_free(s); return res; } @@ -3950,7 +4218,7 @@ AVOutputFormat ff_mov_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ ff_codec_movvideo_tags, ff_codec_movaudio_tags, 0 }, @@ -3969,7 +4237,7 @@ AVOutputFormat ff_tgp_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 }, .priv_class = &tgp_muxer_class, }; @@ -3988,7 +4256,7 @@ AVOutputFormat ff_mp4_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 }, .priv_class = &mp4_muxer_class, }; @@ -4006,7 +4274,7 @@ AVOutputFormat ff_psp_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 }, .priv_class = &psp_muxer_class, }; @@ -4023,7 +4291,7 @@ AVOutputFormat ff_tg2_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ codec_3gp_tags, 0 }, .priv_class = &tg2_muxer_class, }; @@ -4041,7 +4309,7 @@ AVOutputFormat ff_ipod_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 }, .priv_class = &ipod_muxer_class, }; @@ -4059,7 +4327,7 @@ AVOutputFormat ff_ismv_muxer = { .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 }, .priv_class = &ismv_muxer_class, }; diff --git a/ffmpeg/libavformat/movenc.h b/ffmpeg/libavformat/movenc.h index a5db895..09f3ea7 100644 --- a/ffmpeg/libavformat/movenc.h +++ b/ffmpeg/libavformat/movenc.h @@ -26,7 +26,8 @@ #include "avformat.h" -#define MOV_INDEX_CLUSTER_SIZE 16384 +#define MOV_FRAG_INFO_ALLOC_INCREMENT 64 +#define MOV_INDEX_CLUSTER_SIZE 1024 #define MOV_TIMESCALE 1000 #define RTP_MAX_PACKET_SIZE 1450 @@ -75,7 +76,7 @@ typedef struct MOVFragmentInfo { int64_t tfrf_offset; } MOVFragmentInfo; -typedef struct MOVIndex { +typedef struct MOVTrack { int mode; int entry; unsigned timescale; @@ -88,20 +89,22 @@ typedef struct MOVIndex { int has_keyframes; #define MOV_TRACK_CTTS 0x0001 #define MOV_TRACK_STPS 0x0002 +#define MOV_TRACK_ENABLED 0x0004 uint32_t flags; #define MOV_TIMECODE_FLAG_DROPFRAME 0x0001 #define MOV_TIMECODE_FLAG_24HOURSMAX 0x0002 #define MOV_TIMECODE_FLAG_ALLOWNEGATIVE 0x0004 uint32_t timecode_flags; int language; - int secondary; int track_id; int tag; ///< stsd fourcc + AVStream *st; AVCodecContext *enc; int vos_len; uint8_t *vos_data; MOVIentry *cluster; + unsigned cluster_capacity; int audio_vbr; int height; ///< active picture (w/o VBI) height for D-10/IMX uint32_t tref_tag; @@ -122,13 +125,13 @@ typedef struct MOVIndex { HintSampleQueue sample_queue; AVIOContext *mdat_buf; - int64_t moof_size_offset; int64_t data_offset; int64_t frag_start; int64_t tfrf_offset; int nb_frag_info; MOVFragmentInfo *frag_info; + unsigned frag_info_capacity; struct { int64_t struct_offset; @@ -153,8 +156,6 @@ typedef struct MOVMuxContext { int flags; int rtp_flags; - int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise - int64_t reserved_moov_pos; int iods_skip; int iods_video_profile; @@ -168,6 +169,10 @@ typedef struct MOVMuxContext { AVIOContext *mdat_buf; int use_editlist; + int video_track_timescale; + + int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise + int64_t reserved_moov_pos; } MOVMuxContext; #define FF_MOV_FLAG_RTP_HINT 1 @@ -178,6 +183,7 @@ typedef struct MOVMuxContext { #define FF_MOV_FLAG_FRAG_CUSTOM 32 #define FF_MOV_FLAG_ISML 64 #define FF_MOV_FLAG_FASTSTART 128 +#define FF_MOV_FLAG_OMIT_TFHD_OFFSET 256 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt); diff --git a/ffmpeg/libavformat/movenchint.c b/ffmpeg/libavformat/movenchint.c index cc90f0b..9d6a66e 100644 --- a/ffmpeg/libavformat/movenchint.c +++ b/ffmpeg/libavformat/movenchint.c @@ -87,7 +87,7 @@ static void sample_queue_free(HintSampleQueue *queue) if (queue->samples[i].own_data) av_free(queue->samples[i].data); av_freep(&queue->samples); - queue->len = 0; + queue->len = 0; queue->size = 0; } @@ -104,17 +104,17 @@ static void sample_queue_push(HintSampleQueue *queue, uint8_t *data, int size, if (size <= 14) return; if (!queue->samples || queue->len >= queue->size) { - HintSample* samples; - queue->size += 10; - samples = av_realloc(queue->samples, sizeof(HintSample)*queue->size); + HintSample *samples; + samples = av_realloc_array(queue->samples, queue->size + 10, sizeof(HintSample)); if (!samples) return; + queue->size += 10; queue->samples = samples; } queue->samples[queue->len].data = data; queue->samples[queue->len].size = size; queue->samples[queue->len].sample_number = sample; - queue->samples[queue->len].offset = 0; + queue->samples[queue->len].offset = 0; queue->samples[queue->len].own_data = 0; queue->len++; } @@ -128,7 +128,7 @@ static void sample_queue_retain(HintSampleQueue *queue) for (i = 0; i < queue->len; ) { HintSample *sample = &queue->samples[i]; if (!sample->own_data) { - uint8_t* ptr = av_malloc(sample->size); + uint8_t *ptr = av_malloc(sample->size); if (!ptr) { /* Unable to allocate memory for this one, remove it */ memmove(queue->samples + i, queue->samples + i + 1, @@ -309,11 +309,11 @@ static void describe_payload(const uint8_t *data, int size, * @param data buffer containing RTP packets * @param size the size of the data buffer * @param trk the MOVTrack for the hint track - * @param pts pointer where the timestamp for the written RTP hint is stored + * @param dts pointer where the timestamp for the written RTP hint is stored * @return the number of RTP packets in the written hint */ static int write_hint_packets(AVIOContext *out, const uint8_t *data, - int size, MOVTrack *trk, int64_t *pts) + int size, MOVTrack *trk, int64_t *dts) { int64_t curpos; int64_t count_pos, entries_pos; @@ -328,6 +328,7 @@ static int write_hint_packets(AVIOContext *out, const uint8_t *data, uint32_t packet_len = AV_RB32(data); uint16_t seq; uint32_t ts; + int32_t ts_diff; data += 4; size -= 4; @@ -344,25 +345,35 @@ static int write_hint_packets(AVIOContext *out, const uint8_t *data, trk->max_packet_size = packet_len; seq = AV_RB16(&data[2]); - ts = AV_RB32(&data[4]); + ts = AV_RB32(&data[4]); if (trk->prev_rtp_ts == 0) trk->prev_rtp_ts = ts; /* Unwrap the 32-bit RTP timestamp that wraps around often * into a not (as often) wrapping 64-bit timestamp. */ - trk->cur_rtp_ts_unwrapped += (int32_t) (ts - trk->prev_rtp_ts); - trk->prev_rtp_ts = ts; - if (*pts == AV_NOPTS_VALUE) - *pts = trk->cur_rtp_ts_unwrapped; + ts_diff = ts - trk->prev_rtp_ts; + if (ts_diff > 0) { + trk->cur_rtp_ts_unwrapped += ts_diff; + trk->prev_rtp_ts = ts; + ts_diff = 0; + } + if (*dts == AV_NOPTS_VALUE) + *dts = trk->cur_rtp_ts_unwrapped; count++; /* RTPpacket header */ avio_wb32(out, 0); /* relative_time */ avio_write(out, data, 2); /* RTP header */ avio_wb16(out, seq); /* RTPsequenceseed */ - avio_wb16(out, 0); /* reserved + flags */ + avio_wb16(out, ts_diff ? 4 : 0); /* reserved + flags (extra_flag) */ entries_pos = avio_tell(out); avio_wb16(out, 0); /* entry count */ + if (ts_diff) { /* if extra_flag is set */ + avio_wb32(out, 16); /* extra_information_length */ + avio_wb32(out, 12); /* rtpoffsetTLV box */ + avio_write(out, "rtpo", 4); + avio_wb32(out, ts_diff); + } data += 12; size -= 12; @@ -417,7 +428,7 @@ int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt, * for next time. */ size = avio_close_dyn_buf(rtp_ctx->pb, &buf); if ((ret = ffio_open_dyn_packet_buf(&rtp_ctx->pb, - RTP_MAX_PACKET_SIZE)) < 0) + RTP_MAX_PACKET_SIZE)) < 0) goto done; if (size <= 0) @@ -445,8 +456,9 @@ done: return ret; } -void ff_mov_close_hinting(MOVTrack *track) { - AVFormatContext* rtp_ctx = track->rtp_ctx; +void ff_mov_close_hinting(MOVTrack *track) +{ + AVFormatContext *rtp_ctx = track->rtp_ctx; uint8_t *ptr; av_freep(&track->enc); diff --git a/ffmpeg/libavformat/mp3dec.c b/ffmpeg/libavformat/mp3dec.c index 57e4ba3..5d484e9 100644 --- a/ffmpeg/libavformat/mp3dec.c +++ b/ffmpeg/libavformat/mp3dec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/opt.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" @@ -36,11 +37,15 @@ #define XING_TOC_COUNT 100 typedef struct { + AVClass *class; int64_t filesize; + int64_t header_filesize; int xing_toc; int start_pad; int end_pad; -} MP3Context; + int usetoc; + int is_cbr; +} MP3DecContext; /* mp3 read */ @@ -62,6 +67,8 @@ static int mp3_read_probe(AVProbeData *p) for(; buf < end; buf= buf2+1) { buf2 = buf; + if(ff_mpa_check_header(AV_RB32(buf2))) + continue; for(frames = 0; buf2 < end; frames++) { header = AV_RB32(buf2); @@ -76,11 +83,11 @@ static int mp3_read_probe(AVProbeData *p) } // keep this in sync with ac3 probe, both need to avoid // issues with MPEG-files! - if (first_frames>=4) return AVPROBE_SCORE_MAX/2+1; - else if(max_frames>200)return AVPROBE_SCORE_MAX/2; - else if(max_frames>=4) return AVPROBE_SCORE_MAX/4; + if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1; + else if(max_frames>200)return AVPROBE_SCORE_EXTENSION; + else if(max_frames>=4) return AVPROBE_SCORE_EXTENSION / 2; else if(ff_id3v2_match(buf0, ID3v2_DEFAULT_MAGIC) && 2*ff_id3v2_tag_len(buf0) >= p->buf_size) - return AVPROBE_SCORE_MAX/8; + return p->buf_size < PROBE_BUF_MAX ? AVPROBE_SCORE_EXTENSION / 4 : AVPROBE_SCORE_EXTENSION - 2; else if(max_frames>=1) return 1; else return 0; //mpegps_mp3_unrecognized_format.mpg has max_frames=3 @@ -89,23 +96,25 @@ static int mp3_read_probe(AVProbeData *p) static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration) { int i; - MP3Context *mp3 = s->priv_data; + MP3DecContext *mp3 = s->priv_data; + int fill_index = mp3->usetoc && duration > 0; if (!filesize && !(filesize = avio_size(s->pb))) { av_log(s, AV_LOG_WARNING, "Cannot determine file size, skipping TOC table.\n"); - return; + fill_index = 0; } for (i = 0; i < XING_TOC_COUNT; i++) { uint8_t b = avio_r8(s->pb); - - av_add_index_entry(s->streams[0], + if (fill_index) + av_add_index_entry(s->streams[0], av_rescale(b, filesize, 256), av_rescale(i, duration, XING_TOC_COUNT), 0, 0, AVINDEX_KEYFRAME); } - mp3->xing_toc = 1; + if (fill_index) + mp3->xing_toc = 1; } /** @@ -113,11 +122,11 @@ static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration */ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) { - MP3Context *mp3 = s->priv_data; + MP3DecContext *mp3 = s->priv_data; uint32_t v, spf; unsigned frames = 0; /* Total number of frames in file */ unsigned size = 0; /* Total number of bytes in the stream */ - const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; + static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; MPADecodeHeader c; int vbrtag_size = 0; int is_cbr; @@ -143,7 +152,7 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) frames = avio_rb32(s->pb); if(v & XING_FLAG_SIZE) size = avio_rb32(s->pb); - if (v & XING_FLAG_TOC && frames) + if (v & XING_FLAG_TOC) read_xing_toc(s, size, av_rescale_q(frames, (AVRational){spf, c.sample_rate}, st->time_base)); if(v & 8) @@ -185,12 +194,15 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) if (size && frames && !is_cbr) st->codec->bit_rate = av_rescale(size, 8 * c.sample_rate, frames * (int64_t)spf); + mp3->is_cbr = is_cbr; + mp3->header_filesize = size; + return 0; } static int mp3_read_header(AVFormatContext *s) { - MP3Context *mp3 = s->priv_data; + MP3DecContext *mp3 = s->priv_data; AVStream *st; int64_t off; @@ -226,7 +238,7 @@ static int mp3_read_header(AVFormatContext *s) static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt) { - MP3Context *mp3 = s->priv_data; + MP3DecContext *mp3 = s->priv_data; int ret, size; int64_t pos; @@ -273,29 +285,42 @@ static int check(AVFormatContext *s, int64_t pos) static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { - MP3Context *mp3 = s->priv_data; - AVIndexEntry *ie; + MP3DecContext *mp3 = s->priv_data; + AVIndexEntry *ie, ie1; AVStream *st = s->streams[0]; int64_t ret = av_index_search_timestamp(st, timestamp, flags); int i, j; + int dir = (flags&AVSEEK_FLAG_BACKWARD) ? -1 : 1; + + if (mp3->is_cbr && st->duration > 0 && mp3->header_filesize > s->data_offset) { + int64_t filesize = avio_size(s->pb); + int64_t duration; + if (filesize <= s->data_offset) + filesize = mp3->header_filesize; + filesize -= s->data_offset; + duration = av_rescale(st->duration, filesize, mp3->header_filesize - s->data_offset); + ie = &ie1; + timestamp = av_clip64(timestamp, 0, duration); + ie->timestamp = timestamp; + ie->pos = av_rescale(timestamp, filesize, duration) + s->data_offset; + } else if (mp3->xing_toc) { + if (ret < 0) + return ret; - if (!mp3->xing_toc) { + ie = &st->index_entries[ret]; + } else { st->skip_samples = timestamp <= 0 ? mp3->start_pad + 528 + 1 : 0; return -1; } - if (ret < 0) - return ret; - - ie = &st->index_entries[ret]; ret = avio_seek(s->pb, ie->pos, SEEK_SET); if (ret < 0) return ret; #define MIN_VALID 3 for(i=0; i<4096; i++) { - int64_t pos = ie->pos + i; + int64_t pos = ie->pos + i*dir; for(j=0; j<MIN_VALID; j++) { ret = check(s, pos); if(ret < 0) @@ -308,7 +333,7 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, if(j!=MIN_VALID) i=0; - ret = avio_seek(s->pb, ie->pos + i, SEEK_SET); + ret = avio_seek(s->pb, ie->pos + i*dir, SEEK_SET); if (ret < 0) return ret; ff_update_cur_dts(s, st, ie->timestamp); @@ -316,14 +341,28 @@ static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp, return 0; } +static const AVOption options[] = { + { "usetoc", "use table of contents", offsetof(MP3DecContext, usetoc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM}, + { NULL }, +}; + +static const AVClass demuxer_class = { + .class_name = "mp3", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + AVInputFormat ff_mp3_demuxer = { .name = "mp3", .long_name = NULL_IF_CONFIG_SMALL("MP2/3 (MPEG audio layer 2/3)"), - .priv_data_size = sizeof(MP3Context), .read_probe = mp3_read_probe, .read_header = mp3_read_header, .read_packet = mp3_read_packet, .read_seek = mp3_seek, + .priv_data_size = sizeof(MP3DecContext), .flags = AVFMT_GENERIC_INDEX, - .extensions = "mp2,mp3,m2a", /* XXX: use probe */ + .extensions = "mp2,mp3,m2a,mpa", /* XXX: use probe */ + .priv_class = &demuxer_class, }; diff --git a/ffmpeg/libavformat/mp3enc.c b/ffmpeg/libavformat/mp3enc.c index ee0956e..a5f672b 100644 --- a/ffmpeg/libavformat/mp3enc.c +++ b/ffmpeg/libavformat/mp3enc.c @@ -30,10 +30,6 @@ #include "libavcodec/mpegaudiodecheader.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" -#include "libavcodec/mpegaudio.h" -#include "libavcodec/mpegaudiodata.h" -#include "libavcodec/mpegaudiodecheader.h" -#include "libavformat/avio_internal.h" #include "libavutil/dict.h" #include "libavutil/avassert.h" @@ -385,7 +381,7 @@ AVOutputFormat ff_mp2_muxer = { .name = "mp2", .long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"), .mime_type = "audio/x-mpeg", - .extensions = "mp2,m2a", + .extensions = "mp2,m2a,mpa", .audio_codec = AV_CODEC_ID_MP2, .video_codec = AV_CODEC_ID_NONE, .write_packet = ff_raw_write_packet, diff --git a/ffmpeg/libavformat/mpc.c b/ffmpeg/libavformat/mpc.c index b0f6f53..c3faebe 100644 --- a/ffmpeg/libavformat/mpc.c +++ b/ffmpeg/libavformat/mpc.c @@ -95,9 +95,8 @@ static int mpc_read_header(AVFormatContext *s) st->codec->channel_layout = AV_CH_LAYOUT_STEREO; st->codec->bits_per_coded_sample = 16; - st->codec->extradata_size = 16; - st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE); - avio_read(s->pb, st->codec->extradata, 16); + if (ff_get_extradata(st->codec, s->pb, 16) < 0) + return AVERROR(ENOMEM); st->codec->sample_rate = mpc_rate[st->codec->extradata[2] & 3]; avpriv_set_pts_info(st, 32, MPC_FRAMESIZE, st->codec->sample_rate); /* scan for seekpoints */ diff --git a/ffmpeg/libavformat/mpc8.c b/ffmpeg/libavformat/mpc8.c index 73f8057..b32bc9c 100644 --- a/ffmpeg/libavformat/mpc8.c +++ b/ffmpeg/libavformat/mpc8.c @@ -92,7 +92,7 @@ static int mpc8_probe(AVProbeData *p) if (size < 2) return 0; if (bs + size - 2 >= bs_end) - return AVPROBE_SCORE_MAX / 4 - 1; //seems to be valid MPC but no header yet + return AVPROBE_SCORE_EXTENSION - 1; // seems to be valid MPC but no header yet if (header_found) { if (size < 11 || size > 28) return 0; @@ -136,11 +136,11 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) int tag; int64_t size, pos, ppos[2]; uint8_t *buf; - int i, t, seekd; + int i, t, seekd, ret; GetBitContext gb; - if (s->nb_streams<=0) { - av_log(s, AV_LOG_ERROR, "cannot parse stream table before stream header\n"); + if (s->nb_streams == 0) { + av_log(s, AV_LOG_ERROR, "No stream added before parsing seek table\n"); return; } @@ -151,12 +151,19 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) return; } if (size > INT_MAX/10 || size<=0) { - av_log(s, AV_LOG_ERROR, "Seek table size is invalid\n"); + av_log(s, AV_LOG_ERROR, "Bad seek table size\n"); return; } if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE))) return; - avio_read(s->pb, buf, size); + ret = avio_read(s->pb, buf, size); + if (ret != size) { + av_log(s, AV_LOG_ERROR, "seek table truncated\n"); + av_free(buf); + return; + } + memset(buf+size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + init_get_bits(&gb, buf, size * 8); size = gb_get_v(&gb); if(size > UINT_MAX/4 || size > c->samples/1152){ @@ -241,9 +248,8 @@ static int mpc8_read_header(AVFormatContext *s) st->codec->codec_id = AV_CODEC_ID_MUSEPACK8; st->codec->bits_per_coded_sample = 16; - st->codec->extradata_size = 2; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - avio_read(pb, st->codec->extradata, st->codec->extradata_size); + if (ff_get_extradata(st->codec, pb, 2) < 0) + return AVERROR(ENOMEM); st->codec->channels = (st->codec->extradata[1] >> 4) + 1; st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5]; diff --git a/ffmpeg/libavformat/mpeg.c b/ffmpeg/libavformat/mpeg.c index f36f0db..1777283 100644 --- a/ffmpeg/libavformat/mpeg.c +++ b/ffmpeg/libavformat/mpeg.c @@ -89,14 +89,14 @@ static int mpegps_probe(AVProbeData *p) } if(vid+audio > invalid+1) /* invalid VDR files nd short PES streams */ - score= AVPROBE_SCORE_MAX/4; + score = AVPROBE_SCORE_EXTENSION / 2; if(sys>invalid && sys*9 <= pspack*10) - return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4; // +1 for .mpg + return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg if(pspack > invalid && (priv1+vid+audio)*10 >= pspack*9) - return pspack > 2 ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4; // +1 for .mpg + return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg if((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys && !pspack && p->buf_size>2048 && vid + audio > invalid) /* PES stream */ - return (audio > 12 || vid > 3 + 2*invalid) ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4; + return (audio > 12 || vid > 3 + 2*invalid) ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; //02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1 //mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6 @@ -110,31 +110,28 @@ typedef struct MpegDemuxContext { unsigned char psm_es_type[256]; int sofdec; int dvd; + int imkh_cctv; #if CONFIG_VOBSUB_DEMUXER AVFormatContext *sub_ctx; - FFDemuxSubtitlesQueue q; + FFDemuxSubtitlesQueue q[32]; #endif } MpegDemuxContext; static int mpegps_read_header(AVFormatContext *s) { MpegDemuxContext *m = s->priv_data; - const char *sofdec = "Sofdec"; - int v, i = 0; + char buffer[7]; int64_t last_pos = avio_tell(s->pb); m->header_state = 0xff; s->ctx_flags |= AVFMTCTX_NOHEADER; - m->sofdec = -1; - do { - v = avio_r8(s->pb); - m->sofdec++; - } while (v == sofdec[i] && i++ < 6); - - m->sofdec = (m->sofdec == 6) ? 1 : 0; - - if (!m->sofdec) + avio_get_str(s->pb, 6, buffer, sizeof(buffer)); + if (!memcmp("IMKH", buffer, 4)) { + m->imkh_cctv = 1; + } else if (!memcmp("Sofdec", buffer, 6)) { + m->sofdec = 1; + } else avio_seek(s->pb, last_pos, SEEK_SET); /* no need to do more */ @@ -196,6 +193,8 @@ static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb) /* skip program_stream_info */ avio_skip(pb, ps_info_length); es_map_length = avio_rb16(pb); + /* Ignore es_map_length, trust psm_length */ + es_map_length = psm_length - ps_info_length - 10; /* at least one es available? */ while (es_map_length >= 4){ @@ -506,6 +505,9 @@ static int mpegps_read_packet(AVFormatContext *s, } else if(es_type == STREAM_TYPE_AUDIO_AC3){ codec_id = AV_CODEC_ID_AC3; type = AVMEDIA_TYPE_AUDIO; + } else if(m->imkh_cctv && es_type == 0x91){ + codec_id = AV_CODEC_ID_PCM_MULAW; + type = AVMEDIA_TYPE_AUDIO; } else if (startcode >= 0x1e0 && startcode <= 0x1ef) { static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 }; unsigned char buf[8]; @@ -521,7 +523,13 @@ static int mpegps_read_packet(AVFormatContext *s, codec_id = AV_CODEC_ID_DVD_NAV; } else if (startcode >= 0x1c0 && startcode <= 0x1df) { type = AVMEDIA_TYPE_AUDIO; - codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2; + if (m->sofdec > 0) { + codec_id = AV_CODEC_ID_ADPCM_ADX; + // Auto-detect AC-3 + request_probe = 50; + } else { + codec_id = AV_CODEC_ID_MP2; + } } else if (startcode >= 0x80 && startcode <= 0x87) { type = AVMEDIA_TYPE_AUDIO; codec_id = AV_CODEC_ID_AC3; @@ -535,7 +543,6 @@ static int mpegps_read_packet(AVFormatContext *s, if(lpcm_header_len == 6) { codec_id = AV_CODEC_ID_MLP; } else { - /* 16 bit form will be handled as AV_CODEC_ID_PCM_S16BE */ codec_id = AV_CODEC_ID_PCM_DVD; } } else if (startcode >= 0xb0 && startcode <= 0xbf) { @@ -564,9 +571,13 @@ static int mpegps_read_packet(AVFormatContext *s, st->id = startcode; st->codec->codec_type = type; st->codec->codec_id = codec_id; + if (st->codec->codec_id == AV_CODEC_ID_PCM_MULAW) { + st->codec->channels = 1; + st->codec->channel_layout = AV_CH_LAYOUT_MONO; + st->codec->sample_rate = 8000; + } st->request_probe = request_probe; - if (codec_id != AV_CODEC_ID_PCM_S16BE) - st->need_parsing = AVSTREAM_PARSE_FULL; + st->need_parsing = AVSTREAM_PARSE_FULL; found: if(st->discard >= AVDISCARD_ALL) goto skip; @@ -576,28 +587,6 @@ static int mpegps_read_packet(AVFormatContext *s, goto skip; avio_skip(s->pb, 6); len -=6; - } else { - int b1, freq; - - /* for LPCM, we just skip the header and consider it is raw - audio data */ - if (len <= 3) - goto skip; - avio_r8(s->pb); /* emphasis (1), muse(1), reserved(1), frame number(5) */ - b1 = avio_r8(s->pb); /* quant (2), freq(2), reserved(1), channels(3) */ - avio_r8(s->pb); /* dynamic range control (0x80 = off) */ - len -= 3; - freq = (b1 >> 4) & 3; - st->codec->sample_rate = lpcm_freq_tab[freq]; - st->codec->channels = 1 + (b1 & 7); - st->codec->bits_per_coded_sample = 16 + ((b1 >> 6) & 3) * 4; - st->codec->bit_rate = st->codec->channels * - st->codec->sample_rate * - st->codec->bits_per_coded_sample; - if (st->codec->bits_per_coded_sample == 16) - st->codec->codec_id = AV_CODEC_ID_PCM_S16BE; - else if (st->codec->bits_per_coded_sample == 28) - return AVERROR(EINVAL); } } ret = av_get_packet(s->pb, pkt, len); @@ -712,6 +701,12 @@ static int vobsub_read_header(AVFormatContext *s) stream_id = 0; } + if (stream_id >= FF_ARRAY_ELEMS(vobsub->q)) { + av_log(s, AV_LOG_ERROR, "Maximum number of subtitles streams reached\n"); + ret = AVERROR(EINVAL); + goto end; + } + st = avformat_new_stream(s, NULL); if (!st) { ret = AVERROR(ENOMEM); @@ -720,6 +715,7 @@ static int vobsub_read_header(AVFormatContext *s) st->id = stream_id; st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE; + avpriv_set_pts_info(st, 64, 1, 1000); av_dict_set(&st->metadata, "language", id, 0); av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id); header_parsed = 1; @@ -730,7 +726,13 @@ static int vobsub_read_header(AVFormatContext *s) int64_t pos, timestamp; const char *p = line + 10; - if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"PRIx64, + if (!s->nb_streams) { + av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n"); + ret = AVERROR_INVALIDDATA; + goto end; + } + + if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"SCNx64, &hh, &mm, &ss, &ms, &pos) != 5) { av_log(s, AV_LOG_ERROR, "Unable to parse timestamp line '%s', " "abort parsing\n", line); @@ -739,7 +741,7 @@ static int vobsub_read_header(AVFormatContext *s) timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay; timestamp = av_rescale_q(timestamp, (AVRational){1,1000}, st->time_base); - sub = ff_subtitles_queue_insert(&vobsub->q, "", 0, 0); + sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0); if (!sub) { ret = AVERROR(ENOMEM); goto end; @@ -785,7 +787,10 @@ static int vobsub_read_header(AVFormatContext *s) if (langidx < s->nb_streams) s->streams[langidx]->disposition |= AV_DISPOSITION_DEFAULT; - ff_subtitles_queue_finalize(&vobsub->q); + for (i = 0; i < s->nb_streams; i++) { + vobsub->q[i].sort = SUB_SORT_POS_TS; + ff_subtitles_queue_finalize(&vobsub->q[i]); + } if (!av_bprint_is_complete(&header)) { av_bprint_finalize(&header, NULL); @@ -810,11 +815,22 @@ end: static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) { MpegDemuxContext *vobsub = s->priv_data; - FFDemuxSubtitlesQueue *q = &vobsub->q; + FFDemuxSubtitlesQueue *q; AVIOContext *pb = vobsub->sub_ctx->pb; - int ret, psize, len16 = -1; + int ret, psize, total_read = 0, i; AVPacket idx_pkt; + int64_t min_ts = INT64_MAX; + int sid = 0; + for (i = 0; i < s->nb_streams; i++) { + FFDemuxSubtitlesQueue *tmpq = &vobsub->q[i]; + int64_t ts = tmpq->subs[tmpq->current_sub_idx].pts; + if (ts < min_ts) { + min_ts = ts; + sid = i; + } + } + q = &vobsub->q[sid]; ret = ff_subtitles_queue_read_packet(q, &idx_pkt); if (ret < 0) return ret; @@ -837,19 +853,23 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) do { int n, to_read, startcode; int64_t pts, dts; + int64_t old_pos = avio_tell(pb), new_pos; + int pkt_size; ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts); - if (ret < 0) + if (ret < 0) { + if (pkt->size) // raise packet even if incomplete + break; FAIL(ret); + } to_read = ret & 0xffff; + new_pos = avio_tell(pb); + pkt_size = ret + (new_pos - old_pos); /* this prevents reads above the current packet */ - if (pkt->size + to_read > psize) - break; - - /* if the len is computed, we check for overread */ - if (len16 != -1 && pkt->size + to_read > len16) + if (total_read + pkt_size > psize) break; + total_read += pkt_size; /* the current chunk doesn't match the stream index (unlikely) */ if ((startcode & 0x1f) != idx_pkt.stream_index) @@ -862,11 +882,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read); if (n < to_read) pkt->size -= to_read - n; - - /* first chunk contains the total len of the packet to raise */ - if (len16 == -1 && n > 2) - len16 = AV_RB16(pkt->data); - } while (len16 != -1 && pkt->size != len16); + } while (total_read < psize); pkt->pts = pkt->dts = idx_pkt.pts; pkt->pos = idx_pkt.pos; @@ -876,6 +892,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; fail: + av_free_packet(pkt); av_free_packet(&idx_pkt); return ret; } @@ -884,14 +901,42 @@ static int vobsub_read_seek(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags) { MpegDemuxContext *vobsub = s->priv_data; - return ff_subtitles_queue_seek(&vobsub->q, s, stream_index, + + /* Rescale requested timestamps based on the first stream (timebase is the + * same for all subtitles stream within a .idx/.sub). Rescaling is done just + * like in avformat_seek_file(). */ + if (stream_index == -1 && s->nb_streams != 1) { + int i, ret = 0; + AVRational time_base = s->streams[0]->time_base; + ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base); + min_ts = av_rescale_rnd(min_ts, time_base.den, + time_base.num * (int64_t)AV_TIME_BASE, + AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + max_ts = av_rescale_rnd(max_ts, time_base.den, + time_base.num * (int64_t)AV_TIME_BASE, + AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX); + for (i = 0; i < s->nb_streams; i++) { + int r = ff_subtitles_queue_seek(&vobsub->q[i], s, stream_index, + min_ts, ts, max_ts, flags); + if (r < 0) + ret = r; + } + return ret; + } + + if (stream_index == -1) // only 1 stream + stream_index = 0; + return ff_subtitles_queue_seek(&vobsub->q[stream_index], s, stream_index, min_ts, ts, max_ts, flags); } static int vobsub_read_close(AVFormatContext *s) { + int i; MpegDemuxContext *vobsub = s->priv_data; - ff_subtitles_queue_clean(&vobsub->q); + + for (i = 0; i < s->nb_streams; i++) + ff_subtitles_queue_clean(&vobsub->q[i]); if (vobsub->sub_ctx) avformat_close_input(&vobsub->sub_ctx); return 0; diff --git a/ffmpeg/libavformat/mpeg.h b/ffmpeg/libavformat/mpeg.h index a1e8980..cf10d6a 100644 --- a/ffmpeg/libavformat/mpeg.h +++ b/ffmpeg/libavformat/mpeg.h @@ -41,7 +41,7 @@ #define AUDIO_ID 0xc0 #define VIDEO_ID 0xe0 #define AC3_ID 0x80 -#define DTS_ID 0x8a +#define DTS_ID 0x88 #define LPCM_ID 0xa0 #define SUB_ID 0x20 diff --git a/ffmpeg/libavformat/mpegenc.c b/ffmpeg/libavformat/mpegenc.c index b467bb5..ccf3ec2 100644 --- a/ffmpeg/libavformat/mpegenc.c +++ b/ffmpeg/libavformat/mpegenc.c @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + +#include "libavutil/attributes.h" #include "libavutil/fifo.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" @@ -264,8 +267,7 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_str flush_put_bits(&pb); size = put_bits_ptr(&pb) - pb.buf; /* patch packet size */ - buf[4] = (size - 6) >> 8; - buf[5] = (size - 6) & 0xff; + AV_WB16(buf + 4, size - 6); return size; } @@ -293,7 +295,7 @@ static int get_system_header_size(AVFormatContext *ctx) return buf_index; } -static int mpeg_mux_init(AVFormatContext *ctx) +static av_cold int mpeg_mux_init(AVFormatContext *ctx) { MpegMuxContext *s = ctx->priv_data; int bitrate, i, mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id, j; @@ -320,7 +322,7 @@ static int mpeg_mux_init(AVFormatContext *ctx) } else s->packet_size = 2048; if (ctx->max_delay < 0) /* Not set by the caller */ - ctx->max_delay = 0; + ctx->max_delay = 0.7*AV_TIME_BASE; s->vcd_padding_bytes_written = 0; s->vcd_padding_bitrate=0; @@ -344,6 +346,15 @@ static int mpeg_mux_init(AVFormatContext *ctx) switch(st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: + if (!s->is_mpeg2 && + (st->codec->codec_id == AV_CODEC_ID_AC3 || + st->codec->codec_id == AV_CODEC_ID_DTS || + st->codec->codec_id == AV_CODEC_ID_PCM_S16BE)) + av_log(ctx, AV_LOG_WARNING, + "%s in MPEG-1 system streams is not widely supported, " + "consider using the vob or the dvd muxer " + "to force a MPEG-2 program stream.\n", + avcodec_get_name(st->codec->codec_id)); if (st->codec->codec_id == AV_CODEC_ID_AC3) { stream->id = ac3_id++; } else if (st->codec->codec_id == AV_CODEC_ID_DTS) { @@ -379,6 +390,10 @@ static int mpeg_mux_init(AVFormatContext *ctx) av_log(ctx, AV_LOG_WARNING, "VBV buffer size not set, muxing may fail\n"); stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default } + if (stream->max_buffer_size > 1024 * 8191) { + av_log(ctx, AV_LOG_WARNING, "buffer size %d, too large\n", stream->max_buffer_size); + stream->max_buffer_size = 1024 * 8191; + } s->video_bound++; break; case AVMEDIA_TYPE_SUBTITLE: @@ -424,6 +439,10 @@ static int mpeg_mux_init(AVFormatContext *ctx) bitrate += bitrate / 20; bitrate += 10000; s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); + if (s->mux_rate >= (1<<22)) { + av_log(ctx, AV_LOG_WARNING, "mux rate %d is too large\n", s->mux_rate); + s->mux_rate = (1<<22) - 1; + } } if (s->is_vcd) { @@ -905,7 +924,7 @@ static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr){ if(stream->buffer_index < pkt_desc->size || stream->predecode_packet == stream->premux_packet){ av_log(ctx, AV_LOG_ERROR, - "buffer underflow i=%d bufi=%d size=%d\n", + "buffer underflow st=%d bufi=%d size=%d\n", i, stream->buffer_index, pkt_desc->size); break; } @@ -947,14 +966,16 @@ retry: return 0; if(avail_data==0) continue; - assert(avail_data>0); + av_assert0(avail_data>0); if(space < s->packet_size && !ignore_constraints) continue; if(next_pkt && next_pkt->dts - scr > max_delay) continue; - + if ( stream->predecode_packet + && stream->predecode_packet->size > stream->buffer_index) + rel_space += 1<<28; if(rel_space > best_score){ best_score= rel_space; best_i = i; @@ -1144,7 +1165,7 @@ static int mpeg_mux_end(AVFormatContext *ctx) #define OFFSET(x) offsetof(MpegMuxContext, x) #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "muxrate", NULL, OFFSET(user_mux_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, + { "muxrate", NULL, OFFSET(user_mux_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, ((1<<22) - 1) * (8 * 50), E }, { "preload", "Initial demux-decode delay in microseconds.", OFFSET(preload), AV_OPT_TYPE_INT, {.i64 = 500000}, 0, INT_MAX, E}, { NULL }, }; diff --git a/ffmpeg/libavformat/mpegts.c b/ffmpeg/libavformat/mpegts.c index 85b5146..39b1b5d 100644 --- a/ffmpeg/libavformat/mpegts.c +++ b/ffmpeg/libavformat/mpegts.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavcodec/bytestream.h" #include "libavcodec/get_bits.h" +#include "libavcodec/mathops.h" #include "avformat.h" #include "mpegts.h" #include "internal.h" @@ -52,7 +53,7 @@ enum MpegTSFilterType { typedef struct MpegTSFilter MpegTSFilter; -typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos); +typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos, int64_t cur_pcr); typedef struct MpegTSPESFilter { PESCallback *pes_cb; @@ -89,6 +90,9 @@ struct Program { unsigned int id; //program id/service id unsigned int nb_pids; unsigned int pids[MAX_PIDS_PER_PROGRAM]; + + /** have we found pmt for this program */ + int pmt_found; }; struct MpegTSContext { @@ -98,7 +102,11 @@ struct MpegTSContext { /** raw packet size, including FEC if present */ int raw_packet_size; - int pos47; + int size_stat[3]; + int size_stat_count; +#define SIZE_STAT_THRESHOLD 10 + + int64_t pos47_full; /** if true, all pids are analyzed to find streams */ int auto_guess; @@ -106,6 +114,9 @@ struct MpegTSContext { /** compute exact PCR for each transport stream packet */ int mpeg2ts_compute_pcr; + /** fix dvb teletext pts */ + int fix_teletext_pts; + int64_t cur_pcr; /**< used to estimate the exact PCR */ int pcr_incr; /**< used to estimate the exact PCR */ @@ -131,16 +142,33 @@ struct MpegTSContext { int current_pid; }; -static const AVOption options[] = { +static const AVOption mpegtsraw_options[] = { {"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, + {.i64 = 0}, 0, 0, AV_OPT_FLAG_METADATA }, { NULL }, }; static const AVClass mpegtsraw_class = { .class_name = "mpegtsraw demuxer", .item_name = av_default_item_name, - .option = options, + .option = mpegtsraw_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVOption mpegts_options[] = { + {"fix_teletext_pts", "Try to fix pts values of dvb teletext streams.", offsetof(MpegTSContext, fix_teletext_pts), AV_OPT_TYPE_INT, + {.i64 = 1}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT, + {.i64 = 0}, 0, 0, AV_OPT_FLAG_METADATA }, + { NULL }, +}; + +static const AVClass mpegts_class = { + .class_name = "mpegts demuxer", + .item_name = av_default_item_name, + .option = mpegts_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -179,10 +207,22 @@ typedef struct PESContext { uint8_t header[MAX_PES_HEADER_SIZE]; AVBufferRef *buffer; SLConfigDescr sl; + int64_t last_pcr; } PESContext; extern AVInputFormat ff_mpegts_demuxer; +static struct Program * get_program(MpegTSContext *ts, unsigned int programid) +{ + int i; + for(i=0; i<ts->nb_prg; i++) { + if(ts->prg[i].id == programid) { + return &ts->prg[i]; + } + } + return NULL; +} + static void clear_avprogram(MpegTSContext *ts, unsigned int programid) { AVProgram *prg = NULL; @@ -203,8 +243,10 @@ static void clear_program(MpegTSContext *ts, unsigned int programid) clear_avprogram(ts, programid); for(i=0; i<ts->nb_prg; i++) - if(ts->prg[i].id == programid) + if(ts->prg[i].id == programid) { ts->prg[i].nb_pids = 0; + ts->prg[i].pmt_found = 0; + } } static void clear_programs(MpegTSContext *ts) @@ -216,26 +258,20 @@ static void clear_programs(MpegTSContext *ts) static void add_pat_entry(MpegTSContext *ts, unsigned int programid) { struct Program *p; - void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(struct Program)); - if(!tmp) + if (av_reallocp_array(&ts->prg, ts->nb_prg + 1, sizeof(*ts->prg)) < 0) { + ts->nb_prg = 0; return; - ts->prg = tmp; + } p = &ts->prg[ts->nb_prg]; p->id = programid; p->nb_pids = 0; + p->pmt_found = 0; ts->nb_prg++; } static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid) { - int i; - struct Program *p = NULL; - for(i=0; i<ts->nb_prg; i++) { - if(ts->prg[i].id == programid) { - p = &ts->prg[i]; - break; - } - } + struct Program *p = get_program(ts, programid); if(!p) return; @@ -244,6 +280,15 @@ static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned i p->pids[p->nb_pids++] = pid; } +static void set_pmt_found(MpegTSContext *ts, unsigned int programid) +{ + struct Program *p = get_program(ts, programid); + if(!p) + return; + + p->pmt_found = 1; +} + static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid) { int i; @@ -268,6 +313,17 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid) int i, j, k; int used = 0, discarded = 0; struct Program *p; + + /* If none of the programs have .discard=AVDISCARD_ALL then there's + * no way we have to discard this packet + */ + for (k = 0; k < ts->stream->nb_programs; k++) { + if (ts->stream->programs[k]->discard == AVDISCARD_ALL) + break; + } + if (k == ts->stream->nb_programs) + return 0; + for(i=0; i<ts->nb_prg; i++) { p = &ts->prg[i]; for(j=0; j<p->nb_pids; j++) { @@ -419,22 +475,19 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) static int analyze(const uint8_t *buf, int size, int packet_size, int *index){ int stat[TS_MAX_PACKET_SIZE]; int i; - int x=0; int best_score=0; - memset(stat, 0, packet_size*sizeof(int)); + memset(stat, 0, packet_size*sizeof(*stat)); - for(x=i=0; i<size-3; i++){ + for(i=0; i<size-3; i++){ if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){ + int x = i % packet_size; stat[x]++; if(stat[x] > best_score){ best_score= stat[x]; if(index) *index= x; } } - - x++; - if(x == packet_size) x= 0; } return best_score; @@ -566,6 +619,7 @@ static const StreamType ISO_types[] = { { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */ #endif { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, + { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, { 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, @@ -600,11 +654,17 @@ static const StreamType REGD_types[] = { { MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, { MKTAG('D','T','S','2'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, { MKTAG('D','T','S','3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { MKTAG('H','E','V','C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV }, { MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 }, { 0 }, }; +static const StreamType METADATA_types[] = { + { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV }, + { 0 }, +}; + /* descriptor present */ static const StreamType DESC_types[] = { { 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */ @@ -808,7 +868,7 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf /* return non zero if a packet could be constructed */ static int mpegts_push_data(MpegTSFilter *filter, const uint8_t *buf, int buf_size, int is_start, - int64_t pos) + int64_t pos, int64_t pcr) { PESContext *pes = filter->u.pes_filter.opaque; MpegTSContext *ts = pes->ts; @@ -818,6 +878,9 @@ static int mpegts_push_data(MpegTSFilter *filter, if(!ts->pkt) return 0; + if (pcr != -1) + pes->last_pcr = pcr; + if (is_start) { if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { new_pes_packet(pes, ts->pkt); @@ -932,7 +995,10 @@ static int mpegts_push_data(MpegTSFilter *filter, pes->pts = AV_NOPTS_VALUE; pes->dts = AV_NOPTS_VALUE; if ((flags & 0xc0) == 0x80) { - pes->dts = pes->pts = ff_parse_pes_pts(r); + pes->pts = ff_parse_pes_pts(r); + /* video pts is not monotonic, can't be used for dts */ + if (pes->st->codec->codec_type != AVMEDIA_TYPE_VIDEO) + pes->dts = pes->pts; r += 5; } else if ((flags & 0xc0) == 0xc0) { pes->pts = ff_parse_pes_pts(r); @@ -964,6 +1030,38 @@ static int mpegts_push_data(MpegTSFilter *filter, p += sl_header_bytes; buf_size -= sl_header_bytes; } + if (pes->stream_type == 0x15 && buf_size >= 5) { + /* skip metadata access unit header */ + pes->pes_header_size += 5; + p += 5; + buf_size -= 5; + } + if (pes->ts->fix_teletext_pts && pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) { + AVProgram *p = NULL; + while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) { + if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) { + MpegTSFilter *f = pes->ts->pids[p->pcr_pid]; + if (f && f->type == MPEGTS_PES) { + PESContext *pcrpes = f->u.pes_filter.opaque; + if (pcrpes && pcrpes->last_pcr != -1 && pcrpes->st && pcrpes->st->discard != AVDISCARD_ALL) { + // teletext packets do not always have correct timestamps, + // the standard says they should be handled after 40.6 ms at most, + // and the pcr error to this packet should be no more than 100 ms. + // TODO: we should interpolate the PCR, not just use the last one + int64_t pcr = pcrpes->last_pcr / 300; + pes->st->pts_wrap_reference = pcrpes->st->pts_wrap_reference; + pes->st->pts_wrap_behavior = pcrpes->st->pts_wrap_behavior; + if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) { + pes->pts = pes->dts = pcr; + } else if (pes->dts > pcr + 3654 + 9000) { + pes->pts = pes->dts = pcr + 3654 + 9000; + } + break; + } + } + } + } + } } break; case MPEGTS_PAYLOAD: @@ -1020,6 +1118,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) pes->state = MPEGTS_SKIP; pes->pts = AV_NOPTS_VALUE; pes->dts = AV_NOPTS_VALUE; + pes->last_pcr = -1; tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); if (!tss) { av_free(pes); @@ -1157,6 +1256,11 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len) descr->sl.timestamp_res = avio_rb32(&d->pb); avio_rb32(&d->pb); descr->sl.timestamp_len = avio_r8(&d->pb); + if (descr->sl.timestamp_len > 64) { + avpriv_request_sample(NULL, "timestamp_len > 64"); + descr->sl.timestamp_len = 64; + return AVERROR_PATCHWELCOME; + } descr->sl.ocr_len = avio_r8(&d->pb); descr->sl.au_len = avio_r8(&d->pb); descr->sl.inst_bitrate_len = avio_r8(&d->pb); @@ -1391,9 +1495,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4)) avpriv_request_sample(fc, "DVB sub with multiple IDs"); } else { - st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE); - if (st->codec->extradata) { - st->codec->extradata_size = 4; + if (!ff_alloc_extradata(st->codec, 4)) { memcpy(st->codec->extradata, *pp, 4); } } @@ -1426,6 +1528,15 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type case 0x52: /* stream identifier descriptor */ st->stream_identifier = 1 + get8(pp, desc_end); break; + case 0x26: /* metadata descriptor */ + if (get16(pp, desc_end) == 0xFFFF) + *pp += 4; + if (get8(pp, desc_end) == 0xFF) { + st->codec->codec_tag = bytestream_get_le32(pp); + if (st->codec->codec_id == AV_CODEC_ID_NONE) + mpegts_find_stream_type(st, st->codec->codec_tag, METADATA_types); + } + break; default: break; } @@ -1507,6 +1618,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (!ts->stream->nb_streams) ts->stop_parse = 2; + set_pmt_found(ts, h->id); + for(;;) { st = 0; pes = NULL; @@ -1625,12 +1738,18 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (sid == 0x0000) { /* NIT info */ } else { + MpegTSFilter *fil = ts->pids[pmt_pid]; program = av_new_program(ts->stream, sid); program->program_num = sid; program->pmt_pid = pmt_pid; - if (ts->pids[pmt_pid]) - mpegts_close_filter(ts, ts->pids[pmt_pid]); - mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); + if (fil) + if ( fil->type != MPEGTS_SECTION + || fil->pid != pmt_pid + || fil->u.section_filter.section_cb != pmt_cb) + mpegts_close_filter(ts, ts->pids[pmt_pid]); + + if (!ts->pids[pmt_pid]) + mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); add_pat_entry(ts, sid); add_pid_to_pmt(ts, sid, 0); //add pat pid to program add_pid_to_pmt(ts, sid, pmt_pid); @@ -1726,6 +1845,9 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len } } +static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, + const uint8_t *packet); + /* handle one TS packet */ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) { @@ -1790,7 +1912,10 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) return 0; pos = avio_tell(ts->stream->pb); - ts->pos47= pos % ts->raw_packet_size; + if (pos >= 0) { + av_assert0(pos >= TS_PACKET_SIZE); + ts->pos47_full = pos - TS_PACKET_SIZE; + } if (tss->type == MPEGTS_SECTION) { if (is_start) { @@ -1817,17 +1942,70 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) p, p_end - p, 0); } } + + // stop find_stream_info from waiting for more streams + // when all programs have received a PMT + if( ts->stream->ctx_flags & AVFMTCTX_NOHEADER) { + int i; + for(i=0; i<ts->nb_prg; i++) { + if (!ts->prg[i].pmt_found) + break; + } + if (i == ts->nb_prg && ts->nb_prg > 0) { + av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n"); + ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER; + } + } + } else { int ret; + int64_t pcr = -1; + int64_t pcr_h; + int pcr_l; + if (parse_pcr(&pcr_h, &pcr_l, packet) == 0) + pcr = pcr_h * 300 + pcr_l; // Note: The position here points actually behind the current packet. if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, - pos - ts->raw_packet_size)) < 0) + pos - ts->raw_packet_size, pcr)) < 0) return ret; } return 0; } +static void reanalyze(MpegTSContext *ts) { + AVIOContext *pb = ts->stream->pb; + int64_t pos = avio_tell(pb); + if(pos < 0) + return; + pos -= ts->pos47_full; + if (pos == TS_PACKET_SIZE) { + ts->size_stat[0] ++; + } else if (pos == TS_DVHS_PACKET_SIZE) { + ts->size_stat[1] ++; + } else if (pos == TS_FEC_PACKET_SIZE) { + ts->size_stat[2] ++; + } + + ts->size_stat_count ++; + if(ts->size_stat_count > SIZE_STAT_THRESHOLD) { + int newsize = 0; + if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) { + newsize = TS_PACKET_SIZE; + } else if (ts->size_stat[1] > SIZE_STAT_THRESHOLD) { + newsize = TS_DVHS_PACKET_SIZE; + } else if (ts->size_stat[2] > SIZE_STAT_THRESHOLD) { + newsize = TS_FEC_PACKET_SIZE; + } + if (newsize && newsize != ts->raw_packet_size) { + av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", newsize); + ts->raw_packet_size = newsize; + } + ts->size_stat_count = 0; + memset(ts->size_stat, 0, sizeof(ts->size_stat)); + } +} + /* XXX: try to find a better synchro over several packets (use get_packet_size() ?) */ static int mpegts_resync(AVFormatContext *s) @@ -1841,6 +2019,7 @@ static int mpegts_resync(AVFormatContext *s) return -1; if (c == 0x47) { avio_seek(pb, -1, SEEK_CUR); + reanalyze(s->priv_data); return 0; } } @@ -1850,37 +2029,45 @@ static int mpegts_resync(AVFormatContext *s) } /* return -1 if error or EOF. Return 0 if OK. */ -static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size) +static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size, const uint8_t **data) { AVIOContext *pb = s->pb; - int skip, len; + int len; for(;;) { - len = avio_read(pb, buf, TS_PACKET_SIZE); + len = ffio_read_indirect(pb, buf, TS_PACKET_SIZE, data); if (len != TS_PACKET_SIZE) return len < 0 ? len : AVERROR_EOF; /* check packet sync byte */ - if (buf[0] != 0x47) { + if ((*data)[0] != 0x47) { /* find a new packet start */ - avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR); + uint64_t pos = avio_tell(pb); + avio_seek(pb, -FFMIN(raw_packet_size, pos), SEEK_CUR); + if (mpegts_resync(s) < 0) return AVERROR(EAGAIN); else continue; } else { - skip = raw_packet_size - TS_PACKET_SIZE; - if (skip > 0) - avio_skip(pb, skip); break; } } return 0; } +static void finished_reading_packet(AVFormatContext *s, int raw_packet_size) +{ + AVIOContext *pb = s->pb; + int skip = raw_packet_size - TS_PACKET_SIZE; + if (skip > 0) + avio_skip(pb, skip); +} + static int handle_packets(MpegTSContext *ts, int nb_packets) { AVFormatContext *s = ts->stream; uint8_t packet[TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; + const uint8_t *data; int packet_num, ret = 0; if (avio_tell(s->pb) != ts->last_pos) { @@ -1894,6 +2081,7 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) av_buffer_unref(&pes->buffer); pes->data_index = 0; pes->state = MPEGTS_SKIP; /* skip until pes header */ + pes->last_pcr = -1; } ts->pids[i]->last_cc = -1; } @@ -1913,10 +2101,11 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) if (ts->stop_parse > 0) break; - ret = read_packet(s, packet, ts->raw_packet_size); + ret = read_packet(s, packet, ts->raw_packet_size, &data); if (ret != 0) break; - ret = handle_packet(ts, packet); + ret = handle_packet(ts, data); + finished_reading_packet(s, ts->raw_packet_size); if (ret != 0) break; } @@ -1986,6 +2175,15 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, return 0; } +static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) { + + /* NOTE: We attempt to seek on non-seekable files as well, as the + * probe buffer usually is big enough. Only warn if the seek failed + * on files where the seek should work. */ + if (avio_seek(pb, pos, SEEK_SET) < 0) + av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n"); +} + static int mpegts_read_header(AVFormatContext *s) { MpegTSContext *ts = s->priv_data; @@ -1994,6 +2192,8 @@ static int mpegts_read_header(AVFormatContext *s) int len; int64_t pos; + ffio_ensure_seekback(pb, s->probesize); + /* read the first 8192 bytes to get packet size */ pos = avio_tell(pb); len = avio_read(pb, buf, sizeof(buf)); @@ -2009,11 +2209,7 @@ static int mpegts_read_header(AVFormatContext *s) /* normal demux */ /* first do a scan to get all the services */ - /* NOTE: We attempt to seek on non-seekable files as well, as the - * probe buffer usually is big enough. Only warn if the seek failed - * on files where the seek should work. */ - if (avio_seek(pb, pos, SEEK_SET) < 0) - av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n"); + seek_back(s, pb, pos); mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); @@ -2033,6 +2229,7 @@ static int mpegts_read_header(AVFormatContext *s) int64_t pcrs[2], pcr_h; int packet_count[2]; uint8_t packet[TS_PACKET_SIZE]; + const uint8_t *data; /* only read packets */ @@ -2048,18 +2245,21 @@ static int mpegts_read_header(AVFormatContext *s) nb_pcrs = 0; nb_packets = 0; for(;;) { - ret = read_packet(s, packet, ts->raw_packet_size); + ret = read_packet(s, packet, ts->raw_packet_size, &data); if (ret < 0) - return -1; - pid = AV_RB16(packet + 1) & 0x1fff; + goto fail; + pid = AV_RB16(data + 1) & 0x1fff; if ((pcr_pid == -1 || pcr_pid == pid) && - parse_pcr(&pcr_h, &pcr_l, packet) == 0) { + parse_pcr(&pcr_h, &pcr_l, data) == 0) { + finished_reading_packet(s, ts->raw_packet_size); pcr_pid = pid; packet_count[nb_pcrs] = nb_packets; pcrs[nb_pcrs] = pcr_h * 300 + pcr_l; nb_pcrs++; if (nb_pcrs >= 2) break; + } else { + finished_reading_packet(s, ts->raw_packet_size); } nb_packets++; } @@ -2075,7 +2275,7 @@ static int mpegts_read_header(AVFormatContext *s) st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr); } - avio_seek(pb, pos, SEEK_SET); + seek_back(s, pb, pos); return 0; fail: return -1; @@ -2091,15 +2291,19 @@ static int mpegts_raw_read_packet(AVFormatContext *s, int64_t pcr_h, next_pcr_h, pos; int pcr_l, next_pcr_l; uint8_t pcr_buf[12]; + const uint8_t *data; if (av_new_packet(pkt, TS_PACKET_SIZE) < 0) return AVERROR(ENOMEM); pkt->pos= avio_tell(s->pb); - ret = read_packet(s, pkt->data, ts->raw_packet_size); + ret = read_packet(s, pkt->data, ts->raw_packet_size, &data); if (ret < 0) { av_free_packet(pkt); return ret; } + if (data != pkt->data) + memcpy(pkt->data, data, ts->raw_packet_size); + finished_reading_packet(s, ts->raw_packet_size); if (ts->mpeg2ts_compute_pcr) { /* compute exact PCR for each packet */ if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) { @@ -2181,13 +2385,15 @@ static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, int64_t pos, timestamp; uint8_t buf[TS_PACKET_SIZE]; int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid; - pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47; + int pos47 = ts->pos47_full % ts->raw_packet_size; + pos = ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * ts->raw_packet_size + pos47; while(pos < pos_limit) { if (avio_seek(s->pb, pos, SEEK_SET) < 0) return AV_NOPTS_VALUE; if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) return AV_NOPTS_VALUE; if (buf[0] != 0x47) { + avio_seek(s->pb, -TS_PACKET_SIZE, SEEK_CUR); if (mpegts_resync(s) < 0) return AV_NOPTS_VALUE; pos = avio_tell(s->pb); @@ -2209,7 +2415,8 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index, { MpegTSContext *ts = s->priv_data; int64_t pos; - pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47; + int pos47 = ts->pos47_full % ts->raw_packet_size; + pos = ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * ts->raw_packet_size + pos47; ff_read_frame_flush(s); if (avio_seek(s->pb, pos, SEEK_SET) < 0) return AV_NOPTS_VALUE; @@ -2224,7 +2431,7 @@ static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index, if(pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0){ ff_reduce_index(s, pkt.stream_index); av_add_index_entry(s->streams[pkt.stream_index], pkt.pos, pkt.dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */); - if(pkt.stream_index == stream_index){ + if(pkt.stream_index == stream_index && pkt.pos >= *ppos){ *ppos= pkt.pos; return pkt.dts; } @@ -2298,6 +2505,7 @@ AVInputFormat ff_mpegts_demuxer = { .read_close = mpegts_read_close, .read_timestamp = mpegts_get_dts, .flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT, + .priv_class = &mpegts_class, }; AVInputFormat ff_mpegtsraw_demuxer = { diff --git a/ffmpeg/libavformat/mpegtsenc.c b/ffmpeg/libavformat/mpegtsenc.c index 7016774..1d51b97 100644 --- a/ffmpeg/libavformat/mpegtsenc.c +++ b/ffmpeg/libavformat/mpegtsenc.c @@ -22,10 +22,11 @@ #include "libavutil/bswap.h" #include "libavutil/crc.h" #include "libavutil/dict.h" +#include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" -#include "libavcodec/mpegvideo.h" +#include "libavcodec/internal.h" #include "avformat.h" #include "internal.h" #include "mpegts.h" @@ -84,6 +85,7 @@ typedef struct MpegTSWrite { #define MPEGTS_FLAG_AAC_LATM 0x02 int flags; int copyts; + int tables_version; } MpegTSWrite; /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */ @@ -118,8 +120,10 @@ static const AVOption options[] = { // backward compatibility { "resend_headers", "Reemit PAT/PMT before writing the next packet", offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, - { "mpegts_copyts", "dont offset dts/pts", + { "mpegts_copyts", "don't offset dts/pts", offsetof(MpegTSWrite, copyts), AV_OPT_TYPE_INT, {.i64=-1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM}, + { "tables_version", "set PAT, PMT and SDT version", + offsetof(MpegTSWrite, tables_version), AV_OPT_TYPE_INT, {.i64=0}, 0, 31, AV_OPT_FLAG_ENCODING_PARAM}, { NULL }, }; @@ -251,7 +255,7 @@ static void mpegts_write_pat(AVFormatContext *s) put16(&q, service->sid); put16(&q, 0xe000 | service->pmt.pid); } - mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, 0, 0, 0, + mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, ts->tables_version, 0, 0, data, q - data); } @@ -396,13 +400,23 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) *q++ = 'c'; } break; + case AVMEDIA_TYPE_DATA: + if (st->codec->codec_id == AV_CODEC_ID_SMPTE_KLV) { + *q++ = 0x05; /* MPEG-2 registration descriptor */ + *q++ = 4; + *q++ = 'K'; + *q++ = 'L'; + *q++ = 'V'; + *q++ = 'A'; + } + break; } val = 0xf000 | (q - desc_length_ptr - 2); desc_length_ptr[0] = val >> 8; desc_length_ptr[1] = val; } - mpegts_write_section1(&service->pmt, PMT_TID, service->sid, 0, 0, 0, + mpegts_write_section1(&service->pmt, PMT_TID, service->sid, ts->tables_version, 0, 0, data, q - data); } @@ -457,7 +471,7 @@ static void mpegts_write_sdt(AVFormatContext *s) desc_list_len_ptr[0] = val >> 8; desc_list_len_ptr[1] = val; } - mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, 0, 0, 0, + mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, ts->tables_version, 0, 0, data, q - data); } @@ -976,8 +990,8 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, *q++ = len >> 8; *q++ = len; val = 0x80; - /* data alignment indicator is required for subtitle data */ - if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) + /* data alignment indicator is required for subtitle and data streams */ + if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codec->codec_type == AVMEDIA_TYPE_DATA) val |= 0x04; *q++ = val; *q++ = flags; @@ -1094,13 +1108,16 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) uint32_t state = -1; if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) { + if (!st->nb_frames) { av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, " "no startcode found, use the h264_mp4toannexb bitstream filter (-bsf h264_mp4toannexb)\n"); return AVERROR(EINVAL); + } + av_log(s, AV_LOG_WARNING, "H.264 bitstream error, startcode missing\n"); } do { - p = avpriv_mpv_find_start_code(p, buf_end, &state); + p = avpriv_find_start_code(p, buf_end, &state); av_dlog(s, "nal %d\n", state & 0x1f); } while (p < buf_end && (state & 0x1f) != 9 && (state & 0x1f) != 5 && (state & 0x1f) != 1); diff --git a/ffmpeg/libavformat/mpegvideodec.c b/ffmpeg/libavformat/mpegvideodec.c index 471d2f4..ade76d8 100644 --- a/ffmpeg/libavformat/mpegvideodec.c +++ b/ffmpeg/libavformat/mpegvideodec.c @@ -23,6 +23,8 @@ #include "avformat.h" #include "rawdec.h" +#include "libavutil/intreadwrite.h" + #define SEQ_START_CODE 0x000001b3 #define GOP_START_CODE 0x000001b8 #define PICTURE_START_CODE 0x00000100 @@ -35,14 +37,29 @@ static int mpegvideo_probe(AVProbeData *p) { uint32_t code= -1; int pic=0, seq=0, slice=0, pspack=0, vpes=0, apes=0, res=0, sicle=0; - int i; + int i, j; uint32_t last = 0; for(i=0; i<p->buf_size; i++){ code = (code<<8) + p->buf[i]; if ((code & 0xffffff00) == 0x100) { switch(code){ - case SEQ_START_CODE: seq++; break; + case SEQ_START_CODE: + if (!(p->buf[i+1+3+1+2] & 0x20)) + break; + j = i; + if (p->buf[j+8] & 2) + j+= 64; + if (j >= p->buf_size) + break; + if (p->buf[j+8] & 1) + j+= 64; + if (j >= p->buf_size) + break; + if (AV_RB24(p->buf + j + 9) & 0xFFFFFE) + break; + seq++; + break; case PICTURE_START_CODE: pic++; break; case PACK_START_CODE: pspack++; break; case 0x1b6: @@ -63,8 +80,8 @@ static int mpegvideo_probe(AVProbeData *p) } } if(seq && seq*9<=pic*10 && pic*9<=slice*10 && !pspack && !apes && !res && slice > sicle) { - if(vpes) return AVPROBE_SCORE_MAX/8; - else return pic>1 ? AVPROBE_SCORE_MAX/2+1 : AVPROBE_SCORE_MAX/4; // +1 for .mpg + if(vpes) return AVPROBE_SCORE_EXTENSION / 4; + else return pic>1 ? AVPROBE_SCORE_EXTENSION + 1 : AVPROBE_SCORE_EXTENSION / 2; // +1 for .mpg } return 0; } diff --git a/ffmpeg/libavformat/mpjpeg.c b/ffmpeg/libavformat/mpjpeg.c index 916938f..2586ea8 100644 --- a/ffmpeg/libavformat/mpjpeg.c +++ b/ffmpeg/libavformat/mpjpeg.c @@ -47,7 +47,6 @@ static int mpjpeg_write_packet(AVFormatContext *s, AVPacket *pkt) snprintf(buf1, sizeof(buf1), "\r\n--%s\r\n", BOUNDARY_TAG); avio_write(s->pb, buf1, strlen(buf1)); - avio_flush(s->pb); return 0; } diff --git a/ffmpeg/libavformat/mpl2dec.c b/ffmpeg/libavformat/mpl2dec.c index ce2061b..17b302d 100644 --- a/ffmpeg/libavformat/mpl2dec.c +++ b/ffmpeg/libavformat/mpl2dec.c @@ -40,10 +40,10 @@ static int mpl2_probe(AVProbeData *p) const unsigned char *ptr_end = ptr + p->buf_size; for (i = 0; i < 2; i++) { - if (sscanf(ptr, "[%"PRId64"][%"PRId64"]%c", &start, &end, &c) != 3 && - sscanf(ptr, "[%"PRId64"][]%c", &start, &c) != 2) + if (sscanf(ptr, "[%"SCNd64"][%"SCNd64"]%c", &start, &end, &c) != 3 && + sscanf(ptr, "[%"SCNd64"][]%c", &start, &c) != 2) return 0; - ptr += strcspn(ptr, "\r\n") + 1; + ptr += ff_subtitles_next_line(ptr); if (ptr >= ptr_end) return 0; } @@ -56,13 +56,13 @@ static int read_ts(char **line, int64_t *pts_start, int *duration) int len; int64_t end; - if (sscanf(*line, "[%"PRId64"][]%c%n", + if (sscanf(*line, "[%"SCNd64"][]%c%n", pts_start, &c, &len) >= 2) { *duration = -1; *line += len - 1; return 0; } - if (sscanf(*line, "[%"PRId64"][%"PRId64"]%c%n", + if (sscanf(*line, "[%"SCNd64"][%"SCNd64"]%c%n", pts_start, &end, &c, &len) >= 3) { *duration = end - *pts_start; *line += len - 1; diff --git a/ffmpeg/libavformat/mpsubdec.c b/ffmpeg/libavformat/mpsubdec.c index 2acafaa..c5bdcdb 100644 --- a/ffmpeg/libavformat/mpsubdec.c +++ b/ffmpeg/libavformat/mpsubdec.c @@ -37,12 +37,16 @@ static int mpsub_probe(AVProbeData *p) const char *ptr_end = p->buf + p->buf_size; while (ptr < ptr_end) { - int n; - - if (!memcmp(ptr, "FORMAT=TIME", 11) || - sscanf(ptr, "FORMAT=%d", &n) == 1) - return AVPROBE_SCORE_MAX/2; - ptr += strcspn(ptr, "\n") + 1; + int inc; + + if (!memcmp(ptr, "FORMAT=TIME", 11)) + return AVPROBE_SCORE_EXTENSION; + if (!memcmp(ptr, "FORMAT=", 7)) + return AVPROBE_SCORE_EXTENSION / 3; + inc = ff_subtitles_next_line(ptr); + if (!inc) + break; + ptr += inc; } return 0; } diff --git a/ffmpeg/libavformat/mtv.c b/ffmpeg/libavformat/mtv.c index 6ffbb51..0517dd2 100644 --- a/ffmpeg/libavformat/mtv.c +++ b/ffmpeg/libavformat/mtv.c @@ -42,10 +42,10 @@ typedef struct MTVDemuxContext { unsigned int audio_br; ///< bitrate of audio channel (mp3) unsigned int img_colorfmt; ///< frame colorfmt rgb 565/555 unsigned int img_bpp; ///< frame bits per pixel - unsigned int img_width; // - unsigned int img_height; // + unsigned int img_width; + unsigned int img_height; unsigned int img_segment_size; ///< size of image segment - unsigned int video_fps; // + unsigned int video_fps; unsigned int full_segment_size; } MTVDemuxContext; @@ -64,13 +64,13 @@ static int mtv_probe(AVProbeData *p) if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54])) { if(!!AV_RL16(&p->buf[56])) - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; else return 0; } if(p->buf[51] != 16) - return AVPROBE_SCORE_MAX/4; // But we are going to assume 16bpp anyway .. + return AVPROBE_SCORE_EXTENSION / 2; // But we are going to assume 16bpp anyway .. return AVPROBE_SCORE_MAX; } @@ -105,8 +105,8 @@ static int mtv_read_header(AVFormatContext *s) mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3) / mtv->img_width; } - if(!mtv->img_height || !mtv->img_width){ - av_log(s, AV_LOG_ERROR, "width or height is invalid and I cannot calculate them from other information\n"); + if(!mtv->img_height || !mtv->img_width || !mtv->img_segment_size){ + av_log(s, AV_LOG_ERROR, "width or height or segment_size is invalid and I cannot calculate them from other information\n"); return AVERROR(EINVAL); } diff --git a/ffmpeg/libavformat/mux.c b/ffmpeg/libavformat/mux.c index 3578a52..f01b82b 100644 --- a/ffmpeg/libavformat/mux.c +++ b/ffmpeg/libavformat/mux.c @@ -19,8 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* #define DEBUG */ - #include "avformat.h" #include "avio_internal.h" #include "internal.h" @@ -34,6 +32,7 @@ #include "id3v2.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/internal.h" #include "libavutil/mathematics.h" #include "libavutil/parseutils.h" #include "libavutil/time.h" @@ -238,7 +237,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) // some sanity checks if (s->nb_streams == 0 && !(of->flags & AVFMT_NOSTREAMS)) { - av_log(s, AV_LOG_ERROR, "no streams\n"); + av_log(s, AV_LOG_ERROR, "No streams to mux were specified\n"); ret = AVERROR(EINVAL); goto fail; } @@ -275,13 +274,18 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) if (av_cmp_q(st->sample_aspect_ratio, codec->sample_aspect_ratio) && FFABS(av_q2d(st->sample_aspect_ratio) - av_q2d(codec->sample_aspect_ratio)) > 0.004*av_q2d(st->sample_aspect_ratio) ) { - av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between muxer " - "(%d/%d) and encoder layer (%d/%d)\n", - st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, - codec->sample_aspect_ratio.num, - codec->sample_aspect_ratio.den); - ret = AVERROR(EINVAL); - goto fail; + if (st->sample_aspect_ratio.num != 0 && + st->sample_aspect_ratio.den != 0 && + codec->sample_aspect_ratio.den != 0 && + codec->sample_aspect_ratio.den != 0) { + av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between muxer " + "(%d/%d) and encoder layer (%d/%d)\n", + st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, + codec->sample_aspect_ratio.num, + codec->sample_aspect_ratio.den); + ret = AVERROR(EINVAL); + goto fail; + } } break; } @@ -298,12 +302,12 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) } if (codec->codec_tag) { if (!validate_codec_tag(s, st)) { - char tagbuf[32], cortag[32]; + char tagbuf[32], tagbuf2[32]; av_get_codec_tag_string(tagbuf, sizeof(tagbuf), codec->codec_tag); - av_get_codec_tag_string(cortag, sizeof(cortag), av_codec_get_tag(s->oformat->codec_tag, codec->codec_id)); + av_get_codec_tag_string(tagbuf2, sizeof(tagbuf2), av_codec_get_tag(s->oformat->codec_tag, codec->codec_id)); av_log(s, AV_LOG_ERROR, "Tag %s/0x%08x incompatible with output codec id '%d' (%s)\n", - tagbuf, codec->codec_tag, codec->codec_id, cortag); + tagbuf, codec->codec_tag, codec->codec_id, tagbuf2); ret = AVERROR_INVALIDDATA; goto fail; } @@ -335,6 +339,8 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) /* set muxer identification string */ if (s->nb_streams && !(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { av_dict_set(&s->metadata, "encoder", LIBAVFORMAT_IDENT, 0); + } else { + av_dict_set(&s->metadata, "encoder", NULL, 0); } if (options) { @@ -398,6 +404,13 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) if ((ret = init_pts(s)) < 0) return ret; + if (s->avoid_negative_ts < 0) { + if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { + s->avoid_negative_ts = 0; + } else + s->avoid_negative_ts = 1; + } + return 0; } @@ -485,17 +498,52 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) } /** - * Move side data from payload to internal struct, call muxer, and restore - * original packet. + * Make timestamps non negative, move side data from payload to internal struct, call muxer, and restore + * sidedata. + * + * FIXME: this function should NEVER get undefined pts/dts beside when the + * AVFMT_NOTIMESTAMPS is set. + * Those additional safety checks should be dropped once the correct checks + * are set in the callers. */ -static inline int split_write_packet(AVFormatContext *s, AVPacket *pkt) +static int write_packet(AVFormatContext *s, AVPacket *pkt) { int ret, did_split; + if (s->avoid_negative_ts > 0) { + AVStream *st = s->streams[pkt->stream_index]; + int64_t offset = st->mux_ts_offset; + + if (pkt->dts < 0 && pkt->dts != AV_NOPTS_VALUE && !s->offset) { + s->offset = -pkt->dts; + s->offset_timebase = st->time_base; + } + + if (s->offset && !offset) { + offset = st->mux_ts_offset = + av_rescale_q_rnd(s->offset, + s->offset_timebase, + st->time_base, + AV_ROUND_UP); + } + + if (pkt->dts != AV_NOPTS_VALUE) + pkt->dts += offset; + if (pkt->pts != AV_NOPTS_VALUE) + pkt->pts += offset; + + av_assert2(pkt->dts == AV_NOPTS_VALUE || pkt->dts >= 0); + } + did_split = av_packet_split_side_data(pkt); ret = s->oformat->write_packet(s, pkt); + + if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) + avio_flush(s->pb); + if (did_split) av_packet_merge_side_data(pkt); + return ret; } @@ -506,6 +554,8 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) if (!pkt) { if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { ret = s->oformat->write_packet(s, NULL); + if (s->flush_packets && s->pb && s->pb->error >= 0) + avio_flush(s->pb); if (ret >= 0 && s->pb && s->pb->error < 0) ret = s->pb->error; return ret; @@ -518,7 +568,7 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) return ret; - ret = split_write_packet(s, pkt); + ret = write_packet(s, pkt); if (ret >= 0 && s->pb && s->pb->error < 0) ret = s->pb->error; @@ -541,10 +591,13 @@ int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, return AVERROR(ENOMEM); this_pktl->pkt = *pkt; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS pkt->destruct = NULL; // do not free original but only the copy +FF_ENABLE_DEPRECATION_WARNINGS #endif pkt->buf = NULL; av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-allocated memory + av_copy_packet_side_data(&this_pktl->pkt, &this_pktl->pkt); // copy side data if (s->streams[pkt->stream_index]->last_in_packet_buffer) { next_point = &(st->last_in_packet_buffer->next); @@ -596,7 +649,8 @@ next_non_null: return 0; } -static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacket *pkt) +static int interleave_compare_dts(AVFormatContext *s, AVPacket *next, + AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; AVStream *st2 = s->streams[next->stream_index]; @@ -627,7 +681,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, int i, ret; if (pkt) { - ret = ff_interleave_add_packet(s, pkt, ff_interleave_compare_dts); + ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts); if (ret < 0) return ret; } @@ -675,23 +729,6 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, st->last_in_packet_buffer = NULL; av_freep(&pktl); - if (s->avoid_negative_ts > 0) { - if (out->dts != AV_NOPTS_VALUE) { - if (!st->mux_ts_offset && out->dts < 0) { - for (i = 0; i < s->nb_streams; i++) { - s->streams[i]->mux_ts_offset = - av_rescale_q_rnd(-out->dts, - st->time_base, - s->streams[i]->time_base, - AV_ROUND_UP); - } - } - out->dts += st->mux_ts_offset; - } - if (out->pts != AV_NOPTS_VALUE) - out->pts += st->mux_ts_offset; - } - return 1; } else { av_init_packet(out); @@ -748,7 +785,7 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) if (ret <= 0) //FIXME cleanup needed for ret<0 ? return ret; - ret = split_write_packet(s, &opkt); + ret = write_packet(s, &opkt); if (ret >= 0) s->streams[opkt.stream_index]->nb_frames++; @@ -774,7 +811,7 @@ int av_write_trailer(AVFormatContext *s) if (!ret) break; - ret = split_write_packet(s, &pkt); + ret = write_packet(s, &pkt); if (ret >= 0) s->streams[pkt.stream_index]->nb_frames++; @@ -812,3 +849,25 @@ int av_get_output_timestamp(struct AVFormatContext *s, int stream, s->oformat->get_output_timestamp(s, stream, dts, wall); return 0; } + +int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, + AVFormatContext *src) +{ + AVPacket local_pkt; + + local_pkt = *pkt; + local_pkt.stream_index = dst_stream; + if (pkt->pts != AV_NOPTS_VALUE) + local_pkt.pts = av_rescale_q(pkt->pts, + src->streams[pkt->stream_index]->time_base, + dst->streams[dst_stream]->time_base); + if (pkt->dts != AV_NOPTS_VALUE) + local_pkt.dts = av_rescale_q(pkt->dts, + src->streams[pkt->stream_index]->time_base, + dst->streams[dst_stream]->time_base); + if (pkt->duration) + local_pkt.duration = av_rescale_q(pkt->duration, + src->streams[pkt->stream_index]->time_base, + dst->streams[dst_stream]->time_base); + return av_write_frame(dst, &local_pkt); +} diff --git a/ffmpeg/libavformat/mvi.c b/ffmpeg/libavformat/mvi.c index 953c182..5efc443 100644 --- a/ffmpeg/libavformat/mvi.c +++ b/ffmpeg/libavformat/mvi.c @@ -52,9 +52,7 @@ static int read_header(AVFormatContext *s) if (!vst) return AVERROR(ENOMEM); - vst->codec->extradata_size = 2; - vst->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!vst->codec->extradata) + if (ff_alloc_extradata(vst->codec, 2)) return AVERROR(ENOMEM); version = avio_r8(pb); @@ -96,10 +94,12 @@ static int read_header(AVFormatContext *s) mvi->get_int = (vst->codec->width * vst->codec->height < (1 << 16)) ? avio_rl16 : avio_rl24; mvi->audio_frame_size = ((uint64_t)mvi->audio_data_size << MVI_FRAC_BITS) / frames_count; - if (!mvi->audio_frame_size) { - av_log(s, AV_LOG_ERROR, "audio_frame_size is 0\n"); + if (mvi->audio_frame_size <= 1 << MVI_FRAC_BITS - 1) { + av_log(s, AV_LOG_ERROR, "Invalid audio_data_size (%d) or frames_count (%d)\n", + mvi->audio_data_size, frames_count); return AVERROR_INVALIDDATA; } + mvi->audio_size_counter = (ast->codec->sample_rate * 830 / mvi->audio_frame_size - 1) * mvi->audio_frame_size; mvi->audio_size_left = mvi->audio_data_size; diff --git a/ffmpeg/libavformat/mxfdec.c b/ffmpeg/libavformat/mxfdec.c index 4580e1b..61c0cb2 100644 --- a/ffmpeg/libavformat/mxfdec.c +++ b/ffmpeg/libavformat/mxfdec.c @@ -43,12 +43,13 @@ * Only tracks with associated descriptors will be decoded. "Highly Desirable" SMPTE 377M D.1 */ -//#define DEBUG +#include <stdint.h> #include "libavutil/aes.h" #include "libavutil/avassert.h" #include "libavutil/mathematics.h" #include "libavcodec/bytestream.h" +#include "libavutil/intreadwrite.h" #include "libavutil/timecode.h" #include "avformat.h" #include "internal.h" @@ -215,6 +216,7 @@ typedef struct { struct AVAES *aesc; uint8_t *local_tags; int local_tags_count; + uint64_t last_partition; uint64_t footer_partition; KLVPacket current_klv_data; int current_klv_index; @@ -256,6 +258,7 @@ static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 }; static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }; +static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x11,0x01,0x00 }; static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 }; #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y))) @@ -435,10 +438,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size uint64_t footer_partition; uint32_t nb_essence_containers; - if (mxf->partitions_count+1 >= UINT_MAX / sizeof(*mxf->partitions)) - return AVERROR(ENOMEM); - - tmp_part = av_realloc(mxf->partitions, (mxf->partitions_count + 1) * sizeof(*mxf->partitions)); + tmp_part = av_realloc_array(mxf->partitions, mxf->partitions_count + 1, sizeof(*mxf->partitions)); if (!tmp_part) return AVERROR(ENOMEM); mxf->partitions = tmp_part; @@ -565,9 +565,8 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set) { MXFMetadataSet **tmp; - if (mxf->metadata_sets_count+1 >= UINT_MAX / sizeof(*mxf->metadata_sets)) - return AVERROR(ENOMEM); - tmp = av_realloc(mxf->metadata_sets, (mxf->metadata_sets_count + 1) * sizeof(*mxf->metadata_sets)); + + tmp = av_realloc_array(mxf->metadata_sets, mxf->metadata_sets_count + 1, sizeof(*mxf->metadata_sets)); if (!tmp) return AVERROR(ENOMEM); mxf->metadata_sets = tmp; @@ -941,6 +940,7 @@ static const MXFCodecUL mxf_intra_only_essence_container_uls[] = { /* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */ static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra Profiles */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; @@ -1518,6 +1518,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) av_log(mxf->fc, AV_LOG_VERBOSE, "."); } av_log(mxf->fc, AV_LOG_VERBOSE, "\n"); + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { source_track->intra_only = mxf_is_intra_only(descriptor); container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul); @@ -1574,11 +1575,13 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->bits_per_coded_sample = descriptor->bits_per_sample; if (descriptor->sample_rate.den > 0) { - avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num); st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den; + avpriv_set_pts_info(st, 64, descriptor->sample_rate.den, descriptor->sample_rate.num); } else { - av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) found for stream #%d, time base forced to 1/48000\n", - descriptor->sample_rate.num, descriptor->sample_rate.den, st->index); + av_log(mxf->fc, AV_LOG_WARNING, "invalid sample rate (%d/%d) " + "found for stream #%d, time base forced to 1/48000\n", + descriptor->sample_rate.num, descriptor->sample_rate.den, + st->index); avpriv_set_pts_info(st, 64, 1, 48000); } @@ -1602,11 +1605,13 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } if (descriptor->extradata) { - st->codec->extradata = av_mallocz(descriptor->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (st->codec->extradata) + if (!ff_alloc_extradata(st->codec, descriptor->extradata_size)) { memcpy(st->codec->extradata, descriptor->extradata, descriptor->extradata_size); - } else if(st->codec->codec_id == AV_CODEC_ID_H264) { - ff_generate_avci_extradata(st); + } + } else if (st->codec->codec_id == AV_CODEC_ID_H264) { + ret = ff_generate_avci_extradata(st); + if (ret < 0) + return ret; } if (st->codec->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) { /* TODO: decode timestamps */ @@ -1619,6 +1624,124 @@ fail_and_free: return ret; } +static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str) +{ + int ret; + size_t buf_size; + + if (size < 0) + return AVERROR(EINVAL); + + buf_size = size + size/2 + 1; + *str = av_malloc(buf_size); + if (!*str) + return AVERROR(ENOMEM); + + if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) { + av_freep(str); + return ret; + } + + return ret; +} + +static int mxf_uid_to_str(UID uid, char **str) +{ + int i; + char *p; + p = *str = av_mallocz(sizeof(UID) * 2 + 4 + 1); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < sizeof(UID); i++) { + snprintf(p, 2 + 1, "%.2x", uid[i]); + p += 2; + if (i == 3 || i == 5 || i == 7 || i == 9) { + snprintf(p, 1 + 1, "-"); + p++; + } + } + return 0; +} + +static int mxf_timestamp_to_str(uint64_t timestamp, char **str) +{ + struct tm time = {0}; + time.tm_year = (timestamp >> 48) - 1900; + time.tm_mon = (timestamp >> 40 & 0xFF) - 1; + time.tm_mday = (timestamp >> 32 & 0xFF); + time.tm_hour = (timestamp >> 24 & 0xFF); + time.tm_min = (timestamp >> 16 & 0xFF); + time.tm_sec = (timestamp >> 8 & 0xFF); + + /* ensure month/day are valid */ + time.tm_mon = FFMAX(time.tm_mon, 0); + time.tm_mday = FFMAX(time.tm_mday, 1); + + *str = av_mallocz(32); + if (!*str) + return AVERROR(ENOMEM); + strftime(*str, 32, "%Y-%m-%d %H:%M:%S", &time); + + return 0; +} + +#define SET_STR_METADATA(pb, name, str) do { \ + if ((ret = mxf_read_utf16_string(pb, size, &str)) < 0) \ + return ret; \ + av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \ +} while (0) + +#define SET_UID_METADATA(pb, name, var, str) do { \ + avio_read(pb, var, 16); \ + if ((ret = mxf_uid_to_str(var, &str)) < 0) \ + return ret; \ + av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \ +} while (0) + +#define SET_TS_METADATA(pb, name, var, str) do { \ + var = avio_rb64(pb); \ + if ((ret = mxf_timestamp_to_str(var, &str)) < 0) \ + return ret; \ + av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \ +} while (0) + +static int mxf_read_identification_metadata(void *arg, AVIOContext *pb, int tag, int size, UID _uid, int64_t klv_offset) +{ + MXFContext *mxf = arg; + AVFormatContext *s = mxf->fc; + int ret; + UID uid = { 0 }; + char *str = NULL; + uint64_t ts; + switch (tag) { + case 0x3C01: + SET_STR_METADATA(pb, "company_name", str); + break; + case 0x3C02: + SET_STR_METADATA(pb, "product_name", str); + break; + case 0x3C04: + SET_STR_METADATA(pb, "product_version", str); + break; + case 0x3C05: + SET_UID_METADATA(pb, "product_uid", uid, str); + break; + case 0x3C06: + SET_TS_METADATA(pb, "modification_date", ts, str); + break; + case 0x3C08: + SET_STR_METADATA(pb, "application_platform", str); + break; + case 0x3C09: + SET_UID_METADATA(pb, "generation_uid", uid, str); + break; + case 0x3C0A: + SET_UID_METADATA(pb, "uid", uid, str); + break; + } + return 0; +} + static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack }, { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, mxf_read_partition_pack }, @@ -1631,6 +1754,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x04,0x00 }, mxf_read_partition_pack }, { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x02,0x00 }, mxf_read_partition_pack }, { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }, mxf_read_partition_pack }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x30,0x00 }, mxf_read_identification_metadata }, { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType }, { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage }, { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage }, @@ -1736,31 +1860,33 @@ static int mxf_parse_handle_essence(MXFContext *mxf) if (mxf->parsing_backward) { return mxf_seek_to_previous_partition(mxf); - } else { - if (!mxf->footer_partition) { - av_dlog(mxf->fc, "no footer\n"); - return 0; - } + } else if (mxf->footer_partition || mxf->last_partition){ + uint64_t offset; - av_dlog(mxf->fc, "seeking to footer\n"); + offset = mxf->footer_partition ? mxf->footer_partition : mxf->last_partition; + + av_dlog(mxf->fc, "seeking to last partition\n"); /* remember where we were so we don't end up seeking further back than this */ mxf->last_forward_tell = avio_tell(pb); if (!pb->seekable) { - av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing footer\n"); + av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n"); return -1; } - /* seek to footer partition and parse backward */ - if ((ret = avio_seek(pb, mxf->run_in + mxf->footer_partition, SEEK_SET)) < 0) { - av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to footer @ 0x%"PRIx64" (%"PRId64") - partial file?\n", - mxf->run_in + mxf->footer_partition, ret); + /* seek to last partition and parse backward */ + if ((ret = avio_seek(pb, mxf->run_in + offset, SEEK_SET)) < 0) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to seek to last partition @ 0x%"PRIx64" (%"PRId64") - partial file?\n", + mxf->run_in + offset, ret); return ret; } mxf->current_partition = NULL; mxf->parsing_backward = 1; + } else { + av_dlog(mxf->fc, "can't find last partition\n"); + return 0; } return 1; @@ -1852,6 +1978,34 @@ static void mxf_handle_small_eubc(AVFormatContext *s) mxf->edit_units_per_packet = 1920; } +static void mxf_read_random_index_pack(AVFormatContext *s) +{ + MXFContext *mxf = s->priv_data; + uint32_t length; + int64_t file_size; + KLVPacket klv; + + if (!s->pb->seekable) + return; + + file_size = avio_size(s->pb); + avio_seek(s->pb, file_size - 4, SEEK_SET); + length = avio_rb32(s->pb); + if (length <= 32 || length >= FFMIN(file_size, INT_MAX)) + goto end; + avio_seek(s->pb, file_size - length, SEEK_SET); + if (klv_read_packet(&klv, s->pb) < 0 || + !IS_KLV_KEY(klv.key, mxf_random_index_pack_key) || + klv.length != length - 20) + goto end; + + avio_skip(s->pb, klv.length - 12); + mxf->last_partition = avio_rb64(s->pb); + +end: + avio_seek(s->pb, mxf->run_in, SEEK_SET); +} + static int mxf_read_header(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -1870,6 +2024,8 @@ static int mxf_read_header(AVFormatContext *s) mxf->fc = s; mxf->run_in = avio_tell(s->pb); + mxf_read_random_index_pack(s); + while (!url_feof(s->pb)) { const MXFMetadataReadTableEntry *metadata; @@ -2080,7 +2236,9 @@ static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec, AVPacket *p { MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data; pkt->pts = track->sample_count; - if (codec->channels <= 0 || av_get_bits_per_sample(codec->codec_id) <= 0) + if ( codec->channels <= 0 + || av_get_bits_per_sample(codec->codec_id) <= 0 + || codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) < 8) return AVERROR(EINVAL); track->sample_count += pkt->size / (codec->channels * (int64_t)av_get_bits_per_sample(codec->codec_id) / 8); return 0; @@ -2091,10 +2249,8 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) KLVPacket klv; MXFContext *mxf = s->priv_data; - while (!url_feof(s->pb)) { + while (klv_read_packet(&klv, s->pb) == 0) { int ret; - if (klv_read_packet(&klv, s->pb) < 0) - return -1; PRINT_KEY(s, "read packet", klv.key); av_dlog(s, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { @@ -2179,7 +2335,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) skip: avio_skip(s->pb, klv.length); } - return AVERROR_EOF; + return url_feof(s->pb) ? AVERROR_EOF : -1; } static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -2306,10 +2462,19 @@ static int mxf_probe(AVProbeData *p) { /* Must skip Run-In Sequence and search for MXF header partition pack key SMPTE 377M 5.5 */ end -= sizeof(mxf_header_partition_pack_key); - for (; bufp < end; bufp++) { - if (IS_KLV_KEY(bufp, mxf_header_partition_pack_key)) - return AVPROBE_SCORE_MAX; + + for (; bufp < end;) { + if (!((bufp[13] - 1) & 0xF2)){ + if (AV_RN32(bufp ) == AV_RN32(mxf_header_partition_pack_key ) && + AV_RN32(bufp+ 4) == AV_RN32(mxf_header_partition_pack_key+ 4) && + AV_RN32(bufp+ 8) == AV_RN32(mxf_header_partition_pack_key+ 8) && + AV_RN16(bufp+12) == AV_RN16(mxf_header_partition_pack_key+12)) + return AVPROBE_SCORE_MAX; + bufp ++; + } else + bufp += 10; } + return 0; } @@ -2322,6 +2487,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti MXFContext* mxf = s->priv_data; int64_t seekpos; int i, ret; + int64_t ret64; MXFIndexTable *t; MXFTrack *source_track = st->priv_data; @@ -2336,9 +2502,10 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti sample_time = 0; seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den); - if ((ret = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0) - return ret; + if ((ret64 = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET)) < 0) + return ret64; ff_update_cur_dts(s, st, sample_time); + mxf->current_edit_unit = sample_time; } else { t = &mxf->index_tables[0]; diff --git a/ffmpeg/libavformat/mxfenc.c b/ffmpeg/libavformat/mxfenc.c index cf9b77d..5e77a3f 100644 --- a/ffmpeg/libavformat/mxfenc.c +++ b/ffmpeg/libavformat/mxfenc.c @@ -30,8 +30,7 @@ * SMPTE RP224: Registry of SMPTE Universal Labels */ -//#define DEBUG - +#include <inttypes.h> #include <math.h> #include <time.h> @@ -43,6 +42,7 @@ #include "libavcodec/dnxhddata.h" #include "audiointerleave.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "mxf.h" #include "config.h" @@ -76,6 +76,7 @@ typedef struct { int temporal_reordering; AVRational aspect_ratio; ///< display aspect ratio int closed_gop; ///< gop is closed, used in mpeg-2 frame parsing + int video_bit_rate; } MXFStreamContext; typedef struct { @@ -976,13 +977,14 @@ static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st) static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st) { AVIOContext *pb = s->pb; + MXFStreamContext *sc = st->priv_data; int profile_and_level = (st->codec->profile<<4) | st->codec->level; mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5); // bit rate mxf_write_local_tag(pb, 4, 0x8000); - avio_wb32(pb, st->codec->bit_rate); + avio_wb32(pb, sc->video_bit_rate); // profile and level mxf_write_local_tag(pb, 1, 0x8007); @@ -1295,13 +1297,12 @@ static void mxf_write_klv_fill(AVFormatContext *s) avio_write(s->pb, klv_fill_key, 16); pad -= 16 + 4; klv_encode_ber4_length(s->pb, pad); - for (; pad; pad--) - avio_w8(s->pb, 0); + ffio_fill(s->pb, 0, pad); av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1))); } } -static void mxf_write_partition(AVFormatContext *s, int bodysid, +static int mxf_write_partition(AVFormatContext *s, int bodysid, int indexsid, const uint8_t *key, int write_metadata) { @@ -1310,6 +1311,7 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid, int64_t header_byte_count_offset; unsigned index_byte_count = 0; uint64_t partition_offset = avio_tell(pb); + int err; if (!mxf->edit_unit_byte_count && mxf->edit_units_count) index_byte_count = 85 + 12+(s->nb_streams+1)*6 + @@ -1324,10 +1326,11 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid, } if (!memcmp(key, body_partition_key, 16)) { - mxf->body_partition_offset = - av_realloc(mxf->body_partition_offset, - (mxf->body_partitions_count+1)* - sizeof(*mxf->body_partition_offset)); + if ((err = av_reallocp_array(&mxf->body_partition_offset, mxf->body_partitions_count + 1, + sizeof(*mxf->body_partition_offset))) < 0) { + mxf->body_partitions_count = 0; + return err; + } mxf->body_partition_offset[mxf->body_partitions_count++] = partition_offset; } @@ -1392,6 +1395,8 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid, } avio_flush(pb); + + return 0; } static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, @@ -1655,7 +1660,7 @@ static void mxf_gen_umid(AVFormatContext *s) AV_WB64(mxf->umid , umid); AV_WB64(mxf->umid+8, umid>>8); - mxf->instance_number = seed; + mxf->instance_number = seed & 0xFFFFFF; } static int mxf_write_header(AVFormatContext *s) @@ -1705,14 +1710,15 @@ static int mxf_write_header(AVFormatContext *s) ret = av_timecode_init(&mxf->tc, rate, 0, 0, s); if (ret < 0) return ret; + sc->video_bit_rate = st->codec->bit_rate ? st->codec->bit_rate : st->codec->rc_max_rate; if (s->oformat == &ff_mxf_d10_muxer) { - if (st->codec->bit_rate == 50000000) { + if (sc->video_bit_rate == 50000000) { if (mxf->time_base.den == 25) sc->index = 3; else sc->index = 5; - } else if (st->codec->bit_rate == 40000000) { + } else if (sc->video_bit_rate == 40000000) { if (mxf->time_base.den == 25) sc->index = 7; else sc->index = 9; - } else if (st->codec->bit_rate == 30000000) { + } else if (sc->video_bit_rate == 30000000) { if (mxf->time_base.den == 25) sc->index = 11; else sc->index = 13; } else { @@ -1721,7 +1727,7 @@ static int mxf_write_header(AVFormatContext *s) } mxf->edit_unit_byte_count = KAG_SIZE; // system element - mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)st->codec->bit_rate * + mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)sc->video_bit_rate * mxf->time_base.num / (8*mxf->time_base.den); mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); mxf->edit_unit_byte_count += 16 + 4 + 4 + spf->samples_per_frame[0]*8*4; @@ -1855,7 +1861,8 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; - int packet_size = (uint64_t)st->codec->bit_rate*mxf->time_base.num / + MXFStreamContext *sc = st->priv_data; + int packet_size = (uint64_t)sc->video_bit_rate*mxf->time_base.num / (8*mxf->time_base.den); // frame size int pad; @@ -1871,13 +1878,11 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke avio_write(s->pb, klv_fill_key, 16); pad -= 16 + 4; klv_encode_ber4_length(s->pb, pad); - for (; pad; pad--) - avio_w8(s->pb, 0); + ffio_fill(s->pb, 0, pad); av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1))); } else { av_log(s, AV_LOG_WARNING, "cannot fill d-10 video packet\n"); - for (; pad > 0; pad--) - avio_w8(s->pb, 0); + ffio_fill(s->pb, 0, pad); } } @@ -1920,13 +1925,14 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) AVStream *st = s->streams[pkt->stream_index]; MXFStreamContext *sc = st->priv_data; MXFIndexEntry ie = {0}; + int err; if (!mxf->edit_unit_byte_count && !(mxf->edit_units_count % EDIT_UNITS_PER_BODY)) { - mxf->index_entries = av_realloc(mxf->index_entries, - (mxf->edit_units_count + EDIT_UNITS_PER_BODY)*sizeof(*mxf->index_entries)); - if (!mxf->index_entries) { + if ((err = av_reallocp_array(&mxf->index_entries, mxf->edit_units_count + + EDIT_UNITS_PER_BODY, sizeof(*mxf->index_entries))) < 0) { + mxf->edit_units_count = 0; av_log(s, AV_LOG_ERROR, "could not allocate index entries\n"); - return -1; + return err; } } @@ -1949,11 +1955,13 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) if (!mxf->header_written) { if (mxf->edit_unit_byte_count) { - mxf_write_partition(s, 1, 2, header_open_partition_key, 1); + if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0) + return err; mxf_write_klv_fill(s); mxf_write_index_table_segment(s); } else { - mxf_write_partition(s, 0, 0, header_open_partition_key, 1); + if ((err = mxf_write_partition(s, 0, 0, header_open_partition_key, 1)) < 0) + return err; } mxf->header_written = 1; } @@ -1963,8 +1971,8 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) (!mxf->edit_units_count || mxf->edit_units_count > EDIT_UNITS_PER_BODY) && !(ie.flags & 0x33)) { // I frame, Gop start mxf_write_klv_fill(s); - mxf_write_partition(s, 1, 2, body_partition_key, 0); - + if ((err = mxf_write_partition(s, 1, 2, body_partition_key, 0)) < 0) + return err; mxf_write_klv_fill(s); mxf_write_index_table_segment(s); } @@ -2033,16 +2041,18 @@ static int mxf_write_footer(AVFormatContext *s) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; + int err; mxf->duration = mxf->last_indexed_edit_unit + mxf->edit_units_count; mxf_write_klv_fill(s); mxf->footer_partition_offset = avio_tell(pb); if (mxf->edit_unit_byte_count) { // no need to repeat index - mxf_write_partition(s, 0, 0, footer_partition_key, 0); + if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, 0)) < 0) + return err; } else { - mxf_write_partition(s, 0, 2, footer_partition_key, 0); - + if ((err = mxf_write_partition(s, 0, 2, footer_partition_key, 0)) < 0) + return err; mxf_write_klv_fill(s); mxf_write_index_table_segment(s); } @@ -2053,11 +2063,13 @@ static int mxf_write_footer(AVFormatContext *s) if (s->pb->seekable) { avio_seek(pb, 0, SEEK_SET); if (mxf->edit_unit_byte_count) { - mxf_write_partition(s, 1, 2, header_closed_partition_key, 1); + if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0) + return err; mxf_write_klv_fill(s); mxf_write_index_table_segment(s); } else { - mxf_write_partition(s, 0, 0, header_closed_partition_key, 1); + if ((err = mxf_write_partition(s, 0, 0, header_closed_partition_key, 1)) < 0) + return err; } } diff --git a/ffmpeg/libavformat/mxg.c b/ffmpeg/libavformat/mxg.c index 604be78..b2b5b86 100644 --- a/ffmpeg/libavformat/mxg.c +++ b/ffmpeg/libavformat/mxg.c @@ -20,6 +20,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavcodec/mjpeg.h" #include "avformat.h" @@ -74,7 +75,7 @@ static int mxg_read_header(AVFormatContext *s) static uint8_t* mxg_find_startmarker(uint8_t *p, uint8_t *end) { for (; p < end - 3; p += 4) { - uint32_t x = *(uint32_t*)p; + uint32_t x = AV_RN32(p); if (x & (~(x+0x01010101)) & 0x80808080) { if (p[0] == 0xff) { @@ -171,7 +172,9 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pts = pkt->dts = mxg->dts; pkt->stream_index = 0; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS pkt->destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif pkt->buf = NULL; pkt->size = mxg->buffer_ptr - mxg->soi_ptr; @@ -212,7 +215,9 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8); pkt->stream_index = 1; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS pkt->destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif pkt->buf = NULL; pkt->size = size - 14; diff --git a/ffmpeg/libavformat/network.c b/ffmpeg/libavformat/network.c index ceed719..5e2bcf8 100644 --- a/ffmpeg/libavformat/network.c +++ b/ffmpeg/libavformat/network.c @@ -1,37 +1,38 @@ /* - * Copyright (c) 2007 The Libav Project + * Copyright (c) 2007 The FFmpeg Project * - * 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 */ -#include "libavutil/avutil.h" +#include <fcntl.h> #include "network.h" +#include "url.h" #include "libavcodec/internal.h" +#include "libavutil/avutil.h" #include "libavutil/mem.h" -#include "url.h" #include "libavutil/time.h" #if HAVE_THREADS #if HAVE_PTHREADS #include <pthread.h> #elif HAVE_OS2THREADS -#include "libavcodec/os2threads.h" +#include "compat/os2threads.h" #else -#include "libavcodec/w32pthreads.h" +#include "compat/w32pthreads.h" #endif #endif @@ -40,7 +41,6 @@ static int openssl_init; #if HAVE_THREADS #include <openssl/crypto.h> -#include "libavutil/avutil.h" pthread_mutex_t *openssl_mutexes; static void openssl_lock(int mode, int type, const char *file, int line) { @@ -156,12 +156,12 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt int64_t wait_start = 0; while (1) { + if (ff_check_interrupt(int_cb)) + return AVERROR_EXIT; ret = ff_network_wait_fd(fd, write); if (ret != AVERROR(EAGAIN)) return ret; - if (ff_check_interrupt(int_cb)) - return AVERROR_EXIT; - if (timeout) { + if (timeout > 0) { if (!wait_start) wait_start = av_gettime(); else if (av_gettime() - wait_start > timeout) @@ -212,3 +212,176 @@ int ff_is_multicast_address(struct sockaddr *addr) return 0; } + +static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, + AVIOInterruptCB *cb) +{ + int runs = timeout / POLLING_TIME; + int ret = 0; + + do { + if (ff_check_interrupt(cb)) + return AVERROR_EXIT; + ret = poll(p, nfds, POLLING_TIME); + if (ret != 0) + break; + } while (timeout <= 0 || runs-- > 0); + + if (!ret) + return AVERROR(ETIMEDOUT); + if (ret < 0) + return AVERROR(errno); + return ret; +} + +int ff_socket(int af, int type, int proto) +{ + int fd; + +#ifdef SOCK_CLOEXEC + fd = socket(af, type | SOCK_CLOEXEC, proto); + if (fd == -1 && errno == EINVAL) +#endif + { + fd = socket(af, type, proto); +#if HAVE_FCNTL + if (fd != -1) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n"); + } +#endif + } + return fd; +} + +int ff_listen_bind(int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h) +{ + int ret; + int reuse = 1; + struct pollfd lp = { fd, POLLIN, 0 }; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { + av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n"); + } + ret = bind(fd, addr, addrlen); + if (ret) + return ff_neterrno(); + + ret = listen(fd, 1); + if (ret) + return ff_neterrno(); + + ret = ff_poll_interrupt(&lp, 1, timeout, &h->interrupt_callback); + if (ret < 0) + return ret; + + ret = accept(fd, NULL, NULL); + if (ret < 0) + return ff_neterrno(); + + closesocket(fd); + + if (ff_socket_nonblock(ret, 1) < 0) + av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); + + return ret; +} + +int ff_listen_connect(int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h, + int will_try_next) +{ + struct pollfd p = {fd, POLLOUT, 0}; + int ret; + socklen_t optlen; + + if (ff_socket_nonblock(fd, 1) < 0) + av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); + + while ((ret = connect(fd, addr, addrlen))) { + ret = ff_neterrno(); + switch (ret) { + case AVERROR(EINTR): + if (ff_check_interrupt(&h->interrupt_callback)) + return AVERROR_EXIT; + continue; + case AVERROR(EINPROGRESS): + case AVERROR(EAGAIN): + ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); + if (ret < 0) + return ret; + optlen = sizeof(ret); + if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) + ret = AVUNERROR(ff_neterrno()); + if (ret != 0) { + char errbuf[100]; + ret = AVERROR(ret); + av_strerror(ret, errbuf, sizeof(errbuf)); + if (will_try_next) + av_log(h, AV_LOG_WARNING, + "Connection to %s failed (%s), trying next address\n", + h->filename, errbuf); + else + av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", + h->filename, errbuf); + } + default: + return ret; + } + } + return ret; +} + +static int match_host_pattern(const char *pattern, const char *hostname) +{ + int len_p, len_h; + if (!strcmp(pattern, "*")) + return 1; + // Skip a possible *. at the start of the pattern + if (pattern[0] == '*') + pattern++; + if (pattern[0] == '.') + pattern++; + len_p = strlen(pattern); + len_h = strlen(hostname); + if (len_p > len_h) + return 0; + // Simply check if the end of hostname is equal to 'pattern' + if (!strcmp(pattern, &hostname[len_h - len_p])) { + if (len_h == len_p) + return 1; // Exact match + if (hostname[len_h - len_p - 1] == '.') + return 1; // The matched substring is a domain and not just a substring of a domain + } + return 0; +} + +int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) +{ + char *buf, *start; + int ret = 0; + if (!no_proxy) + return 0; + if (!hostname) + return 0; + buf = av_strdup(no_proxy); + if (!buf) + return 0; + start = buf; + while (start) { + char *sep, *next = NULL; + start += strspn(start, " ,"); + sep = start + strcspn(start, " ,"); + if (*sep) { + next = sep + 1; + *sep = '\0'; + } + if (match_host_pattern(start, hostname)) { + ret = 1; + break; + } + start = next; + } + av_free(buf); + return ret; +} diff --git a/ffmpeg/libavformat/network.h b/ffmpeg/libavformat/network.h index f8b4dee..c60e142 100644 --- a/ffmpeg/libavformat/network.h +++ b/ffmpeg/libavformat/network.h @@ -28,6 +28,7 @@ #include "libavutil/error.h" #include "os_support.h" #include "avio.h" +#include "url.h" #if HAVE_UNISTD_H #include <unistd.h> @@ -89,7 +90,7 @@ int ff_network_wait_fd(int fd, int write); * @fd Socket descriptor * @write Set 1 to wait for socket able to be read, 0 to be written * @timeout Timeout interval, in microseconds. Actual precision is 100000 mcs, due to ff_network_wait_fd usage - * @param int_cb Interrupt callback, is checked after each ff_network_wait_fd call + * @param int_cb Interrupt callback, is checked before each ff_network_wait_fd call * @return 0 if data can be read/written, AVERROR(ETIMEDOUT) if timeout expired, or negative error code */ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb); @@ -222,4 +223,45 @@ const char *ff_gai_strerror(int ecode); int ff_is_multicast_address(struct sockaddr *addr); +#define POLLING_TIME 100 /// Time in milliseconds between interrupt check + +/** + * Bind to a file descriptor and poll for a connection. + * + * @param fd First argument of bind(). + * @param addr Second argument of bind(). + * @param addrlen Third argument of bind(). + * @param timeout Polling timeout in milliseconds. + * @param h URLContext providing interrupt check + * callback and logging context. + * @return A non-blocking file descriptor on success + * or an AVERROR on failure. + */ +int ff_listen_bind(int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, + URLContext *h); + +/** + * Connect to a file descriptor and poll for result. + * + * @param fd First argument of connect(), + * will be set as non-blocking. + * @param addr Second argument of connect(). + * @param addrlen Third argument of connect(). + * @param timeout Polling timeout in milliseconds. + * @param h URLContext providing interrupt check + * callback and logging context. + * @param will_try_next Whether the caller will try to connect to another + * address for the same host name, affecting the form of + * logged errors. + * @return 0 on success, AVERROR on failure. + */ +int ff_listen_connect(int fd, const struct sockaddr *addr, + socklen_t addrlen, int timeout, + URLContext *h, int will_try_next); + +int ff_http_match_no_proxy(const char *no_proxy, const char *hostname); + +int ff_socket(int domain, int type, int protocol); + #endif /* AVFORMAT_NETWORK_H */ diff --git a/ffmpeg/libavformat/nistspheredec.c b/ffmpeg/libavformat/nistspheredec.c index c09df9c..2c96686 100644 --- a/ffmpeg/libavformat/nistspheredec.c +++ b/ffmpeg/libavformat/nistspheredec.c @@ -36,7 +36,7 @@ static int nist_read_header(AVFormatContext *s) { char buffer[32], coding[32] = "pcm", format[32] = "01"; int bps = 0, be = 0; - int32_t header_size; + int32_t header_size = -1; AVStream *st; st = avformat_new_stream(s, NULL); @@ -108,8 +108,11 @@ static int nist_read_header(AVFormatContext *s) sscanf(buffer, "%*s %*s %"SCNd32, &st->codec->bits_per_coded_sample); } else { char key[32], value[32]; - sscanf(buffer, "%31s %*s %31s", key, value); - av_dict_set(&s->metadata, key, value, AV_DICT_APPEND); + if (sscanf(buffer, "%31s %*s %31s", key, value) == 3) { + av_dict_set(&s->metadata, key, value, AV_DICT_APPEND); + } else { + av_log(s, AV_LOG_ERROR, "Failed to parse '%s' as metadata\n", buffer); + } } } diff --git a/ffmpeg/libavformat/noproxy-test.c b/ffmpeg/libavformat/noproxy-test.c index a156620..4524764 100644 --- a/ffmpeg/libavformat/noproxy-test.c +++ b/ffmpeg/libavformat/noproxy-test.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "internal.h" +#include "network.h" static void test(const char *pattern, const char *host) { diff --git a/ffmpeg/libavformat/nsvdec.c b/ffmpeg/libavformat/nsvdec.c index bcc2180..4a749a2 100644 --- a/ffmpeg/libavformat/nsvdec.c +++ b/ffmpeg/libavformat/nsvdec.c @@ -2,6 +2,8 @@ * NSV demuxer * Copyright (c) 2004 The FFmpeg Project * + * first version by Francois Revol <revol@free.fr> + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -26,10 +28,6 @@ #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" -//#define DEBUG_DUMP_INDEX // XXX dumbdriving-271.nsv breaks with it commented!! -#define CHECK_SUBSEQUENT_NSVS -//#define DISABLE_AUDIO - /* max bytes to crawl for trying to resync * stupid streaming servers don't start at chunk boundaries... */ @@ -37,7 +35,6 @@ #define NSV_MAX_RESYNC_TRIES 300 /* - * First version by Francois Revol - revol@free.fr * References: * (1) http://www.multimedia.cx/nsv-format.txt * seems someone came to the same conclusions as me, and updated it: @@ -369,25 +366,6 @@ static int nsv_parse_NSVf_header(AVFormatContext *s) av_dlog(s, "NSV got index; filepos %"PRId64"\n", avio_tell(pb)); -#ifdef DEBUG_DUMP_INDEX -#define V(v) ((v<0x20 || v > 127)?'.':v) - /* dump index */ - av_dlog(s, "NSV %d INDEX ENTRIES:\n", table_entries); - av_dlog(s, "NSV [dataoffset][fileoffset]\n", table_entries); - for (i = 0; i < table_entries; i++) { - unsigned char b[8]; - avio_seek(pb, size + nsv->nsvs_file_offset[i], SEEK_SET); - avio_read(pb, b, 8); - av_dlog(s, "NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x" - "%c%c%c%c%c%c%c%c\n", - nsv->nsvs_file_offset[i], size + nsv->nsvs_file_offset[i], - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) ); - } - //avio_seek(pb, size, SEEK_SET); /* go back to end of header */ -#undef V -#endif - avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */ if (url_feof(pb)) @@ -478,7 +456,6 @@ static int nsv_parse_NSVs_header(AVFormatContext *s) } } if (atag != T_NONE) { -#ifndef DISABLE_AUDIO st = avformat_new_stream(s, NULL); if (!st) goto fail; @@ -498,15 +475,12 @@ static int nsv_parse_NSVs_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, framerate.num*1000); st->start_time = 0; st->duration = (int64_t)nsv->duration * framerate.num; -#endif } -#ifdef CHECK_SUBSEQUENT_NSVS } else { if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) { av_dlog(s, "NSV NSVs header values differ from the first one!!!\n"); //return -1; } -#endif /* CHECK_SUBSEQUENT_NSVS */ } nsv->state = NSV_HAS_READ_NSVS; @@ -785,7 +759,7 @@ static int nsv_probe(AVProbeData *p) } /* so we'll have more luck on extension... */ if (av_match_ext(p->filename, "nsv")) - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; /* FIXME: add mime-type check */ return score; } diff --git a/ffmpeg/libavformat/nullenc.c b/ffmpeg/libavformat/nullenc.c index 7da297b..7c08c39 100644 --- a/ffmpeg/libavformat/nullenc.c +++ b/ffmpeg/libavformat/nullenc.c @@ -32,5 +32,5 @@ AVOutputFormat ff_null_muxer = { .audio_codec = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), .video_codec = AV_CODEC_ID_RAWVIDEO, .write_packet = null_write_packet, - .flags = AVFMT_NOFILE | AVFMT_NOTIMESTAMPS | AVFMT_RAWPICTURE, + .flags = AVFMT_VARIABLE_FPS | AVFMT_NOFILE | AVFMT_NOTIMESTAMPS | AVFMT_RAWPICTURE, }; diff --git a/ffmpeg/libavformat/nut.c b/ffmpeg/libavformat/nut.c index 2abe969..8b8a4cb 100644 --- a/ffmpeg/libavformat/nut.c +++ b/ffmpeg/libavformat/nut.c @@ -26,125 +26,138 @@ #include "internal.h" const AVCodecTag ff_nut_subtitle_tags[] = { - { AV_CODEC_ID_TEXT , MKTAG('U', 'T', 'F', '8') }, - { AV_CODEC_ID_SSA , MKTAG('S', 'S', 'A', 0 ) }, - { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('D', 'V', 'D', 'S') }, - { AV_CODEC_ID_DVB_SUBTITLE, MKTAG('D', 'V', 'B', 'S') }, - { AV_CODEC_ID_DVB_TELETEXT, MKTAG('D', 'V', 'B', 'T') }, - { AV_CODEC_ID_NONE , 0 } + { AV_CODEC_ID_TEXT, MKTAG('U', 'T', 'F', '8') }, + { AV_CODEC_ID_SSA, MKTAG('S', 'S', 'A', 0 ) }, + { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('D', 'V', 'D', 'S') }, + { AV_CODEC_ID_DVB_SUBTITLE, MKTAG('D', 'V', 'B', 'S') }, + { AV_CODEC_ID_DVB_TELETEXT, MKTAG('D', 'V', 'B', 'T') }, + { AV_CODEC_ID_NONE, 0 } }; const AVCodecTag ff_nut_data_tags[] = { - { AV_CODEC_ID_TEXT , MKTAG('U', 'T', 'F', '8') }, - { AV_CODEC_ID_NONE , 0 } + { AV_CODEC_ID_TEXT, MKTAG('U', 'T', 'F', '8') }, + { AV_CODEC_ID_NONE, 0 } }; const AVCodecTag ff_nut_video_tags[] = { - { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'B', 'G', 'R') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'B', 'G', 'R') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 12 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 12 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'B', 'G', 'R') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 'A') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 0 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 'A') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 0 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'B', 'G', 'R') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 24 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 24 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '1', '1', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '1', 'W', '0') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '0', 'W', '1') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 8 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 8 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 4 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 4 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '4', 'B', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', 'B', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 48 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 48 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'B', 'G', 'R') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'R', 'G', 'B') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'R', 'A', 64 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'B', 'A', 64 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'B', 'R', 'A') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'R', 'B', 'A') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 11 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 12 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 11 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 12 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 10 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 12 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 0 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 14 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 11 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 14 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 10 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 14 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 0 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '3', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 8 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 8 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 8 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '2', 0 , 8 ) }, + { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'B', 'G', 'R') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'R', 'G', 'B') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'B', 'G', 'R') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'R', 'G', 'B') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 12 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 12 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'B', 'G', 'R') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'R', 'G', 'B') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 'A') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 0 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 'A') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 0 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'B', 'G', 'R') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'R', 'G', 'B') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'R', 'G', 'B') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 24 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 24 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '1', '1', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '0', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '1', 'W', '0') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '0', 'W', '1') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 4 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 4 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', '4', 'B', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', 'B', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 48 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 48 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'B', 'G', 'R') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'R', 'G', 'B') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'R', 'A', 64 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'B', 'A', 64 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'B', 'R', 'A') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'R', 'B', 'A') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 10 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 11 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 10 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 10 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 12 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 11 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 12 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 10 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 12 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 0 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 14 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 11 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 14 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 10 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 14 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 0 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 16 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '3', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 8 ) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '2', 0 , 8 ) }, + + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 9) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 0, '1', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 9) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 11, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 9) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 10, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 9) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(9, 0, '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 9 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 0 , '1', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 9 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 11 , '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 9 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 10 , '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 9 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG( 9 , 0 , '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 10) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '1', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 10) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 11, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 10) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 10, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 10) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '1', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 11 , '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 10 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 16) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '1', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 16) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 11, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 16) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 10, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 16) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '4', 'Y') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 16 ) }, - { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 8) }, - { AV_CODEC_ID_NONE , 0 } + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 9) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG( 9, 0, '3', 'G') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 10) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '3', 'G') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 12) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 0, '3', 'G') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 14) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(14, 0, '3', 'G') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 16) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '3', 'G') }, + + { AV_CODEC_ID_NONE, 0 } }; static const AVCodecTag nut_audio_extra_tags[] = { @@ -186,45 +199,57 @@ const AVCodecTag * const ff_nut_codec_tags[] = { ff_codec_bmp_tags, ff_codec_wav_tags, nut_audio_extra_tags, ff_nut_data_tags, 0 }; -void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val){ +void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val) +{ int i; - for(i=0; i<nut->avf->nb_streams; i++){ - nut->stream[i].last_pts= av_rescale_rnd( - val, - time_base.num * (int64_t)nut->stream[i].time_base->den, - time_base.den * (int64_t)nut->stream[i].time_base->num, - AV_ROUND_DOWN); - } + for (i = 0; i < nut->avf->nb_streams; i++) + nut->stream[i].last_pts = + av_rescale_rnd(val, + time_base.num * (int64_t)nut->stream[i].time_base->den, + time_base.den * (int64_t)nut->stream[i].time_base->num, + AV_ROUND_DOWN); } -int64_t ff_lsb2full(StreamContext *stream, int64_t lsb){ - int64_t mask = (1ULL<<stream->msb_pts_shift)-1; - int64_t delta= stream->last_pts - mask/2; - return ((lsb - delta)&mask) + delta; +int64_t ff_lsb2full(StreamContext *stream, int64_t lsb) +{ + int64_t mask = (1ULL << stream->msb_pts_shift) - 1; + int64_t delta = stream->last_pts - mask / 2; + return ((lsb - delta) & mask) + delta; } -int ff_nut_sp_pos_cmp(const Syncpoint *a, const Syncpoint *b){ +int ff_nut_sp_pos_cmp(const Syncpoint *a, const Syncpoint *b) +{ return ((a->pos - b->pos) >> 32) - ((b->pos - a->pos) >> 32); } -int ff_nut_sp_pts_cmp(const Syncpoint *a, const Syncpoint *b){ +int ff_nut_sp_pts_cmp(const Syncpoint *a, const Syncpoint *b) +{ return ((a->ts - b->ts) >> 32) - ((b->ts - a->ts) >> 32); } -void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts){ - Syncpoint *sp= av_mallocz(sizeof(Syncpoint)); +int ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts) +{ + Syncpoint *sp = av_mallocz(sizeof(Syncpoint)); struct AVTreeNode *node = av_tree_node_alloc(); + if (!sp || !node) { + av_freep(&sp); + av_freep(&node); + return AVERROR(ENOMEM); + } + nut->sp_count++; - sp->pos= pos; - sp->back_ptr= back_ptr; - sp->ts= ts; + sp->pos = pos; + sp->back_ptr = back_ptr; + sp->ts = ts; av_tree_insert(&nut->syncpoints, sp, (void *) ff_nut_sp_pos_cmp, &node); - if(node){ + if (node) { av_free(sp); av_free(node); } + + return 0; } static int enu_free(void *opaque, void *elem) @@ -240,13 +265,13 @@ void ff_nut_free_sp(NUTContext *nut) } const Dispositions ff_nut_dispositions[] = { - {"default" , AV_DISPOSITION_DEFAULT}, - {"dub" , AV_DISPOSITION_DUB}, - {"original" , AV_DISPOSITION_ORIGINAL}, - {"comment" , AV_DISPOSITION_COMMENT}, - {"lyrics" , AV_DISPOSITION_LYRICS}, - {"karaoke" , AV_DISPOSITION_KARAOKE}, - {"" , 0} + { "default", AV_DISPOSITION_DEFAULT }, + { "dub", AV_DISPOSITION_DUB }, + { "original", AV_DISPOSITION_ORIGINAL }, + { "comment", AV_DISPOSITION_COMMENT }, + { "lyrics", AV_DISPOSITION_LYRICS }, + { "karaoke", AV_DISPOSITION_KARAOKE }, + { "", 0 } }; const AVMetadataConv ff_nut_metadata_conv[] = { diff --git a/ffmpeg/libavformat/nut.h b/ffmpeg/libavformat/nut.h index ab31c27..18b688a 100644 --- a/ffmpeg/libavformat/nut.h +++ b/ffmpeg/libavformat/nut.h @@ -22,9 +22,6 @@ #ifndef AVFORMAT_NUT_H #define AVFORMAT_NUT_H -//#include <limits.h> -//#include "libavutil/adler32.h" -//#include "libavcodec/mpegaudio.h" #include "avformat.h" #include "internal.h" #include "metadata.h" @@ -39,6 +36,8 @@ #define MAX_DISTANCE (1024*32-1) +#define NUT_VERSION 3 + typedef enum{ FLAG_KEY = 1, ///<if set, frame is keyframe FLAG_EOR = 2, ///<if set, stream has no relevance on presentation. (EOR) @@ -105,6 +104,8 @@ typedef struct NUTContext { int sp_count; int64_t max_pts; AVRational *max_pts_tb; + int version; + int minor_version; } NUTContext; extern const AVCodecTag ff_nut_subtitle_tags[]; @@ -123,7 +124,7 @@ void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val); int64_t ff_lsb2full(StreamContext *stream, int64_t lsb); int ff_nut_sp_pos_cmp(const Syncpoint *a, const Syncpoint *b); int ff_nut_sp_pts_cmp(const Syncpoint *a, const Syncpoint *b); -void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts); +int ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts); void ff_nut_free_sp(NUTContext *nut); extern const Dispositions ff_nut_dispositions[]; diff --git a/ffmpeg/libavformat/nutdec.c b/ffmpeg/libavformat/nutdec.c index 8896518..ba9ff02 100644 --- a/ffmpeg/libavformat/nutdec.c +++ b/ffmpeg/libavformat/nutdec.c @@ -196,7 +196,7 @@ static int nut_probe(AVProbeData *p) tmp = ffio_read_varlen(bc); \ if (!(check)) { \ av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp); \ - return -1; \ + return AVERROR_INVALIDDATA; \ } \ dst = tmp; \ } while (0) @@ -206,7 +206,7 @@ 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); @@ -226,7 +226,16 @@ 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); + tmp = ffio_read_varlen(bc); + if (tmp < 2 && tmp > NUT_VERSION) { + av_log(s, AV_LOG_ERROR, "Version %"PRId64" not supported.\n", + tmp); + return AVERROR(ENOSYS); + } + nut->version = tmp; + if (nut->version > 3) + nut->minor_version = ffio_read_varlen(bc); + GET_V(stream_count, tmp > 0 && tmp <= NUT_MAX_STREAMS); nut->max_distance = ffio_read_varlen(bc); @@ -237,6 +246,8 @@ static int decode_main_header(NUTContext *nut) GET_V(nut->time_base_count, tmp > 0 && tmp < INT_MAX / sizeof(AVRational)); nut->time_base = av_malloc(nut->time_base_count * sizeof(AVRational)); + if (!nut->time_base) + return AVERROR(ENOMEM); for (i = 0; i < nut->time_base_count; i++) { GET_V(nut->time_base[i].num, tmp > 0 && tmp < (1ULL << 31)); @@ -332,7 +343,9 @@ static int decode_main_header(NUTContext *nut) return AVERROR_INVALIDDATA; } - nut->stream = av_mallocz(sizeof(StreamContext) * stream_count); + nut->stream = av_calloc(stream_count, sizeof(StreamContext)); + if (!nut->stream) + return AVERROR(ENOMEM); for (i = 0; i < stream_count; i++) avformat_new_stream(s, NULL); @@ -389,7 +402,7 @@ static int decode_stream_header(NUTContext *nut) 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 == AV_CODEC_ID_NONE) av_log(s, AV_LOG_ERROR, @@ -405,9 +418,8 @@ static int decode_stream_header(NUTContext *nut) GET_V(st->codec->extradata_size, tmp < (1 << 30)); if (st->codec->extradata_size) { - st->codec->extradata = av_mallocz(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - avio_read(bc, st->codec->extradata, st->codec->extradata_size); + if (ff_get_extradata(st->codec, bc, st->codec->extradata_size) < 0) + return AVERROR(ENOMEM); } if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -418,7 +430,7 @@ static int decode_stream_header(NUTContext *nut) 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) { @@ -429,7 +441,7 @@ static int decode_stream_header(NUTContext *nut) 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, @@ -537,7 +549,7 @@ static int decode_info_header(NUTContext *nut) 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; } @@ -548,6 +560,7 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) AVIOContext *bc = s->pb; int64_t end; uint64_t tmp; + int ret; nut->last_syncpoint_pos = avio_tell(bc) - 8; @@ -569,7 +582,9 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr) *ts = tmp / nut->time_base_count * av_q2d(nut->time_base[tmp % nut->time_base_count]) * 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; } @@ -580,14 +595,8 @@ static int64_t find_duration(NUTContext *nut, int64_t filesize) AVFormatContext *s = nut->avf; int64_t duration = 0; - int64_t pos = FFMAX(0, filesize - 2*nut->max_distance); - for(;;){ - int64_t ts = nut_read_timestamp(s, -1, &pos, INT64_MAX); - if(ts < 0) - break; - duration = FFMAX(duration, ts); - pos++; - } + ff_find_last_ts(s, -1, &duration, NULL, nut_read_timestamp); + if(duration > 0) s->duration_estimation_method = AVFMT_DURATION_FROM_PTS; return duration; @@ -601,8 +610,9 @@ static int find_and_decode_index(NUTContext *nut) int i, j, syncpoint_count; int64_t filesize = avio_size(bc); int64_t *syncpoints; + uint64_t max_pts; int8_t *has_keyframe; - int ret = -1; + int ret = AVERROR_INVALIDDATA; if(filesize <= 0) return -1; @@ -614,16 +624,25 @@ static int find_and_decode_index(NUTContext *nut) if(s->duration<=0) s->duration = find_duration(nut, filesize); - return -1; + return ret; } end = get_packetheader(nut, bc, 1, INDEX_STARTCODE); end += avio_tell(bc); - ffio_read_varlen(bc); // max_pts + max_pts = ffio_read_varlen(bc); + s->duration = av_rescale_q(max_pts / nut->time_base_count, + nut->time_base[max_pts % nut->time_base_count], + AV_TIME_BASE_Q); + s->duration_estimation_method = AVFMT_DURATION_FROM_PTS; + 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)); + syncpoints = av_malloc_array(syncpoint_count, sizeof(int64_t)); + has_keyframe = av_malloc_array(syncpoint_count + 1, sizeof(int8_t)); + if (!syncpoints || !has_keyframe) { + ret = AVERROR(ENOMEM); + goto fail; + } for (i = 0; i < syncpoint_count; i++) { syncpoints[i] = ffio_read_varlen(bc); if (syncpoints[i] <= 0) @@ -891,7 +910,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) } else { frame_code = avio_r8(bc); if (url_feof(bc)) - return -1; + return AVERROR_EOF; if (frame_code == 'N') { tmp = frame_code; for (i = 1; i < 8; i++) diff --git a/ffmpeg/libavformat/nutenc.c b/ffmpeg/libavformat/nutenc.c index 2d8d265..107e57b 100644 --- a/ffmpeg/libavformat/nutenc.c +++ b/ffmpeg/libavformat/nutenc.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/tree.h" @@ -91,7 +93,7 @@ static int find_expected_header(AVCodecContext *c, int size, int key_frame, header |= (bitrate_index & 1) << 9; return 2; //FIXME actually put the needed ones in build_elision_headers() - return 3; //we guess that the private bit is not set + //return 3; //we guess that the private bit is not set //FIXME the above assumptions should be checked, if these turn out false too often something should be done } return 0; @@ -335,7 +337,9 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc) tmp_head_idx; int64_t tmp_match; - ff_put_v(bc, 3); /* version */ + ff_put_v(bc, nut->version = NUT_VERSION); + if (nut->version > 3) + ff_put_v(bc, nut->minor_version); ff_put_v(bc, nut->avf->nb_streams); ff_put_v(bc, nut->max_distance); ff_put_v(bc, nut->time_base_count); @@ -584,8 +588,15 @@ static int write_index(NUTContext *nut, AVIOContext *bc) { int64_t last_pts= -1; int j, k; for (j=0; j<nut->sp_count; j++) { - int flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count); + int flag; int n = 0; + + if (j && nus->keyframe_pts[j] == nus->keyframe_pts[j-1]) { + av_log(nut->avf, AV_LOG_WARNING, "Multiple keyframes with same PTS\n"); + nus->keyframe_pts[j] = AV_NOPTS_VALUE; + } + + flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count); for (; j<nut->sp_count && (nus->keyframe_pts[j] != AV_NOPTS_VALUE) == flag; j++) n++; @@ -680,10 +691,10 @@ static int nut_write_header(AVFormatContext *s) nut->avf = s; - nut->stream = av_mallocz(sizeof(StreamContext ) * s->nb_streams); - nut->chapter = av_mallocz(sizeof(ChapterContext) * s->nb_chapters); - nut->time_base= av_mallocz(sizeof(AVRational ) *(s->nb_streams + - s->nb_chapters)); + nut->stream = av_calloc(s->nb_streams, sizeof(*nut->stream )); + nut->chapter = av_calloc(s->nb_chapters, sizeof(*nut->chapter)); + nut->time_base= av_calloc(s->nb_streams + + s->nb_chapters, sizeof(*nut->time_base)); if (!nut->stream || !nut->chapter || !nut->time_base) { av_freep(&nut->stream); av_freep(&nut->chapter); @@ -858,13 +869,14 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0); put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE); - ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts); + if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0) + return ret; if ((1ll<<60) % nut->sp_count == 0) for (i=0; i<s->nb_streams; i++) { int j; StreamContext *nus = &nut->stream[i]; - nus->keyframe_pts = av_realloc(nus->keyframe_pts, 2*nut->sp_count*sizeof(*nus->keyframe_pts)); + av_reallocp_array(&nus->keyframe_pts, 2*nut->sp_count, sizeof(*nus->keyframe_pts)); if (!nus->keyframe_pts) return AVERROR(ENOMEM); for (j=nut->sp_count == 1 ? 0 : nut->sp_count; j<2*nut->sp_count; j++) diff --git a/ffmpeg/libavformat/nuv.c b/ffmpeg/libavformat/nuv.c index fc9e916..2c02de1 100644 --- a/ffmpeg/libavformat/nuv.c +++ b/ffmpeg/libavformat/nuv.c @@ -86,11 +86,8 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst, av_freep(&vst->codec->extradata); vst->codec->extradata_size = 0; } - vst->codec->extradata = av_malloc(size); - if (!vst->codec->extradata) + if (ff_get_extradata(vst->codec, pb, size) < 0) return AVERROR(ENOMEM); - vst->codec->extradata_size = size; - avio_read(pb, vst->codec->extradata, size); size = 0; if (!myth) return 0; diff --git a/ffmpeg/libavformat/oggdec.c b/ffmpeg/libavformat/oggdec.c index fdb5e96..8639eae 100644 --- a/ffmpeg/libavformat/oggdec.c +++ b/ffmpeg/libavformat/oggdec.c @@ -30,6 +30,7 @@ #include <stdio.h> #include "libavutil/avassert.h" +#include "libavutil/intreadwrite.h" #include "oggdec.h" #include "avformat.h" #include "internal.h" @@ -88,7 +89,7 @@ static int ogg_restore(AVFormatContext *s, int discard) struct ogg *ogg = s->priv_data; AVIOContext *bc = s->pb; struct ogg_state *ost = ogg->state; - int i; + int i, err; if (!ost) return 0; @@ -96,25 +97,21 @@ static int ogg_restore(AVFormatContext *s, int discard) ogg->state = ost->next; if (!discard) { - struct ogg_stream *old_streams = ogg->streams; for (i = 0; i < ogg->nstreams; i++) - av_free(ogg->streams[i].buf); + av_freep(&ogg->streams[i].buf); avio_seek(bc, ost->pos, SEEK_SET); ogg->page_pos = -1; ogg->curidx = ost->curidx; ogg->nstreams = ost->nstreams; - ogg->streams = av_realloc(ogg->streams, - ogg->nstreams * sizeof(*ogg->streams)); - - if (ogg->streams) { + if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams, + sizeof(*ogg->streams))) < 0) { + ogg->nstreams = 0; + return err; + } else memcpy(ogg->streams, ost->streams, ost->nstreams * sizeof(*ogg->streams)); - } else { - av_free(old_streams); - ogg->nstreams = 0; - } } av_free(ost); @@ -145,6 +142,7 @@ static int ogg_reset(AVFormatContext *s) if (start_pos <= s->data_offset) { os->lastpts = 0; } + os->end_trimming = 0; } ogg->page_pos = -1; @@ -636,14 +634,14 @@ static int ogg_read_close(AVFormatContext *s) int i; for (i = 0; i < ogg->nstreams; i++) { - av_free(ogg->streams[i].buf); + av_freep(&ogg->streams[i].buf); if (ogg->streams[i].codec && ogg->streams[i].codec->cleanup) { ogg->streams[i].codec->cleanup(s, i); } - av_free(ogg->streams[i].private); + av_freep(&ogg->streams[i].private); } - av_free(ogg->streams); + av_freep(&ogg->streams); return 0; } @@ -671,7 +669,12 @@ static int ogg_read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i); ogg->streams[i].codec = NULL; } else if (os->codec && os->nb_header < os->codec->nb_header) { - av_log(s, AV_LOG_WARNING, "Number of headers (%d) mismatch for stream %d\n", os->nb_header, i); + av_log(s, AV_LOG_WARNING, + "Headers mismatch for stream %d: " + "expected %d received %d.\n", + i, os->codec->nb_header, os->nb_header); + if (s->error_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; } if (os->start_granule != OGG_NOGRANULE_VALUE) os->lastpts = s->streams[i]->start_time = @@ -735,6 +738,11 @@ static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt) int pstart, psize; int64_t fpos, pts, dts; + if (s->io_repositioned) { + ogg_reset(s); + s->io_repositioned = 0; + } + //Get an ogg packet retry: do { @@ -767,6 +775,19 @@ retry: pkt->duration = os->pduration; pkt->pos = fpos; + if (os->end_trimming) { + uint8_t *side_data = av_packet_new_side_data(pkt, + AV_PKT_DATA_SKIP_SAMPLES, + 10); + if(side_data == NULL) { + av_free_packet(pkt); + av_free(pkt); + return AVERROR(ENOMEM); + } + AV_WL32(side_data + 4, os->end_trimming); + os->end_trimming = 0; + } + return psize; } @@ -849,5 +870,5 @@ AVInputFormat ff_ogg_demuxer = { .read_seek = ogg_read_seek, .read_timestamp = ogg_read_timestamp, .extensions = "ogg", - .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT, + .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH, }; diff --git a/ffmpeg/libavformat/oggdec.h b/ffmpeg/libavformat/oggdec.h index e9a300d..c31859f 100644 --- a/ffmpeg/libavformat/oggdec.h +++ b/ffmpeg/libavformat/oggdec.h @@ -84,6 +84,7 @@ struct ogg_stream { int got_start; int got_data; ///< 1 if the stream got some data (non-initial packets), 0 otherwise int nb_header; ///< set to the number of parsed headers + int end_trimming; ///< set the number of packets to drop from the end void *private; }; diff --git a/ffmpeg/libavformat/oggenc.c b/ffmpeg/libavformat/oggenc.c index 3d4519c..d9ef23c 100644 --- a/ffmpeg/libavformat/oggenc.c +++ b/ffmpeg/libavformat/oggenc.c @@ -19,8 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "libavutil/crc.h" -#include "libavutil/opt.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/random_seed.h" @@ -81,18 +82,10 @@ static const AVOption options[] = { { "pagesize", "preferred page size in bytes (deprecated)", OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM }, { "page_duration", "preferred page duration, in microseconds", - OFFSET(pref_duration), AV_OPT_TYPE_INT, { .i64 = 1000000 }, 0, INT64_MAX, PARAM }, + OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM }, { NULL }, }; -static const AVClass ogg_muxer_class = { - .class_name = "Ogg muxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - - static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset) { int64_t pos = avio_tell(pb); @@ -447,11 +440,13 @@ static int ogg_write_header(AVFormatContext *s) } while (j < i); oggstream->serial_num = serial_num; + av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE); + st->priv_data = oggstream; if (st->codec->codec_id == AV_CODEC_ID_FLAC) { int err = ogg_build_flac_headers(st->codec, oggstream, st->codec->flags & CODEC_FLAG_BITEXACT, - &s->metadata); + &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n"); av_freep(&st->priv_data); @@ -460,7 +455,7 @@ static int ogg_write_header(AVFormatContext *s) } else if (st->codec->codec_id == AV_CODEC_ID_SPEEX) { int err = ogg_build_speex_headers(st->codec, oggstream, st->codec->flags & CODEC_FLAG_BITEXACT, - &s->metadata); + &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n"); av_freep(&st->priv_data); @@ -469,7 +464,7 @@ static int ogg_write_header(AVFormatContext *s) } else if (st->codec->codec_id == AV_CODEC_ID_OPUS) { int err = ogg_build_opus_headers(st->codec, oggstream, st->codec->flags & CODEC_FLAG_BITEXACT, - &s->metadata); + &st->metadata); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n"); av_freep(&st->priv_data); @@ -490,7 +485,7 @@ static int ogg_write_header(AVFormatContext *s) } p = ogg_write_vorbiscomment(7, st->codec->flags & CODEC_FLAG_BITEXACT, - &oggstream->header_len[1], &s->metadata, + &oggstream->header_len[1], &st->metadata, framing_bit); oggstream->header[1] = p; if (!p) @@ -621,16 +616,81 @@ static int ogg_write_trailer(AVFormatContext *s) return 0; } +#if CONFIG_OGG_MUXER +static const AVClass ogg_muxer_class = { + .class_name = "Ogg muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_ogg_muxer = { .name = "ogg", .long_name = NULL_IF_CONFIG_SMALL("Ogg"), .mime_type = "application/ogg", - .extensions = "ogg,ogv,spx,opus", + .extensions = "ogg,ogv" +#if !CONFIG_SPEEX_MUXER + ",spx" +#endif +#if !CONFIG_OPUS_MUXER + ",opus" +#endif + , .priv_data_size = sizeof(OGGContext), .audio_codec = AV_CODEC_ID_FLAC, .video_codec = AV_CODEC_ID_THEORA, .write_header = ogg_write_header, .write_packet = ogg_write_packet, .write_trailer = ogg_write_trailer, + .flags = AVFMT_TS_NEGATIVE, .priv_class = &ogg_muxer_class, }; +#endif + +#if CONFIG_SPEEX_MUXER +static const AVClass speex_muxer_class = { + .class_name = "Speex muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVOutputFormat ff_speex_muxer = { + .name = "speex", + .long_name = NULL_IF_CONFIG_SMALL("Speex"), + .mime_type = "audio/ogg", + .extensions = "spx", + .priv_data_size = sizeof(OGGContext), + .audio_codec = AV_CODEC_ID_SPEEX, + .video_codec = AV_CODEC_ID_NONE, + .write_header = ogg_write_header, + .write_packet = ogg_write_packet, + .write_trailer = ogg_write_trailer, + .flags = AVFMT_TS_NEGATIVE, + .priv_class = &speex_muxer_class, +}; +#endif + +#if CONFIG_OPUS_MUXER +static const AVClass opus_muxer_class = { + .class_name = "Opus muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVOutputFormat ff_opus_muxer = { + .name = "opus", + .long_name = NULL_IF_CONFIG_SMALL("Opus"), + .mime_type = "audio/ogg", + .extensions = "opus", + .priv_data_size = sizeof(OGGContext), + .audio_codec = AV_CODEC_ID_OPUS, + .video_codec = AV_CODEC_ID_NONE, + .write_header = ogg_write_header, + .write_packet = ogg_write_packet, + .write_trailer = ogg_write_trailer, + .flags = AVFMT_TS_NEGATIVE, + .priv_class = &opus_muxer_class, +}; +#endif diff --git a/ffmpeg/libavformat/oggparsecelt.c b/ffmpeg/libavformat/oggparsecelt.c index afc4392..f3c2c1a 100644 --- a/ffmpeg/libavformat/oggparsecelt.c +++ b/ffmpeg/libavformat/oggparsecelt.c @@ -44,16 +44,12 @@ static int celt_header(AVFormatContext *s, int idx) uint32_t version, sample_rate, nb_channels, frame_size; uint32_t overlap, extra_headers; - uint8_t *extradata; - extradata = av_malloc(2 * sizeof(uint32_t) + - FF_INPUT_BUFFER_PADDING_SIZE); priv = av_malloc(sizeof(struct oggcelt_private)); - if (!extradata || !priv) { - av_free(extradata); - av_free(priv); + if (!priv) + return AVERROR(ENOMEM); + if (ff_alloc_extradata(st->codec, 2 * sizeof(uint32_t)) < 0) return AVERROR(ENOMEM); - } version = AV_RL32(p + 28); /* unused header size field skipped */ sample_rate = AV_RL32(p + 36); @@ -67,16 +63,13 @@ static int celt_header(AVFormatContext *s, int idx) st->codec->sample_rate = sample_rate; st->codec->channels = nb_channels; st->codec->frame_size = frame_size; - av_free(st->codec->extradata); - st->codec->extradata = extradata; - st->codec->extradata_size = 2 * sizeof(uint32_t); if (sample_rate) avpriv_set_pts_info(st, 64, 1, sample_rate); priv->extra_headers_left = 1 + extra_headers; av_free(os->private); os->private = priv; - AV_WL32(extradata + 0, overlap); - AV_WL32(extradata + 4, version); + AV_WL32(st->codec->extradata + 0, overlap); + AV_WL32(st->codec->extradata + 4, version); return 1; } else if (priv && priv->extra_headers_left) { /* Extra headers (vorbiscomment) */ diff --git a/ffmpeg/libavformat/oggparseflac.c b/ffmpeg/libavformat/oggparseflac.c index 3ff594e..f69533f 100644 --- a/ffmpeg/libavformat/oggparseflac.c +++ b/ffmpeg/libavformat/oggparseflac.c @@ -62,10 +62,9 @@ flac_header (AVFormatContext * s, int idx) st->codec->codec_id = AV_CODEC_ID_FLAC; st->need_parsing = AVSTREAM_PARSE_HEADERS; - st->codec->extradata = - av_malloc(FLAC_STREAMINFO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); - memcpy(st->codec->extradata, streaminfo_start, FLAC_STREAMINFO_SIZE); - st->codec->extradata_size = FLAC_STREAMINFO_SIZE; + if (ff_alloc_extradata(st->codec, FLAC_STREAMINFO_SIZE) < 0) + return AVERROR(ENOMEM); + memcpy(st->codec->extradata, streaminfo_start, st->codec->extradata_size); avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); } else if (mdt == FLAC_METADATA_TYPE_VORBIS_COMMENT) { @@ -78,11 +77,32 @@ flac_header (AVFormatContext * s, int idx) static int old_flac_header (AVFormatContext * s, int idx) { + struct ogg *ogg = s->priv_data; AVStream *st = s->streams[idx]; + struct ogg_stream *os = ogg->streams + idx; + AVCodecParserContext *parser = av_parser_init(AV_CODEC_ID_FLAC); + int size; + uint8_t *data; + + if (!parser) + return -1; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = AV_CODEC_ID_FLAC; - return 0; + parser->flags = PARSER_FLAG_COMPLETE_FRAMES; + av_parser_parse2(parser, st->codec, + &data, &size, os->buf + os->pstart, os->psize, + AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1); + + av_parser_close(parser); + + if (st->codec->sample_rate) { + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + return 0; + } + + return 1; } const struct ogg_codec ff_flac_codec = { diff --git a/ffmpeg/libavformat/oggparseogm.c b/ffmpeg/libavformat/oggparseogm.c index a3caac0..fe4c1f2 100644 --- a/ffmpeg/libavformat/oggparseogm.c +++ b/ffmpeg/libavformat/oggparseogm.c @@ -38,34 +38,35 @@ ogm_header(AVFormatContext *s, int idx) struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; AVStream *st = s->streams[idx]; - const uint8_t *p = os->buf + os->pstart; + GetByteContext p; uint64_t time_unit; uint64_t spu; uint32_t size; - if(!(*p & 1)) + bytestream2_init(&p, os->buf + os->pstart, os->psize); + if (!(bytestream2_peek_byte(&p) & 1)) return 0; - if(*p == 1) { - p++; + if (bytestream2_peek_byte(&p) == 1) { + bytestream2_skip(&p, 1); - if(*p == 'v'){ + if (bytestream2_peek_byte(&p) == 'v'){ int tag; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - p += 8; - tag = bytestream_get_le32(&p); + bytestream2_skip(&p, 8); + tag = bytestream2_get_le32(&p); st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); st->codec->codec_tag = tag; - } else if (*p == 't') { + } else if (bytestream2_peek_byte(&p) == 't') { st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_TEXT; - p += 12; + bytestream2_skip(&p, 12); } else { - uint8_t acid[5]; + uint8_t acid[5] = { 0 }; int cid; st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - p += 8; - bytestream_get_buffer(&p, acid, 4); + bytestream2_skip(&p, 8); + bytestream2_get_buffer(&p, acid, 4); acid[4] = 0; cid = strtol(acid, NULL, 16); st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid); @@ -74,38 +75,38 @@ ogm_header(AVFormatContext *s, int idx) st->need_parsing = AVSTREAM_PARSE_FULL; } - size = bytestream_get_le32(&p); + size = bytestream2_get_le32(&p); size = FFMIN(size, os->psize); - time_unit = bytestream_get_le64(&p); - spu = bytestream_get_le64(&p); - p += 4; /* default_len */ - p += 8; /* buffersize + bits_per_sample */ + time_unit = bytestream2_get_le64(&p); + spu = bytestream2_get_le64(&p); + bytestream2_skip(&p, 4); /* default_len */ + bytestream2_skip(&p, 8); /* buffersize + bits_per_sample */ if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO){ - st->codec->width = bytestream_get_le32(&p); - st->codec->height = bytestream_get_le32(&p); + st->codec->width = bytestream2_get_le32(&p); + st->codec->height = bytestream2_get_le32(&p); avpriv_set_pts_info(st, 64, time_unit, spu * 10000000); } else { - st->codec->channels = bytestream_get_le16(&p); - p += 2; /* block_align */ - st->codec->bit_rate = bytestream_get_le32(&p) * 8; + st->codec->channels = bytestream2_get_le16(&p); + bytestream2_skip(&p, 2); /* block_align */ + st->codec->bit_rate = bytestream2_get_le32(&p) * 8; st->codec->sample_rate = time_unit ? spu * 10000000 / time_unit : 0; avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) { - p += 4; + bytestream2_skip(&p, 4); size -= 4; } if (size > 52) { av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52); size -= 52; - st->codec->extradata_size = size; - st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); - bytestream_get_buffer(&p, st->codec->extradata, size); + ff_alloc_extradata(st->codec, size); + bytestream2_get_buffer(&p, st->codec->extradata, st->codec->extradata_size); } } - } else if (*p == 3) { - if (os->psize > 8) - ff_vorbis_comment(s, &st->metadata, p+7, os->psize-8); + } else if (bytestream2_peek_byte(&p) == 3) { + bytestream2_skip(&p, 7); + if (bytestream2_get_bytes_left(&p) > 1) + ff_vorbis_comment(s, &st->metadata, p.buffer, bytestream2_get_bytes_left(&p) - 1); } return 1; @@ -125,15 +126,23 @@ ogm_dshow_header(AVFormatContext *s, int idx) if(*p != 1) return 1; + if (os->psize < 100) + return AVERROR_INVALIDDATA; t = AV_RL32(p + 96); if(t == 0x05589f80){ + if (os->psize < 184) + return AVERROR_INVALIDDATA; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68)); avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000); st->codec->width = AV_RL32(p + 176); st->codec->height = AV_RL32(p + 180); } else if(t == 0x05589f81){ + if (os->psize < 136) + return AVERROR_INVALIDDATA; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124)); st->codec->channels = AV_RL16(p + 126); diff --git a/ffmpeg/libavformat/oggparseopus.c b/ffmpeg/libavformat/oggparseopus.c index 0e8f1ca..aafefbb 100644 --- a/ffmpeg/libavformat/oggparseopus.c +++ b/ffmpeg/libavformat/oggparseopus.c @@ -36,35 +36,34 @@ struct oggopus_private { static int opus_header(AVFormatContext *avf, int idx) { - struct ogg *ogg = avf->priv_data; - struct ogg_stream *os = &ogg->streams[idx]; - AVStream *st = avf->streams[idx]; + struct ogg *ogg = avf->priv_data; + struct ogg_stream *os = &ogg->streams[idx]; + AVStream *st = avf->streams[idx]; struct oggopus_private *priv = os->private; - uint8_t *packet = os->buf + os->pstart; - uint8_t *extradata; + uint8_t *packet = os->buf + os->pstart; if (!priv) { priv = os->private = av_mallocz(sizeof(*priv)); if (!priv) return AVERROR(ENOMEM); } + if (os->flags & OGG_FLAG_BOS) { if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0) return AVERROR_INVALIDDATA; - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = AV_CODEC_ID_OPUS; - st->codec->channels = AV_RL8 (packet + 9); - priv->pre_skip = AV_RL16(packet + 10); - /*orig_sample_rate = AV_RL32(packet + 12);*/ - /*gain = AV_RL16(packet + 16);*/ - /*channel_map = AV_RL8 (packet + 18);*/ - - extradata = av_malloc(os->psize + FF_INPUT_BUFFER_PADDING_SIZE); - if (!extradata) + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = AV_CODEC_ID_OPUS; + st->codec->channels = AV_RL8 (packet + 9); + priv->pre_skip = AV_RL16(packet + 10); + st->codec->delay = priv->pre_skip; + /*orig_sample_rate = AV_RL32(packet + 12);*/ + /*gain = AV_RL16(packet + 16);*/ + /*channel_map = AV_RL8 (packet + 18);*/ + + if (ff_alloc_extradata(st->codec, os->psize)) return AVERROR(ENOMEM); - memcpy(extradata, packet, os->psize); - st->codec->extradata = extradata; - st->codec->extradata_size = os->psize; + + memcpy(st->codec->extradata, packet, os->psize); st->codec->sample_rate = 48000; avpriv_set_pts_info(st, 64, 1, 48000); @@ -79,57 +78,104 @@ static int opus_header(AVFormatContext *avf, int idx) priv->need_comments--; return 1; } + return 0; } +static int opus_duration(uint8_t *src, int size) +{ + unsigned nb_frames = 1; + unsigned toc = src[0]; + unsigned toc_config = toc >> 3; + unsigned toc_count = toc & 3; + unsigned frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) : + toc_config < 16 ? 480 << (toc_config & 1) : + 120 << (toc_config & 3); + if (toc_count == 3) { + if (size<2) + return AVERROR_INVALIDDATA; + nb_frames = src[1] & 0x3F; + } else if (toc_count) { + nb_frames = 2; + } + + return frame_size * nb_frames; +} + static int opus_packet(AVFormatContext *avf, int idx) { - struct ogg *ogg = avf->priv_data; - struct ogg_stream *os = &ogg->streams[idx]; - AVStream *st = avf->streams[idx]; + struct ogg *ogg = avf->priv_data; + struct ogg_stream *os = &ogg->streams[idx]; + AVStream *st = avf->streams[idx]; struct oggopus_private *priv = os->private; - uint8_t *packet = os->buf + os->pstart; - unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1; + uint8_t *packet = os->buf + os->pstart; + int ret; if (!os->psize) return AVERROR_INVALIDDATA; - toc = *packet; - toc_config = toc >> 3; - toc_count = toc & 3; - frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) : - toc_config < 16 ? 480 << (toc_config & 1) : - 120 << (toc_config & 3); - if (toc_count == 3) { - if (os->psize < 2) - return AVERROR_INVALIDDATA; - nb_frames = packet[1] & 0x3F; - } else if (toc_count) { - nb_frames = 2; + + if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { + int seg, d; + int duration; + uint8_t *last_pkt = os->buf + os->pstart; + uint8_t *next_pkt = last_pkt; + + duration = 0; + seg = os->segp; + d = opus_duration(last_pkt, os->psize); + if (d < 0) { + os->pflags |= AV_PKT_FLAG_CORRUPT; + return 0; + } + duration += d; + last_pkt = next_pkt = next_pkt + os->psize; + for (; seg < os->nsegs; seg++) { + if (os->segments[seg] < 255) { + int d = opus_duration(last_pkt, os->segments[seg]); + if (d < 0) { + duration = os->granule; + break; + } + duration += d; + last_pkt = next_pkt + os->segments[seg]; + } + next_pkt += os->segments[seg]; + } + os->lastpts = + os->lastdts = os->granule - duration; } - os->pduration = frame_size * nb_frames; + + if ((ret = opus_duration(packet, os->psize)) < 0) + return ret; + + os->pduration = ret; if (os->lastpts != AV_NOPTS_VALUE) { if (st->start_time == AV_NOPTS_VALUE) st->start_time = os->lastpts; priv->cur_dts = os->lastdts = os->lastpts -= priv->pre_skip; } + priv->cur_dts += os->pduration; if ((os->flags & OGG_FLAG_EOS)) { int64_t skip = priv->cur_dts - os->granule + priv->pre_skip; skip = FFMIN(skip, os->pduration); if (skip > 0) { os->pduration = skip < os->pduration ? os->pduration - skip : 1; - av_log(avf, AV_LOG_WARNING, - "Last packet must be truncated to %d (unimplemented).\n", + os->end_trimming = skip; + av_log(avf, AV_LOG_DEBUG, + "Last packet was truncated to %d due to end trimming.\n", os->pduration); } } + return 0; } const struct ogg_codec ff_opus_codec = { - .name = "Opus", - .magic = "OpusHead", - .magicsize = 8, - .header = opus_header, - .packet = opus_packet, + .name = "Opus", + .magic = "OpusHead", + .magicsize = 8, + .header = opus_header, + .packet = opus_packet, + .nb_header = 1, }; diff --git a/ffmpeg/libavformat/oggparseskeleton.c b/ffmpeg/libavformat/oggparseskeleton.c index 307387d..d94b0c2 100644 --- a/ffmpeg/libavformat/oggparseskeleton.c +++ b/ffmpeg/libavformat/oggparseskeleton.c @@ -37,6 +37,9 @@ static int skeleton_header(AVFormatContext *s, int idx) strcpy(st->codec->codec_name, "skeleton"); st->codec->codec_type = AVMEDIA_TYPE_DATA; + if ((os->flags & OGG_FLAG_EOS) && os->psize == 0) + return 1; + if (os->psize < 8) return -1; @@ -74,12 +77,16 @@ static int skeleton_header(AVFormatContext *s, int idx) target_idx = ogg_find_stream(ogg, AV_RL32(buf+12)); start_granule = AV_RL64(buf+36); + if (target_idx < 0) { + av_log(s, AV_LOG_WARNING, "Serial number in fisbone doesn't match any stream\n"); + return 1; + } + os = ogg->streams + target_idx; if (os->start_granule != OGG_NOGRANULE_VALUE) { - avpriv_report_missing_feature(s, - "Multiple fisbone for the same stream"); + av_log(s, AV_LOG_WARNING, "Multiple fisbone for the same stream\n"); return 1; } - if (target_idx >= 0 && start_granule != OGG_NOGRANULE_VALUE) { + if (start_granule != OGG_NOGRANULE_VALUE) { os->start_granule = start_granule; } } diff --git a/ffmpeg/libavformat/oggparsespeex.c b/ffmpeg/libavformat/oggparsespeex.c index 63e6370..1b9de9c 100644 --- a/ffmpeg/libavformat/oggparsespeex.c +++ b/ffmpeg/libavformat/oggparsespeex.c @@ -77,9 +77,8 @@ static int speex_header(AVFormatContext *s, int idx) { if (frames_per_packet) spxp->packet_size *= frames_per_packet; - st->codec->extradata_size = os->psize; - st->codec->extradata = av_malloc(st->codec->extradata_size - + FF_INPUT_BUFFER_PADDING_SIZE); + if (ff_alloc_extradata(st->codec, os->psize) < 0) + return AVERROR(ENOMEM); memcpy(st->codec->extradata, p, st->codec->extradata_size); avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); diff --git a/ffmpeg/libavformat/oggparsetheora.c b/ffmpeg/libavformat/oggparsetheora.c index 6877d1e..59df17e 100644 --- a/ffmpeg/libavformat/oggparsetheora.c +++ b/ffmpeg/libavformat/oggparsetheora.c @@ -1,26 +1,26 @@ /** - Copyright (C) 2005 Matthieu CASTET, Alex Beregszaszi - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -**/ + * Copyright (C) 2005 Matthieu CASTET, Alex Beregszaszi + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + **/ #include <stdlib.h> #include "libavutil/bswap.h" @@ -29,64 +29,67 @@ #include "internal.h" #include "oggdec.h" -struct theora_params { +typedef struct TheoraParams { int gpshift; int gpmask; unsigned version; -}; +} TheoraParams; -static int -theora_header (AVFormatContext * s, int idx) +static int theora_header(AVFormatContext *s, int idx) { - struct ogg *ogg = s->priv_data; + struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; - AVStream *st = s->streams[idx]; - struct theora_params *thp = os->private; - int cds = st->codec->extradata_size + os->psize + 2; + AVStream *st = s->streams[idx]; + TheoraParams *thp = os->private; + int cds = st->codec->extradata_size + os->psize + 2; + int err; uint8_t *cdp; - if(!(os->buf[os->pstart] & 0x80)) + if (!(os->buf[os->pstart] & 0x80)) return 0; - if(!thp){ + if (!thp) { thp = av_mallocz(sizeof(*thp)); + if (!thp) + return AVERROR(ENOMEM); os->private = thp; } switch (os->buf[os->pstart]) { case 0x80: { GetBitContext gb; - int width, height; AVRational timebase; - init_get_bits(&gb, os->buf + os->pstart, os->psize*8); + init_get_bits(&gb, os->buf + os->pstart, os->psize * 8); - skip_bits_long(&gb, 7*8); /* 0x80"theora" */ + /* 0x80"theora" */ + skip_bits_long(&gb, 7 * 8); thp->version = get_bits_long(&gb, 24); - if (thp->version < 0x030100) - { + if (thp->version < 0x030100) { av_log(s, AV_LOG_ERROR, - "Too old or unsupported Theora (%x)\n", thp->version); - return -1; + "Too old or unsupported Theora (%x)\n", thp->version); + return AVERROR(ENOSYS); } - width = get_bits(&gb, 16) << 4; - height = get_bits(&gb, 16) << 4; - avcodec_set_dimensions(st->codec, width, height); + st->codec->width = get_bits(&gb, 16) << 4; + st->codec->height = get_bits(&gb, 16) << 4; if (thp->version >= 0x030400) skip_bits(&gb, 100); if (thp->version >= 0x030200) { - width = get_bits_long(&gb, 24); - height = get_bits_long(&gb, 24); - if ( width <= st->codec->width && width > st->codec->width-16 - && height <= st->codec->height && height > st->codec->height-16) - avcodec_set_dimensions(st->codec, width, height); + int width = get_bits_long(&gb, 24); + int height = get_bits_long(&gb, 24); + if (width <= st->codec->width && width > st->codec->width - 16 && + height <= st->codec->height && height > st->codec->height - 16) { + st->codec->width = width; + st->codec->height = height; + } skip_bits(&gb, 16); } + timebase.den = get_bits_long(&gb, 32); timebase.num = get_bits_long(&gb, 32); if (!(timebase.num > 0 && timebase.den > 0)) { @@ -105,41 +108,46 @@ theora_header (AVFormatContext * s, int idx) skip_bits(&gb, 2); thp->gpshift = get_bits(&gb, 5); - thp->gpmask = (1 << thp->gpshift) - 1; + thp->gpmask = (1 << thp->gpshift) - 1; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = AV_CODEC_ID_THEORA; - st->need_parsing = AVSTREAM_PARSE_HEADERS; + st->codec->codec_id = AV_CODEC_ID_THEORA; + st->need_parsing = AVSTREAM_PARSE_HEADERS; } break; case 0x81: ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7); case 0x82: if (!thp->version) - return -1; + return AVERROR_INVALIDDATA; break; default: av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]); - return -1; + return AVERROR_INVALIDDATA; + } + + if ((err = av_reallocp(&st->codec->extradata, + cds + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { + st->codec->extradata_size = 0; + return err; } + memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE); - st->codec->extradata = av_realloc (st->codec->extradata, - cds + FF_INPUT_BUFFER_PADDING_SIZE); - cdp = st->codec->extradata + st->codec->extradata_size; + cdp = st->codec->extradata + st->codec->extradata_size; *cdp++ = os->psize >> 8; *cdp++ = os->psize & 0xff; - memcpy (cdp, os->buf + os->pstart, os->psize); + memcpy(cdp, os->buf + os->pstart, os->psize); st->codec->extradata_size = cds; return 1; } -static uint64_t -theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts) +static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, + int64_t *dts) { - struct ogg *ogg = ctx->priv_data; + struct ogg *ogg = ctx->priv_data; struct ogg_stream *os = ogg->streams + idx; - struct theora_params *thp = os->private; + TheoraParams *thp = os->private; uint64_t iframe, pframe; if (!thp) @@ -151,7 +159,7 @@ theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts) if (thp->version < 0x030201) iframe++; - if(!pframe) + if (!pframe) os->pflags |= AV_PKT_FLAG_KEY; if (dts) @@ -197,10 +205,10 @@ static int theora_packet(AVFormatContext *s, int idx) } const struct ogg_codec ff_theora_codec = { - .magic = "\200theora", + .magic = "\200theora", .magicsize = 7, - .header = theora_header, - .packet = theora_packet, - .gptopts = theora_gptopts, + .header = theora_header, + .packet = theora_packet, + .gptopts = theora_gptopts, .nb_header = 3, }; diff --git a/ffmpeg/libavformat/oggparsevorbis.c b/ffmpeg/libavformat/oggparsevorbis.c index da029a4..36ad738 100644 --- a/ffmpeg/libavformat/oggparsevorbis.c +++ b/ffmpeg/libavformat/oggparsevorbis.c @@ -1,35 +1,38 @@ -/** - Copyright (C) 2005 Michael Ahlberg, MÃ¥ns RullgÃ¥rd - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -**/ +/* + * Copyright (C) 2005 Michael Ahlberg, MÃ¥ns RullgÃ¥rd + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ #include <stdlib.h> + #include "libavutil/avstring.h" +#include "libavutil/base64.h" #include "libavutil/bswap.h" #include "libavutil/dict.h" -#include "libavcodec/get_bits.h" #include "libavcodec/bytestream.h" +#include "libavcodec/get_bits.h" #include "libavcodec/vorbis_parser.h" #include "avformat.h" +#include "flac_picture.h" #include "internal.h" #include "oggdec.h" #include "vorbiscomment.h" @@ -39,19 +42,19 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) int i, cnum, h, m, s, ms, keylen = strlen(key); AVChapter *chapter = NULL; - if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1) + if (keylen < 9 || sscanf(key, "CHAPTER%03d", &cnum) != 1) return 0; - if (keylen == 9) { + if (keylen <= 10) { if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4) return 0; - avpriv_new_chapter(as, cnum, (AVRational){1,1000}, - ms + 1000*(s + 60*(m + 60*h)), - AV_NOPTS_VALUE, NULL); + avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 }, + ms + 1000 * (s + 60 * (m + 60 * h)), + AV_NOPTS_VALUE, NULL); av_free(val); - } else if (!strcmp(key+9, "NAME")) { - for(i = 0; i < as->nb_chapters; i++) + } else if (!strcmp(key + keylen - 4, "NAME")) { + for (i = 0; i < as->nb_chapters; i++) if (as->chapters[i]->id == cnum) { chapter = as->chapters[i]; break; @@ -59,8 +62,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) if (!chapter) return 0; - av_dict_set(&chapter->metadata, "title", val, - AV_DICT_DONT_STRDUP_VAL); + av_dict_set(&chapter->metadata, "title", val, AV_DICT_DONT_STRDUP_VAL); } else return 0; @@ -68,21 +70,22 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) return 1; } -int -ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, int size) +int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, + const uint8_t *buf, int size) { - const uint8_t *p = buf; + const uint8_t *p = buf; const uint8_t *end = buf + size; unsigned n, j; int s; - if (size < 8) /* must have vendor_length and user_comment_list_length */ - return -1; + /* must have vendor_length and user_comment_list_length */ + if (size < 8) + return AVERROR_INVALIDDATA; s = bytestream_get_le32(&p); if (end - p - 4 < s || s < 0) - return -1; + return AVERROR_INVALIDDATA; p += s; @@ -97,7 +100,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in if (end - p < s || s < 0) break; - t = p; + t = p; p += s; n--; @@ -117,8 +120,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in if (!tt || !ct) { av_freep(&tt); av_freep(&ct); - av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n"); - continue; + return AVERROR(ENOMEM); } for (j = 0; j < tl; j++) @@ -128,15 +130,41 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in memcpy(ct, v, vl); ct[vl] = 0; - if (!ogm_chapter(as, tt, ct)) + /* The format in which the pictures are stored is the FLAC format. + * Xiph says: "The binary FLAC picture structure is base64 encoded + * and placed within a VorbisComment with the tag name + * 'METADATA_BLOCK_PICTURE'. This is the preferred and + * recommended way of embedding cover art within VorbisComments." + */ + if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) { + int ret; + char *pict = av_malloc(vl); + + if (!pict) { + av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n"); + av_freep(&tt); + av_freep(&ct); + continue; + } + if ((ret = av_base64_decode(pict, ct, vl)) > 0) + ret = ff_flac_parse_picture(as, pict, ret); + av_freep(&tt); + av_freep(&ct); + av_freep(&pict); + if (ret < 0) { + av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); + continue; + } + } else if (!ogm_chapter(as, tt, ct)) av_dict_set(m, tt, ct, - AV_DICT_DONT_STRDUP_KEY | - AV_DICT_DONT_STRDUP_VAL); + AV_DICT_DONT_STRDUP_KEY | + AV_DICT_DONT_STRDUP_VAL); } } if (p != end) - av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p); + av_log(as, AV_LOG_INFO, + "%ti bytes of comment header remain\n", end - p); if (n > 0) av_log(as, AV_LOG_INFO, "truncated comment header, %i comments not found\n", n); @@ -146,8 +174,9 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in return 0; } - -/** Parse the vorbis header +/* + * Parse the vorbis header + * * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec * [vorbis_version] = read 32 bits as unsigned integer | Not used * [audio_channels] = read 8 bit integer as unsigned | Used @@ -158,7 +187,7 @@ ff_vorbis_comment(AVFormatContext * as, AVDictionary **m, const uint8_t *buf, in * [blocksize_0] = read 4 bits as unsigned integer | Not Used * [blocksize_1] = read 4 bits as unsigned integer | Not Used * [framing_flag] = read one bit | Not Used - * */ + */ struct oggvorbis_private { unsigned int len[3]; @@ -168,23 +197,23 @@ struct oggvorbis_private { int final_duration; }; - -static unsigned int -fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv, - uint8_t **buf) +static int fixup_vorbis_headers(AVFormatContext *as, + struct oggvorbis_private *priv, + uint8_t **buf) { - int i,offset, len, buf_len; + int i, offset, len, err; + int buf_len; unsigned char *ptr; len = priv->len[0] + priv->len[1] + priv->len[2]; - buf_len = len + len/255 + 64; + buf_len = len + len / 255 + 64; ptr = *buf = av_realloc(NULL, buf_len); - if (!*buf) - return 0; + if (!ptr) + return AVERROR(ENOMEM); memset(*buf, '\0', buf_len); - ptr[0] = 2; - offset = 1; + ptr[0] = 2; + offset = 1; offset += av_xiphlacing(&ptr[offset], priv->len[0]); offset += av_xiphlacing(&ptr[offset], priv->len[1]); for (i = 0; i < 3; i++) { @@ -192,7 +221,8 @@ fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv, offset += priv->len[i]; av_freep(&priv->packet[i]); } - *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE); + if ((err = av_reallocp(buf, offset + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) + return err; return offset; } @@ -207,35 +237,34 @@ static void vorbis_cleanup(AVFormatContext *s, int idx) av_freep(&priv->packet[i]); } -static int -vorbis_header (AVFormatContext * s, int idx) +static int vorbis_header(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; + AVStream *st = s->streams[idx]; struct ogg_stream *os = ogg->streams + idx; - AVStream *st = s->streams[idx]; struct oggvorbis_private *priv; int pkt_type = os->buf[os->pstart]; - if (!(pkt_type & 1)) - return os->private ? 0 : -1; - if (!os->private) { os->private = av_mallocz(sizeof(struct oggvorbis_private)); if (!os->private) - return -1; + return AVERROR(ENOMEM); } + if (!(pkt_type & 1)) + return 0; + if (os->psize < 1 || pkt_type > 5) - return -1; + return AVERROR_INVALIDDATA; priv = os->private; - if (priv->packet[pkt_type>>1]) - return -1; + if (priv->packet[pkt_type >> 1]) + return AVERROR_INVALIDDATA; if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) - return -1; + return AVERROR_INVALIDDATA; - priv->len[pkt_type >> 1] = os->psize; + priv->len[pkt_type >> 1] = os->psize; priv->packet[pkt_type >> 1] = av_mallocz(os->psize); if (!priv->packet[pkt_type >> 1]) return AVERROR(ENOMEM); @@ -247,36 +276,36 @@ vorbis_header (AVFormatContext * s, int idx) int channels; if (os->psize != 30) - return -1; + return AVERROR_INVALIDDATA; if (bytestream_get_le32(&p) != 0) /* vorbis_version */ - return -1; + return AVERROR_INVALIDDATA; - channels= bytestream_get_byte(&p); + channels = bytestream_get_byte(&p); if (st->codec->channels && channels != st->codec->channels) { av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); return AVERROR_PATCHWELCOME; } st->codec->channels = channels; - srate = bytestream_get_le32(&p); + srate = bytestream_get_le32(&p); p += 4; // skip maximum bitrate st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate p += 4; // skip minimum bitrate blocksize = bytestream_get_byte(&p); - bs0 = blocksize & 15; - bs1 = blocksize >> 4; + bs0 = blocksize & 15; + bs1 = blocksize >> 4; if (bs0 > bs1) - return -1; + return AVERROR_INVALIDDATA; if (bs0 < 6 || bs1 > 13) - return -1; + return AVERROR_INVALIDDATA; if (bytestream_get_byte(&p) != 1) /* framing_flag */ - return -1; + return AVERROR_INVALIDDATA; st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = AV_CODEC_ID_VORBIS; + st->codec->codec_id = AV_CODEC_ID_VORBIS; if (srate > 0) { st->codec->sample_rate = srate; @@ -284,19 +313,23 @@ vorbis_header (AVFormatContext * s, int idx) } } else if (os->buf[os->pstart] == 3) { if (os->psize > 8 && - ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8) >= 0) { + ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, + os->psize - 8) >= 0) { // drop all metadata we parsed and which is not required by libvorbis unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; if (new_len >= 16 && new_len < os->psize) { AV_WL32(priv->packet[1] + new_len - 5, 0); priv->packet[1][new_len - 1] = 1; - priv->len[1] = new_len; + priv->len[1] = new_len; } } } else { - int ret; - st->codec->extradata_size = - fixup_vorbis_headers(s, priv, &st->codec->extradata); + int ret = fixup_vorbis_headers(s, priv, &st->codec->extradata); + if (ret < 0) { + st->codec->extradata_size = 0; + return ret; + } + st->codec->extradata_size = ret; if ((ret = avpriv_vorbis_parse_extradata(st->codec, &priv->vp))) { av_freep(&st->codec->extradata); st->codec->extradata_size = 0; @@ -315,13 +348,13 @@ static int vorbis_packet(AVFormatContext *s, int idx) int duration; /* first packet handling - here we parse the duration of each packet in the first page and compare - the total duration to the page granule to find the encoder delay and - set the first timestamp */ + * here we parse the duration of each packet in the first page and compare + * the total duration to the page granule to find the encoder delay and + * set the first timestamp */ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { int seg, d; - uint8_t *last_pkt = os->buf + os->pstart; - uint8_t *next_pkt = last_pkt; + uint8_t *last_pkt = os->buf + os->pstart; + uint8_t *next_pkt = last_pkt; avpriv_vorbis_parse_reset(&priv->vp); duration = 0; @@ -341,17 +374,18 @@ static int vorbis_packet(AVFormatContext *s, int idx) break; } duration += d; - last_pkt = next_pkt + os->segments[seg]; + last_pkt = next_pkt + os->segments[seg]; } next_pkt += os->segments[seg]; } - os->lastpts = os->lastdts = os->granule - duration; - if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { + os->lastpts = + os->lastdts = os->granule - duration; + if (s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = FFMAX(os->lastpts, 0); if (s->streams[idx]->duration) s->streams[idx]->duration -= s->streams[idx]->start_time; } - priv->final_pts = AV_NOPTS_VALUE; + priv->final_pts = AV_NOPTS_VALUE; avpriv_vorbis_parse_reset(&priv->vp); } @@ -366,12 +400,12 @@ static int vorbis_packet(AVFormatContext *s, int idx) } /* final packet handling - here we save the pts of the first packet in the final page, sum up all - packet durations in the final page except for the last one, and compare - to the page granule to find the duration of the final packet */ + * here we save the pts of the first packet in the final page, sum up all + * packet durations in the final page except for the last one, and compare + * to the page granule to find the duration of the final packet */ if (os->flags & OGG_FLAG_EOS) { if (os->lastpts != AV_NOPTS_VALUE) { - priv->final_pts = os->lastpts; + priv->final_pts = os->lastpts; priv->final_duration = 0; } if (os->segp == os->nsegs) @@ -383,10 +417,10 @@ static int vorbis_packet(AVFormatContext *s, int idx) } const struct ogg_codec ff_vorbis_codec = { - .magic = "\001vorbis", + .magic = "\001vorbis", .magicsize = 7, - .header = vorbis_header, - .packet = vorbis_packet, - .cleanup= vorbis_cleanup, + .header = vorbis_header, + .packet = vorbis_packet, + .cleanup = vorbis_cleanup, .nb_header = 3, }; diff --git a/ffmpeg/libavformat/oma.c b/ffmpeg/libavformat/oma.c index 9e4bfbd..2702867 100644 --- a/ffmpeg/libavformat/oma.c +++ b/ffmpeg/libavformat/oma.c @@ -21,8 +21,9 @@ #include "internal.h" #include "oma.h" #include "libavcodec/avcodec.h" +#include "libavutil/channel_layout.h" -const uint16_t ff_oma_srate_tab[8] = { 320, 441, 480, 882, 960, 0, 0, 0}; +const uint16_t ff_oma_srate_tab[8] = { 320, 441, 480, 882, 960, 0 }; const AVCodecTag ff_oma_codec_tags[] = { { AV_CODEC_ID_ATRAC3, OMA_CODECID_ATRAC3 }, @@ -32,3 +33,16 @@ const AVCodecTag ff_oma_codec_tags[] = { { 0 }, }; +/** map ATRAC-X channel id to internal channel layout */ +const uint64_t ff_oma_chid_to_native_layout[7] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_6POINT1_BACK, + AV_CH_LAYOUT_7POINT1 +}; + +/** map ATRAC-X channel id to total number of channels */ +const int ff_oma_chid_to_num_channels[7] = {1, 2, 3, 4, 6, 7, 8}; diff --git a/ffmpeg/libavformat/oma.h b/ffmpeg/libavformat/oma.h index 1f0ddf9..e2a187b 100644 --- a/ffmpeg/libavformat/oma.h +++ b/ffmpeg/libavformat/oma.h @@ -1,20 +1,20 @@ /* * Sony OpenMG (OMA) common data * - * 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 */ @@ -41,4 +41,7 @@ extern const uint16_t ff_oma_srate_tab[8]; extern const AVCodecTag ff_oma_codec_tags[]; +extern const uint64_t ff_oma_chid_to_native_layout[7]; +extern const int ff_oma_chid_to_num_channels[7]; + #endif /* AVFORMAT_OMA_H */ diff --git a/ffmpeg/libavformat/omadec.c b/ffmpeg/libavformat/omadec.c index 9f65db0..6a08076 100644 --- a/ffmpeg/libavformat/omadec.c +++ b/ffmpeg/libavformat/omadec.c @@ -1,7 +1,7 @@ /* * Sony OpenMG (OMA) demuxer * - * Copyright (c) 2008 Maxim Poliakovski + * Copyright (c) 2008, 2013 Maxim Poliakovski * 2008 Benjamin Larsson * 2011 David Goldwich * @@ -73,18 +73,20 @@ typedef struct OMAContext { struct AVDES av_des; } OMAContext; -static void hex_log(AVFormatContext *s, int level, const char *name, const uint8_t *value, int len) +static void hex_log(AVFormatContext *s, int level, + const char *name, const uint8_t *value, int len) { char buf[33]; len = FFMIN(len, 16); if (av_log_get_level() < level) return; ff_data_to_hex(buf, value, len, 1); - buf[len<<1] = '\0'; + buf[len << 1] = '\0'; av_log(s, level, "%s: %s\n", name, buf); } -static int kset(AVFormatContext *s, const uint8_t *r_val, const uint8_t *n_val, int len) +static int kset(AVFormatContext *s, const uint8_t *r_val, const uint8_t *n_val, + int len) { OMAContext *oc = s->priv_data; @@ -112,13 +114,18 @@ static int kset(AVFormatContext *s, const uint8_t *r_val, const uint8_t *n_val, return 0; } -static int rprobe(AVFormatContext *s, uint8_t *enc_header, const uint8_t *r_val) +#define OMA_RPROBE_M_VAL 48 + 1 + +static int rprobe(AVFormatContext *s, uint8_t *enc_header, unsigned size, + const uint8_t *r_val) { OMAContext *oc = s->priv_data; unsigned int pos; struct AVDES av_des; - if (!enc_header || !r_val) + if (!enc_header || !r_val || + size < OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size || + size < OMA_RPROBE_M_VAL) return -1; /* m_val */ @@ -139,35 +146,41 @@ static int rprobe(AVFormatContext *s, uint8_t *enc_header, const uint8_t *r_val) return memcmp(&enc_header[pos], oc->sm_val, 8) ? -1 : 0; } -static int nprobe(AVFormatContext *s, uint8_t *enc_header, int size, const uint8_t *n_val) +static int nprobe(AVFormatContext *s, uint8_t *enc_header, unsigned size, + const uint8_t *n_val) { OMAContext *oc = s->priv_data; - uint32_t pos, taglen, datalen; + uint64_t pos; + uint32_t taglen, datalen; struct AVDES av_des; - if (!enc_header || !n_val) + if (!enc_header || !n_val || + size < OMA_ENC_HEADER_SIZE + oc->k_size + 4) return -1; pos = OMA_ENC_HEADER_SIZE + oc->k_size; if (!memcmp(&enc_header[pos], "EKB ", 4)) pos += 32; + if (size < pos + 44) + return -1; + if (AV_RB32(&enc_header[pos]) != oc->rid) av_log(s, AV_LOG_DEBUG, "Mismatching RID\n"); - taglen = AV_RB32(&enc_header[pos+32]); - datalen = AV_RB32(&enc_header[pos+36]) >> 4; + taglen = AV_RB32(&enc_header[pos + 32]); + datalen = AV_RB32(&enc_header[pos + 36]) >> 4; - if(pos + (uint64_t)taglen + (((uint64_t)datalen)<<4) + 44 > size) - return -1; + pos += 44L + taglen; - pos += 44 + taglen; + if (pos + (((uint64_t)datalen) << 4) > size) + return -1; av_des_init(&av_des, n_val, 192, 1); while (datalen-- > 0) { av_des_crypt(&av_des, oc->r_val, &enc_header[pos], 2, NULL, 1); kset(s, oc->r_val, NULL, 16); - if (!rprobe(s, enc_header, oc->r_val)) + if (!rprobe(s, enc_header, size, oc->r_val)) return 0; pos += 16; } @@ -196,12 +209,13 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) } if (!em) { av_log(s, AV_LOG_ERROR, "No encryption header found\n"); - return -1; + return AVERROR_INVALIDDATA; } if (geob->datasize < 64) { - av_log(s, AV_LOG_ERROR, "Invalid GEOB data size: %u\n", geob->datasize); - return -1; + av_log(s, AV_LOG_ERROR, + "Invalid GEOB data size: %u\n", geob->datasize); + return AVERROR_INVALIDDATA; } gdata = geob->data; @@ -216,11 +230,10 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) if (memcmp(&gdata[OMA_ENC_HEADER_SIZE], "KEYRING ", 12)) { av_log(s, AV_LOG_ERROR, "Invalid encryption header\n"); - return -1; + return AVERROR_INVALIDDATA; } - if ( OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size + 8 > geob->datasize - || OMA_ENC_HEADER_SIZE + 48 > geob->datasize - ) { + if (OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size + 8 > geob->datasize || + OMA_ENC_HEADER_SIZE + 48 > geob->datasize) { av_log(s, AV_LOG_ERROR, "Too little GEOB data\n"); return AVERROR_INVALIDDATA; } @@ -230,32 +243,36 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) memcpy(oc->iv, &header[0x58], 8); hex_log(s, AV_LOG_DEBUG, "IV", oc->iv, 8); - hex_log(s, AV_LOG_DEBUG, "CBC-MAC", &gdata[OMA_ENC_HEADER_SIZE+oc->k_size+oc->e_size+oc->i_size], 8); + hex_log(s, AV_LOG_DEBUG, "CBC-MAC", + &gdata[OMA_ENC_HEADER_SIZE + oc->k_size + oc->e_size + oc->i_size], + 8); if (s->keylen > 0) { kset(s, s->key, s->key, s->keylen); } if (!memcmp(oc->r_val, (const uint8_t[8]){0}, 8) || - rprobe(s, gdata, oc->r_val) < 0 && + rprobe(s, gdata, geob->datasize, oc->r_val) < 0 && nprobe(s, gdata, geob->datasize, oc->n_val) < 0) { int i; for (i = 0; i < FF_ARRAY_ELEMS(leaf_table); i += 2) { uint8_t buf[16]; - AV_WL64(buf, leaf_table[i]); - AV_WL64(&buf[8], leaf_table[i+1]); + AV_WL64(buf, leaf_table[i]); + AV_WL64(&buf[8], leaf_table[i + 1]); kset(s, buf, buf, 16); - if (!rprobe(s, gdata, oc->r_val) || !nprobe(s, gdata, geob->datasize, oc->n_val)) + if (!rprobe(s, gdata, geob->datasize, oc->r_val) || + !nprobe(s, gdata, geob->datasize, oc->n_val)) break; } if (i >= FF_ARRAY_ELEMS(leaf_table)) { av_log(s, AV_LOG_ERROR, "Invalid key\n"); - return -1; + return AVERROR_INVALIDDATA; } } /* e_val */ av_des_init(&oc->av_des, oc->m_val, 64, 0); - av_des_crypt(&oc->av_des, oc->e_val, &gdata[OMA_ENC_HEADER_SIZE + 40], 1, NULL, 0); + av_des_crypt(&oc->av_des, oc->e_val, + &gdata[OMA_ENC_HEADER_SIZE + 40], 1, NULL, 0); hex_log(s, AV_LOG_DEBUG, "EK", oc->e_val, 8); /* init e_val */ @@ -267,7 +284,7 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) static int oma_read_header(AVFormatContext *s) { int ret, framesize, jsflag, samplerate; - uint32_t codec_params; + uint32_t codec_params, channel_id; int16_t eid; uint8_t buf[EA3_HEADER_SIZE]; uint8_t *edata; @@ -280,9 +297,10 @@ static int oma_read_header(AVFormatContext *s) if (ret < EA3_HEADER_SIZE) return -1; - if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) { + if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}), 3) || + buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) { av_log(s, AV_LOG_ERROR, "Couldn't find the EA3 header !\n"); - return -1; + return AVERROR_INVALIDDATA; } oc->content_start = avio_tell(s->pb); @@ -303,65 +321,85 @@ static int oma_read_header(AVFormatContext *s) return AVERROR(ENOMEM); st->start_time = 0; - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_tag = buf[32]; - st->codec->codec_id = ff_codec_get_id(ff_oma_codec_tags, st->codec->codec_tag); + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_tag = buf[32]; + st->codec->codec_id = ff_codec_get_id(ff_oma_codec_tags, + st->codec->codec_tag); switch (buf[32]) { - case OMA_CODECID_ATRAC3: - samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7]*100; - if (samplerate != 44100) - avpriv_request_sample(s, "Sample rate %d", samplerate); - - framesize = (codec_params & 0x3FF) * 8; - jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */ - st->codec->channels = 2; - st->codec->channel_layout = AV_CH_LAYOUT_STEREO; - st->codec->sample_rate = samplerate; - st->codec->bit_rate = st->codec->sample_rate * framesize * 8 / 1024; - - /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */ - st->codec->extradata_size = 14; - edata = av_mallocz(14 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!edata) - return AVERROR(ENOMEM); - - st->codec->extradata = edata; - AV_WL16(&edata[0], 1); // always 1 - AV_WL32(&edata[2], samplerate); // samples rate - AV_WL16(&edata[6], jsflag); // coding mode - AV_WL16(&edata[8], jsflag); // coding mode - AV_WL16(&edata[10], 1); // always 1 - // AV_WL16(&edata[12], 0); // always 0 - - avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); - break; - case OMA_CODECID_ATRAC3P: - st->codec->channels = (codec_params >> 10) & 7; - framesize = ((codec_params & 0x3FF) * 8) + 8; - st->codec->sample_rate = ff_oma_srate_tab[(codec_params >> 13) & 7]*100; - st->codec->bit_rate = st->codec->sample_rate * framesize * 8 / 1024; - avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); - av_log(s, AV_LOG_ERROR, "Unsupported codec ATRAC3+!\n"); - break; - case OMA_CODECID_MP3: - st->need_parsing = AVSTREAM_PARSE_FULL_RAW; - framesize = 1024; - break; - case OMA_CODECID_LPCM: - /* PCM 44.1 kHz 16 bit stereo big-endian */ - st->codec->channels = 2; - st->codec->channel_layout = AV_CH_LAYOUT_STEREO; - st->codec->sample_rate = 44100; - framesize = 1024; - /* bit rate = sample rate x PCM block align (= 4) x 8 */ - st->codec->bit_rate = st->codec->sample_rate * 32; - st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id); - avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); - break; - default: - av_log(s, AV_LOG_ERROR, "Unsupported codec %d!\n",buf[32]); - return -1; + case OMA_CODECID_ATRAC3: + samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7] * 100; + if (!samplerate) { + av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n"); + return AVERROR_INVALIDDATA; + } + if (samplerate != 44100) + avpriv_request_sample(s, "Sample rate %d", samplerate); + + framesize = (codec_params & 0x3FF) * 8; + + /* get stereo coding mode, 1 for joint-stereo */ + jsflag = (codec_params >> 17) & 1; + + st->codec->channels = 2; + st->codec->channel_layout = AV_CH_LAYOUT_STEREO; + st->codec->sample_rate = samplerate; + st->codec->bit_rate = st->codec->sample_rate * framesize * 8 / 1024; + + /* fake the ATRAC3 extradata + * (wav format, makes stream copy to wav work) */ + if (ff_alloc_extradata(st->codec, 14)) + return AVERROR(ENOMEM); + + edata = st->codec->extradata; + AV_WL16(&edata[0], 1); // always 1 + AV_WL32(&edata[2], samplerate); // samples rate + AV_WL16(&edata[6], jsflag); // coding mode + AV_WL16(&edata[8], jsflag); // coding mode + AV_WL16(&edata[10], 1); // always 1 + // AV_WL16(&edata[12], 0); // always 0 + + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + break; + case OMA_CODECID_ATRAC3P: + channel_id = (codec_params >> 10) & 7; + if (!channel_id) { + av_log(s, AV_LOG_ERROR, + "Invalid ATRAC-X channel id: %d\n", channel_id); + return AVERROR_INVALIDDATA; + } + st->codec->channel_layout = ff_oma_chid_to_native_layout[channel_id - 1]; + st->codec->channels = ff_oma_chid_to_num_channels[channel_id - 1]; + framesize = ((codec_params & 0x3FF) * 8) + 8; + samplerate = ff_oma_srate_tab[(codec_params >> 13) & 7] * 100; + if (!samplerate) { + av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n"); + return AVERROR_INVALIDDATA; + } + st->codec->sample_rate = samplerate; + st->codec->bit_rate = samplerate * framesize * 8 / 2048; + avpriv_set_pts_info(st, 64, 1, samplerate); + av_log(s, AV_LOG_ERROR, "Unsupported codec ATRAC3+!\n"); + break; + case OMA_CODECID_MP3: + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + framesize = 1024; + break; + case OMA_CODECID_LPCM: + /* PCM 44.1 kHz 16 bit stereo big-endian */ + st->codec->channels = 2; + st->codec->channel_layout = AV_CH_LAYOUT_STEREO; + st->codec->sample_rate = 44100; + framesize = 1024; + /* bit rate = sample rate x PCM block align (= 4) x 8 */ + st->codec->bit_rate = st->codec->sample_rate * 32; + st->codec->bits_per_coded_sample = + av_get_bits_per_sample(st->codec->codec_id); + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + break; + default: + av_log(s, AV_LOG_ERROR, "Unsupported codec %d!\n", buf[32]); + return AVERROR(ENOSYS); } st->codec->block_align = framesize; @@ -376,14 +414,24 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt) int packet_size = s->streams[0]->codec->block_align; int ret = av_get_packet(s->pb, pkt, packet_size); - if (ret <= 0) - return AVERROR(EIO); + if (ret < packet_size) + pkt->flags |= AV_PKT_FLAG_CORRUPT; + + if (ret < 0) + return ret; + if (!ret) + return AVERROR_EOF; pkt->stream_index = 0; if (oc->encrypted) { - /* previous unencrypted block saved in IV for the next packet (CBC mode) */ - av_des_crypt(&oc->av_des, pkt->data, pkt->data, (ret >> 3), oc->iv, 1); + /* previous unencrypted block saved in IV for + * the next packet (CBC mode) */ + if (ret == packet_size) + av_des_crypt(&oc->av_des, pkt->data, pkt->data, + (packet_size >> 3), oc->iv, 1); + else + memset(oc->iv, 0, 8); } return ret; @@ -391,23 +439,16 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt) static int oma_read_probe(AVProbeData *p) { - const uint8_t *buf; + const uint8_t *buf = p->buf; unsigned tag_len = 0; - buf = p->buf; - - if (p->buf_size < ID3v2_HEADER_SIZE || - !ff_id3v2_match(buf, ID3v2_EA3_MAGIC) || - buf[3] != 3 || // version must be 3 - buf[4]) // flags byte zero - return 0; - - tag_len = ff_id3v2_tag_len(buf); + if (p->buf_size >= ID3v2_HEADER_SIZE && ff_id3v2_match(buf, ID3v2_EA3_MAGIC)) + tag_len = ff_id3v2_tag_len(buf); /* This check cannot overflow as tag_len has at most 28 bits */ if (p->buf_size < tag_len + 5) /* EA3 header comes late, might be outside of the probe buffer */ - return AVPROBE_SCORE_MAX / 2; + return tag_len ? AVPROBE_SCORE_EXTENSION : 0; buf += tag_len; @@ -417,26 +458,30 @@ static int oma_read_probe(AVProbeData *p) return 0; } -static int oma_read_seek(struct AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +static int oma_read_seek(struct AVFormatContext *s, + int stream_index, int64_t timestamp, int flags) { OMAContext *oc = s->priv_data; - - ff_pcm_read_seek(s, stream_index, timestamp, flags); - - if (oc->encrypted) { - /* readjust IV for CBC */ - int64_t pos = avio_tell(s->pb); - if (pos < oc->content_start) - memset(oc->iv, 0, 8); - else { - if (avio_seek(s->pb, -8, SEEK_CUR) < 0 || avio_read(s->pb, oc->iv, 8) < 8) { - memset(oc->iv, 0, 8); - return -1; - } - } + int err = ff_pcm_read_seek(s, stream_index, timestamp, flags); + + if (!oc->encrypted) + return err; + + /* readjust IV for CBC */ + if (err || avio_tell(s->pb) < oc->content_start) + goto wipe; + if ((err = avio_seek(s->pb, -8, SEEK_CUR)) < 0) + goto wipe; + if ((err = avio_read(s->pb, oc->iv, 8)) < 8) { + if (err >= 0) + err = AVERROR_EOF; + goto wipe; } return 0; +wipe: + memset(oc->iv, 0, 8); + return err; } AVInputFormat ff_oma_demuxer = { diff --git a/ffmpeg/libavformat/omaenc.c b/ffmpeg/libavformat/omaenc.c index 5c5aff7..b947987 100644 --- a/ffmpeg/libavformat/omaenc.c +++ b/ffmpeg/libavformat/omaenc.c @@ -3,20 +3,20 @@ * * Copyright (c) 2011 Michael Karcher * - * 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 */ diff --git a/ffmpeg/libavformat/options.c b/ffmpeg/libavformat/options.c index 42307d1..5218e5b 100644 --- a/ffmpeg/libavformat/options.c +++ b/ffmpeg/libavformat/options.c @@ -86,7 +86,7 @@ static AVClassCategory get_category(void *ptr) static const AVClass av_format_context_class = { .class_name = "AVFormatContext", .item_name = format_to_name, - .option = options, + .option = avformat_options, .version = LIBAVUTIL_VERSION_INT, .child_next = format_child_next, .child_class_next = format_child_class_next, diff --git a/ffmpeg/libavformat/options_table.h b/ffmpeg/libavformat/options_table.h index 6750050..8145325 100644 --- a/ffmpeg/libavformat/options_table.h +++ b/ffmpeg/libavformat/options_table.h @@ -32,12 +32,13 @@ #define E AV_OPT_FLAG_ENCODING_PARAM #define D AV_OPT_FLAG_DECODING_PARAM -static const AVOption options[]={ +static const AVOption avformat_options[] = { {"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"}, {"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"}, {"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT, {.i64 = 5000000 }, 32, INT_MAX, D}, {"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, E}, -{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "fflags"}, +{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D|E, "fflags"}, +{"flush_packets", "reduce the latency by flushing out packets immediately", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D, "fflags"}, {"ignidx", "ignore index", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNIDX }, INT_MIN, INT_MAX, D, "fflags"}, {"genpts", "generate pts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_GENPTS }, INT_MIN, INT_MAX, D, "fflags"}, {"nofillin", "do not fill in missing values that can be exactly calculated", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOFILLIN }, INT_MIN, INT_MAX, D, "fflags"}, @@ -45,10 +46,10 @@ static const AVOption options[]={ {"igndts", "ignore dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNDTS }, INT_MIN, INT_MAX, D, "fflags"}, {"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"}, {"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"}, -{"keepside", "dont merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, +{"keepside", "don't merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, {"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, -{"seek2any", "forces seeking to enable seek to any mode", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D}, +{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D}, {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.i64 = 5*AV_TIME_BASE }, 0, INT_MAX, D}, {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, @@ -68,13 +69,14 @@ static const AVOption options[]={ {"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, D, "err_detect"}, {"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, D, "err_detect"}, {"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, D, "err_detect"}, -{"careful", "consider things that violate the spec and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"}, +{"careful", "consider things that violate the spec, are fast to check and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"}, {"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_COMPLIANT }, INT_MIN, INT_MAX, D, "err_detect"}, -{"aggressive", "consider things that a sane encoder shouldnt do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, D, "err_detect"}, +{"aggressive", "consider things that a sane encoder shouldn't do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, D, "err_detect"}, {"use_wallclock_as_timestamps", "use wallclock as timestamps", OFFSET(use_wallclock_as_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D}, -{"avoid_negative_ts", "shift timestamps to make them positive. 1 enables, 0 disables, default of -1 enables when required by target format.", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, E}, -{"skip_initial_bytes", "skip initial bytes", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D}, +{"avoid_negative_ts", "shift timestamps to make them non-negative. 1 enables, 0 disables, default of -1 enables when required by target format.", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, E}, +{"skip_initial_bytes", "set number of bytes to skip before reading header and frames", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D}, {"correct_ts_overflow", "correct single timestamp overflows", OFFSET(correct_ts_overflow), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D}, +{"flush_packets", "enable flushing of the I/O context after each packet", OFFSET(flush_packets), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E}, {NULL}, }; diff --git a/ffmpeg/libavformat/os_support.c b/ffmpeg/libavformat/os_support.c index 0a901f6..e8f063a 100644 --- a/ffmpeg/libavformat/os_support.c +++ b/ffmpeg/libavformat/os_support.c @@ -27,55 +27,18 @@ #include "avformat.h" #include "os_support.h" -#if defined(_WIN32) && !defined(__MINGW32CE__) -#undef open -#undef lseek -#undef stat -#undef fstat -#include <fcntl.h> -#include <io.h> -#include <windows.h> -#include <share.h> - -int ff_win32_open(const char *filename_utf8, int oflag, int pmode) -{ - int fd; - int num_chars; - wchar_t *filename_w; - - /* convert UTF-8 to wide chars */ - num_chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0); - if (num_chars <= 0) - goto fallback; - filename_w = av_mallocz(sizeof(wchar_t) * num_chars); - if (!filename_w) - return -1; - MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars); - - fd = _wsopen(filename_w, oflag, SH_DENYNO, pmode); - av_freep(&filename_w); - - if (fd != -1 || (oflag & O_CREAT)) - return fd; - -fallback: - /* filename maybe be in CP_ACP */ - return _sopen(filename_utf8, oflag, SH_DENYNO, pmode); -} -#endif - #if CONFIG_NETWORK #include <fcntl.h> #if !HAVE_POLL_H #if HAVE_SYS_TIME_H #include <sys/time.h> -#endif +#endif /* HAVE_SYS_TIME_H */ #if HAVE_WINSOCK2_H #include <winsock2.h> #elif HAVE_SYS_SELECT_H #include <sys/select.h> -#endif -#endif +#endif /* HAVE_WINSOCK2_H */ +#endif /* !HAVE_POLL_H */ #include "network.h" @@ -119,7 +82,7 @@ int ff_getaddrinfo(const char *node, const char *service, win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo"); if (win_getaddrinfo) return win_getaddrinfo(node, service, hints, res); -#endif +#endif /* HAVE_WINSOCK2_H */ *res = NULL; sin = av_mallocz(sizeof(struct sockaddr_in)); @@ -193,7 +156,7 @@ void ff_freeaddrinfo(struct addrinfo *res) win_freeaddrinfo(res); return; } -#endif +#endif /* HAVE_WINSOCK2_H */ av_free(res->ai_canonname); av_free(res->ai_addr); @@ -214,7 +177,7 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen, win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo"); if (win_getnameinfo) return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); -#endif +#endif /* HAVE_WINSOCK2_H */ if (sa->sa_family != AF_INET) return EAI_FAMILY; @@ -245,7 +208,7 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen, #if HAVE_GETSERVBYPORT if (!(flags & NI_NUMERICSERV)) ent = getservbyport(sin->sin_port, flags & NI_DGRAM ? "udp" : "tcp"); -#endif +#endif /* HAVE_GETSERVBYPORT */ if (ent) snprintf(serv, servlen, "%s", ent->s_name); @@ -275,7 +238,7 @@ const char *ff_gai_strerror(int ecode) #if EAI_NODATA != EAI_NONAME case EAI_NODATA: return "No address associated with hostname"; -#endif +#endif /* EAI_NODATA != EAI_NONAME */ case EAI_NONAME: return "The name does not resolve for the supplied parameters"; case EAI_SERVICE: @@ -298,7 +261,7 @@ int ff_socket_nonblock(int socket, int enable) return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); else return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); -#endif +#endif /* HAVE_WINSOCK2_H */ } #if !HAVE_POLL_H @@ -316,7 +279,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout) errno = EINVAL; return -1; } -#endif +#endif /* HAVE_WINSOCK2_H */ FD_ZERO(&read_set); FD_ZERO(&write_set); @@ -331,7 +294,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout) errno = EINVAL; return -1; } -#endif +#endif /* !HAVE_WINSOCK2_H */ if (fds[i].events & POLLIN) FD_SET(fds[i].fd, &read_set); @@ -373,5 +336,6 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout) return rc; } -#endif /* HAVE_POLL_H */ +#endif /* !HAVE_POLL_H */ + #endif /* CONFIG_NETWORK */ diff --git a/ffmpeg/libavformat/os_support.h b/ffmpeg/libavformat/os_support.h index e5f31e0..7c7cd1f 100644 --- a/ffmpeg/libavformat/os_support.h +++ b/ffmpeg/libavformat/os_support.h @@ -54,8 +54,6 @@ #include <io.h> #endif #define mkdir(a, b) _mkdir(a) -#else -#include <sys/stat.h> #endif static inline int is_dos_path(const char *path) @@ -86,11 +84,6 @@ static inline int is_dos_path(const char *path) #endif #endif -#if defined(_WIN32) && !defined(__MINGW32CE__) -int ff_win32_open(const char *filename, int oflag, int pmode); -#define open ff_win32_open -#endif - #if CONFIG_NETWORK #if !HAVE_SOCKLEN_T typedef int socklen_t; diff --git a/ffmpeg/libavformat/paf.c b/ffmpeg/libavformat/paf.c index 09786eb..09aefe6 100644 --- a/ffmpeg/libavformat/paf.c +++ b/ffmpeg/libavformat/paf.c @@ -233,10 +233,11 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) p->current_frame_block++; } - size = p->video_size - p->frames_offset_table[p->current_frame]; - if (size < 1) + if (p->frames_offset_table[p->current_frame] >= p->video_size) return AVERROR_INVALIDDATA; + size = p->video_size - p->frames_offset_table[p->current_frame]; + if (av_new_packet(pkt, size) < 0) return AVERROR(ENOMEM); diff --git a/ffmpeg/libavformat/pjsdec.c b/ffmpeg/libavformat/pjsdec.c index ef2b626..a69a316 100644 --- a/ffmpeg/libavformat/pjsdec.c +++ b/ffmpeg/libavformat/pjsdec.c @@ -39,7 +39,7 @@ static int pjs_probe(AVProbeData *p) int64_t start, end; const unsigned char *ptr = p->buf; - if (sscanf(ptr, "%"PRId64",%"PRId64",%c", &start, &end, &c) == 3) { + if (sscanf(ptr, "%"SCNd64",%"SCNd64",%c", &start, &end, &c) == 3) { size_t q1pos = strcspn(ptr, "\""); size_t q2pos = q1pos + strcspn(ptr + q1pos + 1, "\"") + 1; if (strcspn(ptr, "\r\n") > q2pos) @@ -52,7 +52,7 @@ static int64_t read_ts(char **line, int *duration) { int64_t start, end; - if (sscanf(*line, "%"PRId64",%"PRId64, &start, &end) == 2) { + if (sscanf(*line, "%"SCNd64",%"SCNd64, &start, &end) == 2) { *line += strcspn(*line, "\"") + 1; *duration = end - start; return start; diff --git a/ffmpeg/libavformat/pmpdec.c b/ffmpeg/libavformat/pmpdec.c index 2fe6c46..71f450e 100644 --- a/ffmpeg/libavformat/pmpdec.c +++ b/ffmpeg/libavformat/pmpdec.c @@ -174,7 +174,7 @@ static int pmp_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags) { PMPContext *pmp = s->priv_data; pmp->cur_stream = 0; - // fallback to default seek now + // fall back on default seek now return -1; } diff --git a/ffmpeg/libavformat/psxstr.c b/ffmpeg/libavformat/psxstr.c index 90c933e..5efcadf 100644 --- a/ffmpeg/libavformat/psxstr.c +++ b/ffmpeg/libavformat/psxstr.c @@ -30,6 +30,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" @@ -126,7 +127,7 @@ static int str_probe(AVProbeData *p) } /* MPEG files (like those ripped from VCDs) can also look like this; * only return half certainty */ - if(vid+aud > 3) return 50; + if(vid+aud > 3) return AVPROBE_SCORE_EXTENSION; else if(vid+aud) return 1; else return 0; } @@ -220,6 +221,7 @@ static int str_read_packet(AVFormatContext *s, av_free_packet(pkt); if (av_new_packet(pkt, sector_count*VIDEO_DATA_CHUNK_SIZE)) return AVERROR(EIO); + memset(pkt->data, 0, sector_count*VIDEO_DATA_CHUNK_SIZE); pkt->pos= avio_tell(pb) - RAW_CD_SECTOR_SIZE; pkt->stream_index = @@ -237,7 +239,9 @@ static int str_read_packet(AVFormatContext *s, pkt->size= -1; pkt->buf = NULL; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS pkt->destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif return 0; } diff --git a/ffmpeg/libavformat/pva.c b/ffmpeg/libavformat/pva.c index ae42c83..18ab1cd 100644 --- a/ffmpeg/libavformat/pva.c +++ b/ffmpeg/libavformat/pva.c @@ -49,7 +49,7 @@ static int pva_probe(AVProbeData * pd) { if (pd->buf_size >= len + 8 && pva_check(buf + len) >= 0) - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; return AVPROBE_SCORE_MAX / 4; } @@ -85,6 +85,7 @@ static int read_part_of_packet(AVFormatContext *s, int64_t *pts, PVAContext *pvactx = s->priv_data; int syncword, streamid, reserved, flags, length, pts_flag; int64_t pva_pts = AV_NOPTS_VALUE, startpos; + int ret; recover: startpos = avio_tell(pb); @@ -133,8 +134,8 @@ recover: pes_flags = avio_rb16(pb); pes_header_data_length = avio_r8(pb); - if (pes_signal != 1) { - pva_log(s, AV_LOG_WARNING, "expected signaled PES packet, " + if (pes_signal != 1 || pes_header_data_length == 0) { + pva_log(s, AV_LOG_WARNING, "expected non empty signaled PES packet, " "trying to recover\n"); avio_skip(pb, length - 9); if (!read_packet) @@ -142,15 +143,23 @@ recover: goto recover; } - avio_read(pb, pes_header_data, pes_header_data_length); + ret = avio_read(pb, pes_header_data, pes_header_data_length); + if (ret != pes_header_data_length) + return ret < 0 ? ret : AVERROR_INVALIDDATA; length -= 9 + pes_header_data_length; pes_packet_length -= 3 + pes_header_data_length; pvactx->continue_pes = pes_packet_length; - if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20) + if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20) { + if (pes_header_data_length < 5) { + pva_log(s, AV_LOG_ERROR, "header too short\n"); + avio_skip(pb, length); + return AVERROR_INVALIDDATA; + } pva_pts = ff_parse_pes_pts(pes_header_data); + } } pvactx->continue_pes -= length; diff --git a/ffmpeg/libavformat/r3d.c b/ffmpeg/libavformat/r3d.c index 3b3ecce..0719fb6 100644 --- a/ffmpeg/libavformat/r3d.c +++ b/ffmpeg/libavformat/r3d.c @@ -19,8 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -//#define DEBUG - #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "libavutil/mathematics.h" @@ -87,7 +85,7 @@ static int r3d_read_red1(AVFormatContext *s) framerate.num = avio_rb16(s->pb); framerate.den = avio_rb16(s->pb); - if (framerate.num && framerate.den) { + if (framerate.num > 0 && framerate.den > 0) { #if FF_API_R_FRAME_RATE st->r_frame_rate = #endif @@ -285,8 +283,8 @@ static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom) dts = avio_rb32(s->pb); st->codec->sample_rate = avio_rb32(s->pb); - if (st->codec->sample_rate < 0) { - av_log(s, AV_LOG_ERROR, "negative sample rate\n"); + if (st->codec->sample_rate <= 0) { + av_log(s, AV_LOG_ERROR, "Bad sample rate\n"); return AVERROR_INVALIDDATA; } diff --git a/ffmpeg/libavformat/rawdec.c b/ffmpeg/libavformat/rawdec.c index 07c2782..a9ff22a 100644 --- a/ffmpeg/libavformat/rawdec.c +++ b/ffmpeg/libavformat/rawdec.c @@ -70,7 +70,6 @@ int ff_raw_video_read_header(AVFormatContext *s) { AVStream *st; FFRawVideoDemuxerContext *s1 = s->priv_data; - AVRational framerate; int ret = 0; @@ -84,27 +83,43 @@ int ff_raw_video_read_header(AVFormatContext *s) st->codec->codec_id = s->iformat->raw_codec_id; st->need_parsing = AVSTREAM_PARSE_FULL_RAW; - if ((ret = av_parse_video_rate(&framerate, s1->framerate)) < 0) { - av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s1->framerate); - goto fail; - } - - st->codec->time_base = av_inv_q(framerate); + st->codec->time_base = av_inv_q(s1->framerate); avpriv_set_pts_info(st, 64, 1, 1200000); fail: return ret; } +static int ff_raw_data_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = AVMEDIA_TYPE_DATA; + st->codec->codec_id = s->iformat->raw_codec_id; + st->start_time = 0; + return 0; +} + /* Note: Do not forget to add new entries to the Makefile as well. */ #define OFFSET(x) offsetof(FFRawVideoDemuxerContext, x) #define DEC AV_OPT_FLAG_DECODING_PARAM const AVOption ff_rawvideo_options[] = { - { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC}, + { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC}, { NULL }, }; +#if CONFIG_DATA_DEMUXER +AVInputFormat ff_data_demuxer = { + .name = "data", + .long_name = NULL_IF_CONFIG_SMALL("raw data"), + .read_header = ff_raw_data_read_header, + .read_packet = ff_raw_read_partial_packet, + .raw_codec_id = AV_CODEC_ID_NONE, +}; +#endif + #if CONFIG_LATM_DEMUXER AVInputFormat ff_latm_demuxer = { .name = "latm", diff --git a/ffmpeg/libavformat/rawdec.h b/ffmpeg/libavformat/rawdec.h index d978295..5910855 100644 --- a/ffmpeg/libavformat/rawdec.h +++ b/ffmpeg/libavformat/rawdec.h @@ -30,7 +30,7 @@ typedef struct FFRawVideoDemuxerContext { const AVClass *class; /**< Class for private options. */ char *video_size; /**< String describing video size, set by a private option. */ char *pixel_format; /**< Set by a private option. */ - char *framerate; /**< String describing framerate, set by a private option. */ + AVRational framerate; /**< AVRational describing framerate, set by a private option. */ } FFRawVideoDemuxerContext; extern const AVOption ff_rawvideo_options[]; diff --git a/ffmpeg/libavformat/rawenc.c b/ffmpeg/libavformat/rawenc.c index b804c24..5044698 100644 --- a/ffmpeg/libavformat/rawenc.c +++ b/ffmpeg/libavformat/rawenc.c @@ -26,7 +26,16 @@ int ff_raw_write_packet(AVFormatContext *s, AVPacket *pkt) { avio_write(s->pb, pkt->data, pkt->size); - avio_flush(s->pb); + return 0; +} + +static int force_one_stream(AVFormatContext *s) +{ + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "%s files have exactly one stream\n", + s->oformat->name); + return AVERROR(EINVAL); + } return 0; } @@ -40,6 +49,7 @@ AVOutputFormat ff_ac3_muxer = { .extensions = "ac3", .audio_codec = AV_CODEC_ID_AC3, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -52,6 +62,7 @@ AVOutputFormat ff_adx_muxer = { .extensions = "adx", .audio_codec = AV_CODEC_ID_ADPCM_ADX, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -64,6 +75,17 @@ AVOutputFormat ff_cavsvideo_muxer = { .extensions = "cavs", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_CAVS, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + +#if CONFIG_DATA_MUXER +AVOutputFormat ff_data_muxer = { + .name = "data", + .long_name = NULL_IF_CONFIG_SMALL("raw data"), + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -76,6 +98,7 @@ AVOutputFormat ff_dirac_muxer = { .extensions = "drc", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_DIRAC, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -88,6 +111,7 @@ AVOutputFormat ff_dnxhd_muxer = { .extensions = "dnxhd", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_DNXHD, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -101,6 +125,7 @@ AVOutputFormat ff_dts_muxer = { .extensions = "dts", .audio_codec = AV_CODEC_ID_DTS, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -114,6 +139,7 @@ AVOutputFormat ff_eac3_muxer = { .extensions = "eac3", .audio_codec = AV_CODEC_ID_EAC3, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -127,6 +153,7 @@ AVOutputFormat ff_g722_muxer = { .extensions = "g722", .audio_codec = AV_CODEC_ID_ADPCM_G722, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -140,6 +167,7 @@ AVOutputFormat ff_g723_1_muxer = { .extensions = "tco,rco", .audio_codec = AV_CODEC_ID_G723_1, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -153,6 +181,7 @@ AVOutputFormat ff_h261_muxer = { .extensions = "h261", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_H261, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -166,6 +195,7 @@ AVOutputFormat ff_h263_muxer = { .extensions = "h263", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_H263, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -178,6 +208,7 @@ AVOutputFormat ff_h264_muxer = { .extensions = "h264", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_H264, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -203,6 +234,7 @@ AVOutputFormat ff_mjpeg_muxer = { .extensions = "mjpg,mjpeg", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_MJPEG, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -215,6 +247,7 @@ AVOutputFormat ff_mlp_muxer = { .extensions = "mlp", .audio_codec = AV_CODEC_ID_MLP, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -228,6 +261,7 @@ AVOutputFormat ff_mpeg1video_muxer = { .extensions = "mpg,mpeg,m1v", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_MPEG1VIDEO, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -240,6 +274,7 @@ AVOutputFormat ff_mpeg2video_muxer = { .extensions = "m2v", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_MPEG2VIDEO, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -264,6 +299,7 @@ AVOutputFormat ff_truehd_muxer = { .extensions = "thd", .audio_codec = AV_CODEC_ID_TRUEHD, .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; @@ -276,6 +312,7 @@ AVOutputFormat ff_vc1_muxer = { .extensions = "vc1", .audio_codec = AV_CODEC_ID_NONE, .video_codec = AV_CODEC_ID_VC1, + .write_header = force_one_stream, .write_packet = ff_raw_write_packet, .flags = AVFMT_NOTIMESTAMPS, }; diff --git a/ffmpeg/libavformat/rawvideodec.c b/ffmpeg/libavformat/rawvideodec.c index 8460781..cbcae43 100644 --- a/ffmpeg/libavformat/rawvideodec.c +++ b/ffmpeg/libavformat/rawvideodec.c @@ -27,18 +27,16 @@ typedef struct RawVideoDemuxerContext { const AVClass *class; /**< Class for private options. */ - char *video_size; /**< String describing video size, set by a private option. */ + int width, height; /**< Integers describing video size, set by a private option. */ char *pixel_format; /**< Set by a private option. */ - char *framerate; /**< String describing framerate, set by a private option. */ + AVRational framerate; /**< AVRational describing framerate, set by a private option. */ } RawVideoDemuxerContext; static int rawvideo_read_header(AVFormatContext *ctx) { RawVideoDemuxerContext *s = ctx->priv_data; - int width = 0, height = 0, ret = 0; enum AVPixelFormat pix_fmt; - AVRational framerate; AVStream *st; st = avformat_new_stream(ctx, NULL); @@ -49,30 +47,18 @@ static int rawvideo_read_header(AVFormatContext *ctx) st->codec->codec_id = ctx->iformat->raw_codec_id; - if (s->video_size && - (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) { - av_log(ctx, AV_LOG_ERROR, "Couldn't parse video size.\n"); - return ret; - } - if ((pix_fmt = av_get_pix_fmt(s->pixel_format)) == AV_PIX_FMT_NONE) { av_log(ctx, AV_LOG_ERROR, "No such pixel format: %s.\n", s->pixel_format); return AVERROR(EINVAL); } - if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) { - av_log(ctx, AV_LOG_ERROR, "Could not parse framerate: %s.\n", - s->framerate); - return ret; - } - - avpriv_set_pts_info(st, 64, framerate.den, framerate.num); + avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num); - st->codec->width = width; - st->codec->height = height; + st->codec->width = s->width; + st->codec->height = s->height; st->codec->pix_fmt = pix_fmt; - st->codec->bit_rate = av_rescale_q(avpicture_get_size(st->codec->pix_fmt, width, height), + st->codec->bit_rate = av_rescale_q(avpicture_get_size(st->codec->pix_fmt, s->width, s->height), (AVRational){8,1}, st->time_base); return 0; @@ -103,9 +89,9 @@ static int rawvideo_read_packet(AVFormatContext *s, AVPacket *pkt) #define OFFSET(x) offsetof(RawVideoDemuxerContext, x) #define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption rawvideo_options[] = { - { "video_size", "set frame size", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, { "pixel_format", "set pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = "yuv420p"}, 0, 0, DEC }, - { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC }, + { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC }, { NULL }, }; diff --git a/ffmpeg/libavformat/rdt.c b/ffmpeg/libavformat/rdt.c index 695323a..201a3e0 100644 --- a/ffmpeg/libavformat/rdt.c +++ b/ffmpeg/libavformat/rdt.c @@ -98,7 +98,7 @@ ff_rdt_calc_response_and_checksum(char response[41], char chksum[9], unsigned char zres[16], buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 }; #define XOR_TABLE_SIZE 37 - const unsigned char xor_table[XOR_TABLE_SIZE] = { + static const unsigned char xor_table[XOR_TABLE_SIZE] = { 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53, 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70, 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09, @@ -419,15 +419,16 @@ rdt_parse_sdp_line (AVFormatContext *s, int st_index, for (n = 0; n < s->nb_streams; n++) if (s->streams[n]->id == stream->id) { - int count = s->streams[n]->index + 1; + int count = s->streams[n]->index + 1, err; if (first == -1) first = n; if (rdt->nb_rmst < count) { - RMStream **rmst= av_realloc(rdt->rmst, count*sizeof(*rmst)); - if (!rmst) - return AVERROR(ENOMEM); - memset(rmst + rdt->nb_rmst, 0, - (count - rdt->nb_rmst) * sizeof(*rmst)); - rdt->rmst = rmst; + if ((err = av_reallocp(&rdt->rmst, + count * sizeof(*rdt->rmst))) < 0) { + rdt->nb_rmst = 0; + return err; + } + memset(rdt->rmst + rdt->nb_rmst, 0, + (count - rdt->nb_rmst) * sizeof(*rdt->rmst)); rdt->nb_rmst = count; } rdt->rmst[s->streams[n]->index] = ff_rm_alloc_rmstream(); @@ -548,7 +549,7 @@ rdt_free_context (PayloadContext *rdt) } #define RDT_HANDLER(n, s, t) \ -static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \ +static RTPDynamicProtocolHandler rdt_ ## n ## _handler = { \ .enc_name = s, \ .codec_type = t, \ .codec_id = AV_CODEC_ID_NONE, \ @@ -563,10 +564,10 @@ RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO); RDT_HANDLER(video, "x-pn-realvideo", AVMEDIA_TYPE_VIDEO); RDT_HANDLER(audio, "x-pn-realaudio", AVMEDIA_TYPE_AUDIO); -void av_register_rdt_dynamic_payload_handlers(void) +void ff_register_rdt_dynamic_payload_handlers(void) { - ff_register_dynamic_payload_handler(&ff_rdt_video_handler); - ff_register_dynamic_payload_handler(&ff_rdt_audio_handler); - ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler); - ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler); + ff_register_dynamic_payload_handler(&rdt_video_handler); + ff_register_dynamic_payload_handler(&rdt_audio_handler); + ff_register_dynamic_payload_handler(&rdt_live_video_handler); + ff_register_dynamic_payload_handler(&rdt_live_audio_handler); } diff --git a/ffmpeg/libavformat/rdt.h b/ffmpeg/libavformat/rdt.h index c2ec94b..ce6026f 100644 --- a/ffmpeg/libavformat/rdt.h +++ b/ffmpeg/libavformat/rdt.h @@ -62,7 +62,7 @@ void ff_rdt_calc_response_and_checksum(char response[41], char chksum[9], /** * Register RDT-related dynamic payload handlers with our cache. */ -void av_register_rdt_dynamic_payload_handlers(void); +void ff_register_rdt_dynamic_payload_handlers(void); /** * Add subscription information to Subscribe parameter string. diff --git a/ffmpeg/libavformat/realtextdec.c b/ffmpeg/libavformat/realtextdec.c index 67bc339..5e4981a 100644 --- a/ffmpeg/libavformat/realtextdec.c +++ b/ffmpeg/libavformat/realtextdec.c @@ -41,7 +41,7 @@ static int realtext_probe(AVProbeData *p) if (AV_RB24(ptr) == 0xEFBBBF) ptr += 3; /* skip UTF-8 BOM */ - return !av_strncasecmp(ptr, "<window", 7) ? AVPROBE_SCORE_MAX/2 : 0; + return !av_strncasecmp(ptr, "<window", 7) ? AVPROBE_SCORE_EXTENSION : 0; } static int read_ts(const char *s) diff --git a/ffmpeg/libavformat/riff.c b/ffmpeg/libavformat/riff.c index ac1a4ff..52640d1 100644 --- a/ffmpeg/libavformat/riff.c +++ b/ffmpeg/libavformat/riff.c @@ -19,19 +19,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/mathematics.h" +#include "libavutil/error.h" #include "libavcodec/avcodec.h" #include "avformat.h" -#include "avio_internal.h" #include "riff.h" -#include "libavcodec/bytestream.h" -#include "libavutil/avassert.h" -/* Note: when encoding, the first matching tag is used, so order is - important if multiple tags possible for a given codec. - Note also that this list is used for more than just riff, other - files use it as well. -*/ +/* Note: When encoding, the first matching tag is used, so order is + * important if multiple tags are possible for a given codec. + * Note also that this list is used for more than just riff, other + * files use it as well. + */ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_H264, MKTAG('H', '2', '6', '4') }, { AV_CODEC_ID_H264, MKTAG('h', '2', '6', '4') }, @@ -43,6 +40,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') }, { AV_CODEC_ID_H264, MKTAG('Q', '2', '6', '4') }, /* QNAP surveillance system */ { AV_CODEC_ID_H264, MKTAG('V', '2', '6', '4') }, + { AV_CODEC_ID_H264, MKTAG('G', 'A', 'V', 'C') }, /* GeoVision camera */ + { AV_CODEC_ID_H264, MKTAG('U', 'M', 'S', 'V') }, { AV_CODEC_ID_H263, MKTAG('H', '2', '6', '3') }, { AV_CODEC_ID_H263, MKTAG('X', '2', '6', '3') }, { AV_CODEC_ID_H263, MKTAG('T', '2', '6', '3') }, @@ -52,7 +51,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_H263, MKTAG('M', '2', '6', '3') }, { AV_CODEC_ID_H263, MKTAG('l', 's', 'v', 'm') }, { AV_CODEC_ID_H263P, MKTAG('H', '2', '6', '3') }, - { AV_CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */ + { AV_CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* Intel H.263 */ { AV_CODEC_ID_H261, MKTAG('H', '2', '6', '1') }, { AV_CODEC_ID_H263, MKTAG('U', '2', '6', '3') }, { AV_CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') }, @@ -61,8 +60,10 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, { AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') }, - { AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 0 ) }, /* some broken avi use this */ - { AV_CODEC_ID_MPEG4, MKTAG('Z', 'M', 'P', '4') }, /* some broken avi use this */ + /* some broken AVIs use this */ + { AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 0 ) }, + /* some broken AVIs use this */ + { AV_CODEC_ID_MPEG4, MKTAG('Z', 'M', 'P', '4') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') }, { AV_CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') }, { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, @@ -71,7 +72,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MPEG4, MKTAG('S', 'E', 'D', 'G') }, { AV_CODEC_ID_MPEG4, MKTAG('R', 'M', 'P', '4') }, { AV_CODEC_ID_MPEG4, MKTAG('3', 'I', 'V', '2') }, - { AV_CODEC_ID_MPEG4, MKTAG('W', 'A', 'W', 'V') }, /* WaWv MPEG-4 Video Codec */ + /* WaWv MPEG-4 Video Codec */ + { AV_CODEC_ID_MPEG4, MKTAG('W', 'A', 'W', 'V') }, { AV_CODEC_ID_MPEG4, MKTAG('F', 'F', 'D', 'S') }, { AV_CODEC_ID_MPEG4, MKTAG('F', 'V', 'F', 'W') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'C', 'O', 'D') }, @@ -82,18 +84,26 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MPEG4, MKTAG('V', 'I', 'D', 'M') }, { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'T', '3') }, { AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'X') }, - { AV_CODEC_ID_MPEG4, MKTAG('H', 'D', 'X', '4') }, /* flipped video */ + /* flipped video */ + { AV_CODEC_ID_MPEG4, MKTAG('G', '2', '6', '4') }, + /* flipped video */ + { AV_CODEC_ID_MPEG4, MKTAG('H', 'D', 'X', '4') }, + { AV_CODEC_ID_MPEG4, MKTAG('D', 'M', '4', 'V') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'M', 'K', '2') }, + { AV_CODEC_ID_MPEG4, MKTAG('D', 'Y', 'M', '4') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'G', 'I') }, { AV_CODEC_ID_MPEG4, MKTAG('I', 'N', 'M', 'C') }, - { AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') }, /* Ephv MPEG-4 */ + /* Ephv MPEG-4 */ + { AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') }, { AV_CODEC_ID_MPEG4, MKTAG('E', 'M', '4', 'A') }, - { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'C', 'C') }, /* Divio MPEG-4 */ + /* Divio MPEG-4 */ + { AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'C', 'C') }, { AV_CODEC_ID_MPEG4, MKTAG('S', 'N', '4', '0') }, { AV_CODEC_ID_MPEG4, MKTAG('V', 'S', 'P', 'X') }, { AV_CODEC_ID_MPEG4, MKTAG('U', 'L', 'D', 'X') }, { AV_CODEC_ID_MPEG4, MKTAG('G', 'E', 'O', 'V') }, - { AV_CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') }, /* Samsung SHR-6040 */ + /* Samsung SHR-6040 */ + { AV_CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') }, { AV_CODEC_ID_MPEG4, MKTAG('S', 'M', '4', 'V') }, { AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'X') }, { AV_CODEC_ID_MPEG4, MKTAG('D', 'r', 'e', 'X') }, @@ -122,9 +132,12 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') }, { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') }, { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', '0') }, - { AV_CODEC_ID_DVVIDEO, MKTAG('c', 'd', 'v', 'c') }, /* Canopus DV */ - { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', 'H') }, /* Canopus DV */ - { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', '5') }, /* Canopus DV */ + /* Canopus DV */ + { AV_CODEC_ID_DVVIDEO, MKTAG('c', 'd', 'v', 'c') }, + /* Canopus DV */ + { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', 'H') }, + /* Canopus DV */ + { AV_CODEC_ID_DVVIDEO, MKTAG('C', 'D', 'V', '5') }, { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', ' ') }, { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'c', 's') }, { AV_CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', '1') }, @@ -144,10 +157,12 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MPEG4, MKTAG( 4 , 0 , 0 , 16) }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') }, - { AV_CODEC_ID_MPEG2VIDEO, MKTAG('L', 'M', 'P', '2') }, /* Lead MPEG2 in avi */ + /* Lead MPEG-2 in AVI */ + { AV_CODEC_ID_MPEG2VIDEO, MKTAG('L', 'M', 'P', '2') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('s', 'l', 'i', 'f') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('E', 'M', '2', 'V') }, - { AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', '7', '0', '1') }, /* Matrox MPEG2 intra-only */ + /* Matrox MPEG-2 intra-only */ + { AV_CODEC_ID_MPEG2VIDEO, MKTAG('M', '7', '0', '1') }, { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', 'v') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('B', 'W', '1', '0') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('X', 'M', 'P', 'G') }, /* Xing MPEG intra only */ @@ -156,23 +171,31 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MJPEG, MKTAG('d', 'm', 'b', '1') }, { AV_CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, { AV_CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') }, - { AV_CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */ - { AV_CODEC_ID_JPEGLS, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */ + /* Pegasus lossless JPEG */ + { AV_CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, + /* JPEG-LS custom FOURCC for AVI - encoder */ + { AV_CODEC_ID_JPEGLS, MKTAG('M', 'J', 'L', 'S') }, { AV_CODEC_ID_JPEGLS, MKTAG('M', 'J', 'P', 'G') }, - { AV_CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - decoder */ + /* JPEG-LS custom FOURCC for AVI - decoder */ + { AV_CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, { AV_CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, { AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') }, { AV_CODEC_ID_AVRN, MKTAG('A', 'V', 'R', 'n') }, { AV_CODEC_ID_MJPEG, MKTAG('A', 'C', 'D', 'V') }, { AV_CODEC_ID_MJPEG, MKTAG('Q', 'I', 'V', 'G') }, - { AV_CODEC_ID_MJPEG, MKTAG('S', 'L', 'M', 'J') }, /* SL M-JPEG */ - { AV_CODEC_ID_MJPEG, MKTAG('C', 'J', 'P', 'G') }, /* Creative Webcam JPEG */ - { AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'L', 'V') }, /* Intel JPEG Library Video Codec */ - { AV_CODEC_ID_MJPEG, MKTAG('M', 'V', 'J', 'P') }, /* Midvid JPEG Video Codec */ + /* SL M-JPEG */ + { AV_CODEC_ID_MJPEG, MKTAG('S', 'L', 'M', 'J') }, + /* Creative Webcam JPEG */ + { AV_CODEC_ID_MJPEG, MKTAG('C', 'J', 'P', 'G') }, + /* Intel JPEG Library Video Codec */ + { AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'L', 'V') }, + /* Midvid JPEG Video Codec */ + { AV_CODEC_ID_MJPEG, MKTAG('M', 'V', 'J', 'P') }, { AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'I', '1') }, { AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'I', '2') }, { AV_CODEC_ID_MJPEG, MKTAG('M', 'T', 'S', 'J') }, - { AV_CODEC_ID_MJPEG, MKTAG('Z', 'J', 'P', 'G') }, /* Paradigm Matrix M-JPEG Codec */ + /* Paradigm Matrix M-JPEG Codec */ + { AV_CODEC_ID_MJPEG, MKTAG('Z', 'J', 'P', 'G') }, { AV_CODEC_ID_MJPEG, MKTAG('M', 'M', 'J', 'P') }, { AV_CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') }, { AV_CODEC_ID_FFVHUFF, MKTAG('F', 'F', 'V', 'H') }, @@ -202,7 +225,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '8', ' ', ' ') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('H', 'D', 'Y', 'C') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', 'U', '9') }, - { AV_CODEC_ID_RAWVIDEO, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */ + /* SoftLab-NSK VideoTizer */ + { AV_CODEC_ID_RAWVIDEO, MKTAG('V', 'D', 'T', 'Z') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', '1', '1') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('N', 'V', '1', '2') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('N', 'V', '2', '1') }, @@ -231,9 +255,11 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') }, { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') }, { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') }, + { AV_CODEC_ID_VP6A, MKTAG('V', 'P', '6', 'A') }, { AV_CODEC_ID_VP6F, MKTAG('V', 'P', '6', 'F') }, { AV_CODEC_ID_VP6F, MKTAG('F', 'L', 'V', '4') }, { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, + { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, { AV_CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') }, { AV_CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') }, { AV_CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') }, @@ -304,21 +330,20 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_DPX, MKTAG('d', 'p', 'x', ' ') }, { AV_CODEC_ID_KGV1, MKTAG('K', 'G', 'V', '1') }, { AV_CODEC_ID_LAGARITH, MKTAG('L', 'A', 'G', 'S') }, - { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') }, - { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') }, - { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') }, { AV_CODEC_ID_AMV, MKTAG('A', 'M', 'V', 'F') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'A') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'G') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '0') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') }, + /* Ut Video version 13.0.1 BT.709 codecs */ + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '0') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '2') }, { AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, { AV_CODEC_ID_ZEROCODEC, MKTAG('Z', 'E', 'C', 'O') }, { AV_CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') }, { AV_CODEC_ID_FLIC, MKTAG('A', 'F', 'L', 'C') }, - { AV_CODEC_ID_EXR, MKTAG('e', 'x', 'r', ' ') }, { AV_CODEC_ID_MSS1, MKTAG('M', 'S', 'S', '1') }, { AV_CODEC_ID_MSA1, MKTAG('M', 'S', 'A', '1') }, { AV_CODEC_ID_TSCC2, MKTAG('T', 'S', 'C', '2') }, @@ -328,27 +353,34 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') }, { AV_CODEC_ID_012V, MKTAG('0', '1', '2', 'v') }, { AV_CODEC_ID_012V, MKTAG('a', '1', '2', 'v') }, + { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') }, + { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') }, + { AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') }, { AV_CODEC_ID_NONE, 0 } }; const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_PCM_S16LE, 0x0001 }, - { AV_CODEC_ID_PCM_U8, 0x0001 }, /* must come after s16le in this list */ + /* must come after s16le in this list */ + { AV_CODEC_ID_PCM_U8, 0x0001 }, { AV_CODEC_ID_PCM_S24LE, 0x0001 }, { AV_CODEC_ID_PCM_S32LE, 0x0001 }, { AV_CODEC_ID_ADPCM_MS, 0x0002 }, { AV_CODEC_ID_PCM_F32LE, 0x0003 }, - { AV_CODEC_ID_PCM_F64LE, 0x0003 }, /* must come after f32le in this list */ + /* must come after f32le in this list */ + { AV_CODEC_ID_PCM_F64LE, 0x0003 }, { AV_CODEC_ID_PCM_ALAW, 0x0006 }, { AV_CODEC_ID_PCM_MULAW, 0x0007 }, { AV_CODEC_ID_WMAVOICE, 0x000A }, { AV_CODEC_ID_ADPCM_IMA_OKI, 0x0010 }, { AV_CODEC_ID_ADPCM_IMA_WAV, 0x0011 }, - { AV_CODEC_ID_PCM_ZORK, 0x0011 }, /* must come after adpcm_ima_wav in this list */ + /* must come after adpcm_ima_wav in this list */ + { AV_CODEC_ID_PCM_ZORK, 0x0011 }, { AV_CODEC_ID_ADPCM_IMA_OKI, 0x0017 }, { AV_CODEC_ID_ADPCM_YAMAHA, 0x0020 }, { AV_CODEC_ID_TRUESPEECH, 0x0022 }, { AV_CODEC_ID_GSM_MS, 0x0031 }, + { AV_CODEC_ID_GSM_MS, 0x0032 }, /* msn audio */ { AV_CODEC_ID_AMR_NB, 0x0038 }, /* rogue format number */ { AV_CODEC_ID_G723_1, 0x0042 }, { AV_CODEC_ID_ADPCM_G726, 0x0045 }, @@ -356,11 +388,15 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_MP3, 0x0055 }, { AV_CODEC_ID_AMR_NB, 0x0057 }, { AV_CODEC_ID_AMR_WB, 0x0058 }, - { AV_CODEC_ID_ADPCM_IMA_DK4, 0x0061 }, /* rogue format number */ - { AV_CODEC_ID_ADPCM_IMA_DK3, 0x0062 }, /* rogue format number */ + /* rogue format number */ + { AV_CODEC_ID_ADPCM_IMA_DK4, 0x0061 }, + /* rogue format number */ + { AV_CODEC_ID_ADPCM_IMA_DK3, 0x0062 }, + { AV_CODEC_ID_ADPCM_G726, 0x0064 }, { AV_CODEC_ID_ADPCM_IMA_WAV, 0x0069 }, - { AV_CODEC_ID_VOXWARE, 0x0075 }, + { AV_CODEC_ID_METASOUND, 0x0075 }, { AV_CODEC_ID_AAC, 0x00ff }, + { AV_CODEC_ID_G723_1, 0x0111 }, { AV_CODEC_ID_SIPR, 0x0130 }, { AV_CODEC_ID_WMAV1, 0x0160 }, { AV_CODEC_ID_WMAV2, 0x0161 }, @@ -373,7 +409,8 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_IAC, 0x0402 }, { AV_CODEC_ID_GSM_MS, 0x1500 }, { AV_CODEC_ID_TRUESPEECH, 0x1501 }, - { AV_CODEC_ID_AAC, 0x1600 }, /* ADTS AAC */ + /* ADTS AAC */ + { AV_CODEC_ID_AAC, 0x1600 }, { AV_CODEC_ID_AAC_LATM, 0x1602 }, { AV_CODEC_ID_AC3, 0x2000 }, { AV_CODEC_ID_DTS, 0x2001 }, @@ -382,486 +419,40 @@ const AVCodecTag ff_codec_wav_tags[] = { { AV_CODEC_ID_PCM_MULAW, 0x6c75 }, { AV_CODEC_ID_AAC, 0x706d }, { AV_CODEC_ID_AAC, 0x4143 }, + { AV_CODEC_ID_XAN_DPCM, 0x594a }, { AV_CODEC_ID_G723_1, 0xA100 }, { AV_CODEC_ID_AAC, 0xA106 }, { AV_CODEC_ID_SPEEX, 0xA109 }, { AV_CODEC_ID_FLAC, 0xF1AC }, - { AV_CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' }, - { AV_CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id? + { AV_CODEC_ID_ADPCM_SWF, ('S' << 8) + 'F' }, + /* HACK/FIXME: Does Vorbis in WAV/AVI have an (in)official ID? */ + { AV_CODEC_ID_VORBIS, ('V' << 8) + 'o' }, { AV_CODEC_ID_NONE, 0 }, }; -const AVCodecGuid ff_codec_wav_guids[] = { - {AV_CODEC_ID_AC3, {0x2C,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, - {AV_CODEC_ID_ATRAC3P, {0xBF,0xAA,0x23,0xE9,0x58,0xCB,0x71,0x44,0xA1,0x19,0xFF,0xFA,0x01,0xE4,0xCE,0x62}}, - {AV_CODEC_ID_EAC3, {0xAF,0x87,0xFB,0xA7,0x02,0x2D,0xFB,0x42,0xA4,0xD4,0x05,0xCD,0x93,0x84,0x3B,0xDD}}, - {AV_CODEC_ID_MP2, {0x2B,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, - {AV_CODEC_ID_NONE} -}; - const AVMetadataConv ff_riff_info_conv[] = { - { "IART", "artist" }, - { "ICMT", "comment" }, - { "ICOP", "copyright" }, - { "ICRD", "date" }, - { "IGNR", "genre" }, - { "ILNG", "language" }, - { "INAM", "title" }, - { "IPRD", "album" }, - { "IPRT", "track" }, - { "ISFT", "encoder" }, - { "ISMP", "timecode" }, - { "ITCH", "encoded_by"}, + { "IART", "artist" }, + { "ICMT", "comment" }, + { "ICOP", "copyright" }, + { "ICRD", "date" }, + { "IGNR", "genre" }, + { "ILNG", "language" }, + { "INAM", "title" }, + { "IPRD", "album" }, + { "IPRT", "track" }, + { "ITRK", "track" }, + { "ISFT", "encoder" }, + { "ISMP", "timecode" }, + { "ITCH", "encoded_by" }, { 0 }, }; -#if CONFIG_MUXERS -int64_t ff_start_tag(AVIOContext *pb, const char *tag) -{ - ffio_wfourcc(pb, tag); - avio_wl32(pb, 0); - return avio_tell(pb); -} - -void ff_end_tag(AVIOContext *pb, int64_t start) -{ - int64_t pos; - - av_assert0((start&1) == 0); - - pos = avio_tell(pb); - if (pos & 1) - avio_w8(pb, 0); - avio_seek(pb, start - 4, SEEK_SET); - avio_wl32(pb, (uint32_t)(pos - start)); - avio_seek(pb, FFALIGN(pos, 2), SEEK_SET); -} - -/* WAVEFORMATEX header */ -/* returns the size or -1 on error */ -int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) -{ - int bps, blkalign, bytespersec, frame_size; - int hdrsize = 18; - int waveformatextensible; - uint8_t temp[256]; - uint8_t *riff_extradata= temp; - uint8_t *riff_extradata_start= temp; - - if(!enc->codec_tag || enc->codec_tag > 0xffff) - return -1; - - /* We use the known constant frame size for the codec if known, otherwise - fallback to using AVCodecContext.frame_size, which is not as reliable - for indicating packet duration */ - frame_size = av_get_audio_frame_duration(enc, 0); - if (!frame_size) - frame_size = enc->frame_size; - - waveformatextensible = (enc->channels > 2 && enc->channel_layout) - || enc->sample_rate > 48000 - || av_get_bits_per_sample(enc->codec_id) > 16; - - if (waveformatextensible) { - avio_wl16(pb, 0xfffe); - } else { - avio_wl16(pb, enc->codec_tag); - } - avio_wl16(pb, enc->channels); - avio_wl32(pb, enc->sample_rate); - if (enc->codec_id == AV_CODEC_ID_ATRAC3 || - enc->codec_id == AV_CODEC_ID_G723_1 || - enc->codec_id == AV_CODEC_ID_GSM_MS || - enc->codec_id == AV_CODEC_ID_MP2 || - enc->codec_id == AV_CODEC_ID_MP3) { - bps = 0; - } else { - if (!(bps = av_get_bits_per_sample(enc->codec_id))) { - if (enc->bits_per_coded_sample) - bps = enc->bits_per_coded_sample; - else - bps = 16; // default to 16 - } - } - if(bps != enc->bits_per_coded_sample && enc->bits_per_coded_sample){ - av_log(enc, AV_LOG_WARNING, "requested bits_per_coded_sample (%d) and actually stored (%d) differ\n", enc->bits_per_coded_sample, bps); - } - - if (enc->codec_id == AV_CODEC_ID_MP2 || enc->codec_id == AV_CODEC_ID_MP3) { - /* this is wrong, but it seems many demuxers do not work if this is set - correctly */ - blkalign = frame_size; - //blkalign = 144 * enc->bit_rate/enc->sample_rate; - } else if (enc->codec_id == AV_CODEC_ID_AC3) { - blkalign = 3840; //maximum bytes per frame - } else if (enc->codec_id == AV_CODEC_ID_AAC) { - blkalign = 768 * enc->channels; //maximum bytes per frame - } else if (enc->codec_id == AV_CODEC_ID_G723_1) { - blkalign = 24; - } else if (enc->block_align != 0) { /* specified by the codec */ - blkalign = enc->block_align; - } else - blkalign = bps * enc->channels / av_gcd(8, bps); - if (enc->codec_id == AV_CODEC_ID_PCM_U8 || - enc->codec_id == AV_CODEC_ID_PCM_S24LE || - enc->codec_id == AV_CODEC_ID_PCM_S32LE || - enc->codec_id == AV_CODEC_ID_PCM_F32LE || - enc->codec_id == AV_CODEC_ID_PCM_F64LE || - enc->codec_id == AV_CODEC_ID_PCM_S16LE) { - bytespersec = enc->sample_rate * blkalign; - } else if (enc->codec_id == AV_CODEC_ID_G723_1) { - bytespersec = 800; - } else { - bytespersec = enc->bit_rate / 8; - } - avio_wl32(pb, bytespersec); /* bytes per second */ - avio_wl16(pb, blkalign); /* block align */ - avio_wl16(pb, bps); /* bits per sample */ - if (enc->codec_id == AV_CODEC_ID_MP3) { - hdrsize += 12; - bytestream_put_le16(&riff_extradata, 1); /* wID */ - bytestream_put_le32(&riff_extradata, 2); /* fdwFlags */ - bytestream_put_le16(&riff_extradata, 1152); /* nBlockSize */ - bytestream_put_le16(&riff_extradata, 1); /* nFramesPerBlock */ - bytestream_put_le16(&riff_extradata, 1393); /* nCodecDelay */ - } else if (enc->codec_id == AV_CODEC_ID_MP2) { - hdrsize += 22; - bytestream_put_le16(&riff_extradata, 2); /* fwHeadLayer */ - bytestream_put_le32(&riff_extradata, enc->bit_rate); /* dwHeadBitrate */ - bytestream_put_le16(&riff_extradata, enc->channels == 2 ? 1 : 8); /* fwHeadMode */ - bytestream_put_le16(&riff_extradata, 0); /* fwHeadModeExt */ - bytestream_put_le16(&riff_extradata, 1); /* wHeadEmphasis */ - bytestream_put_le16(&riff_extradata, 16); /* fwHeadFlags */ - bytestream_put_le32(&riff_extradata, 0); /* dwPTSLow */ - bytestream_put_le32(&riff_extradata, 0); /* dwPTSHigh */ - } else if (enc->codec_id == AV_CODEC_ID_G723_1) { - hdrsize += 20; - bytestream_put_le32(&riff_extradata, 0x9ace0002); /* extradata needed for msacm g723.1 codec */ - bytestream_put_le32(&riff_extradata, 0xaea2f732); - bytestream_put_le16(&riff_extradata, 0xacde); - } else if (enc->codec_id == AV_CODEC_ID_GSM_MS || enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) { - hdrsize += 2; - bytestream_put_le16(&riff_extradata, frame_size); /* wSamplesPerBlock */ - } else if(enc->extradata_size){ - riff_extradata_start= enc->extradata; - riff_extradata= enc->extradata + enc->extradata_size; - hdrsize += enc->extradata_size; - } - if(waveformatextensible) { /* write WAVEFORMATEXTENSIBLE extensions */ - hdrsize += 22; - avio_wl16(pb, riff_extradata - riff_extradata_start + 22); /* 22 is WAVEFORMATEXTENSIBLE size */ - avio_wl16(pb, bps); /* ValidBitsPerSample || SamplesPerBlock || Reserved */ - avio_wl32(pb, enc->channel_layout); /* dwChannelMask */ - avio_wl32(pb, enc->codec_tag); /* GUID + next 3 */ - avio_wl32(pb, 0x00100000); - avio_wl32(pb, 0xAA000080); - avio_wl32(pb, 0x719B3800); - } else { - avio_wl16(pb, riff_extradata - riff_extradata_start); /* cbSize */ - } - avio_write(pb, riff_extradata_start, riff_extradata - riff_extradata_start); - if(hdrsize&1){ - hdrsize++; - avio_w8(pb, 0); - } - - return hdrsize; -} - -/* BITMAPINFOHEADER header */ -void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf) -{ - avio_wl32(pb, 40 + enc->extradata_size); /* size */ - avio_wl32(pb, enc->width); - //We always store RGB TopDown - avio_wl32(pb, enc->codec_tag ? enc->height : -enc->height); - avio_wl16(pb, 1); /* planes */ - - avio_wl16(pb, enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24); /* depth */ - /* compression type */ - avio_wl32(pb, enc->codec_tag); - avio_wl32(pb, (enc->width * enc->height * (enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24)+7) / 8); - avio_wl32(pb, 0); - avio_wl32(pb, 0); - avio_wl32(pb, 0); - avio_wl32(pb, 0); - - avio_write(pb, enc->extradata, enc->extradata_size); - - if (!for_asf && enc->extradata_size & 1) - avio_w8(pb, 0); -} - -void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale) -{ - int gcd; - int audio_frame_size; - - /* We use the known constant frame size for the codec if known, otherwise - fallback to using AVCodecContext.frame_size, which is not as reliable - for indicating packet duration */ - audio_frame_size = av_get_audio_frame_duration(stream, 0); - if (!audio_frame_size) - audio_frame_size = stream->frame_size; - - *au_ssize= stream->block_align; - if (audio_frame_size && stream->sample_rate) { - *au_scale = audio_frame_size; - *au_rate= stream->sample_rate; - }else if(stream->codec_type == AVMEDIA_TYPE_VIDEO || - stream->codec_type == AVMEDIA_TYPE_DATA || - stream->codec_type == AVMEDIA_TYPE_SUBTITLE){ - *au_scale= stream->time_base.num; - *au_rate = stream->time_base.den; - }else{ - *au_scale= stream->block_align ? stream->block_align*8 : 8; - *au_rate = stream->bit_rate ? stream->bit_rate : 8*stream->sample_rate; - } - gcd= av_gcd(*au_scale, *au_rate); - *au_scale /= gcd; - *au_rate /= gcd; -} - -void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str) -{ - int len = strlen(str); - if (len > 0) { - len++; - ffio_wfourcc(pb, tag); - avio_wl32(pb, len); - avio_put_str(pb, str); - if (len & 1) - avio_w8(pb, 0); - } -} - -static const char riff_tags[][5] = { - "IARL", "IART", "ICMS", "ICMT", "ICOP", "ICRD", "ICRP", "IDIM", "IDPI", - "IENG", "IGNR", "IKEY", "ILGT", "ILNG", "IMED", "INAM", "IPLT", "IPRD", - "IPRT", "ISBJ", "ISFT", "ISHP", "ISMP", "ISRC", "ISRF", "ITCH", - {0} -}; - -static int riff_has_valid_tags(AVFormatContext *s) +const struct AVCodecTag *avformat_get_riff_video_tags(void) { - int i; - - for (i = 0; *riff_tags[i]; i++) { - if (av_dict_get(s->metadata, riff_tags[i], NULL, AV_DICT_MATCH_CASE)) - return 1; - } - - return 0; + return ff_codec_bmp_tags; } -void ff_riff_write_info(AVFormatContext *s) +const struct AVCodecTag *avformat_get_riff_audio_tags(void) { - AVIOContext *pb = s->pb; - int i; - int64_t list_pos; - AVDictionaryEntry *t = NULL; - - ff_metadata_conv(&s->metadata, ff_riff_info_conv, NULL); - - /* writing empty LIST is not nice and may cause problems */ - if (!riff_has_valid_tags(s)) - return; - - list_pos = ff_start_tag(pb, "LIST"); - ffio_wfourcc(pb, "INFO"); - for (i = 0; *riff_tags[i]; i++) { - if ((t = av_dict_get(s->metadata, riff_tags[i], NULL, AV_DICT_MATCH_CASE))) - ff_riff_write_info_tag(s->pb, t->key, t->value); - } - ff_end_tag(pb, list_pos); -} -#endif //CONFIG_MUXERS - -#if CONFIG_DEMUXERS -/* We could be given one of the three possible structures here: - * WAVEFORMAT, PCMWAVEFORMAT or WAVEFORMATEX. Each structure - * is an expansion of the previous one with the fields added - * at the bottom. PCMWAVEFORMAT adds 'WORD wBitsPerSample' and - * WAVEFORMATEX adds 'WORD cbSize' and basically makes itself - * an openended structure. - */ -int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) -{ - int id; - - id = avio_rl16(pb); - codec->codec_type = AVMEDIA_TYPE_AUDIO; - codec->channels = avio_rl16(pb); - codec->sample_rate = avio_rl32(pb); - codec->bit_rate = avio_rl32(pb) * 8; - codec->block_align = avio_rl16(pb); - if (size == 14) { /* We're dealing with plain vanilla WAVEFORMAT */ - codec->bits_per_coded_sample = 8; - }else - codec->bits_per_coded_sample = avio_rl16(pb); - if (id == 0xFFFE) { - codec->codec_tag = 0; - } else { - codec->codec_tag = id; - codec->codec_id = ff_wav_codec_get_id(id, codec->bits_per_coded_sample); - } - if (size >= 18) { /* We're obviously dealing with WAVEFORMATEX */ - int cbSize = avio_rl16(pb); /* cbSize */ - size -= 18; - cbSize = FFMIN(size, cbSize); - if (cbSize >= 22 && id == 0xfffe) { /* WAVEFORMATEXTENSIBLE */ - ff_asf_guid subformat; - int bps = avio_rl16(pb); - if (bps) - codec->bits_per_coded_sample = bps; - codec->channel_layout = avio_rl32(pb); /* dwChannelMask */ - ff_get_guid(pb, &subformat); - if (!memcmp(subformat + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) { - codec->codec_tag = AV_RL32(subformat); - codec->codec_id = ff_wav_codec_get_id(codec->codec_tag, codec->bits_per_coded_sample); - } else { - codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subformat); - if (!codec->codec_id) - av_log(codec, AV_LOG_WARNING, "unknown subformat:"FF_PRI_GUID"\n", FF_ARG_GUID(subformat)); - } - cbSize -= 22; - size -= 22; - } - codec->extradata_size = cbSize; - if (cbSize > 0) { - av_free(codec->extradata); - codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!codec->extradata) - return AVERROR(ENOMEM); - avio_read(pb, codec->extradata, codec->extradata_size); - size -= cbSize; - } - - /* It is possible for the chunk to contain garbage at the end */ - if (size > 0) - avio_skip(pb, size); - } - if (codec->codec_id == AV_CODEC_ID_AAC_LATM) { - /* channels and sample_rate values are those prior to applying SBR and/or PS */ - codec->channels = 0; - codec->sample_rate = 0; - } - /* override bits_per_coded_sample for G.726 */ - if (codec->codec_id == AV_CODEC_ID_ADPCM_G726 && codec->sample_rate) - codec->bits_per_coded_sample = codec->bit_rate / codec->sample_rate; - - return 0; -} - - -enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps) -{ - enum AVCodecID id; - id = ff_codec_get_id(ff_codec_wav_tags, tag); - if (id <= 0) - return id; - - if (id == AV_CODEC_ID_PCM_S16LE) - id = ff_get_pcm_codec_id(bps, 0, 0, ~1); - else if (id == AV_CODEC_ID_PCM_F32LE) - id = ff_get_pcm_codec_id(bps, 1, 0, 0); - - if (id == AV_CODEC_ID_ADPCM_IMA_WAV && bps == 8) - id = AV_CODEC_ID_PCM_ZORK; - return id; -} - -int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize) -{ - int tag1; - if(esize) *esize = avio_rl32(pb); - else avio_rl32(pb); - st->codec->width = avio_rl32(pb); - st->codec->height = (int32_t)avio_rl32(pb); - avio_rl16(pb); /* planes */ - st->codec->bits_per_coded_sample= avio_rl16(pb); /* depth */ - tag1 = avio_rl32(pb); - avio_rl32(pb); /* ImageSize */ - avio_rl32(pb); /* XPelsPerMeter */ - avio_rl32(pb); /* YPelsPerMeter */ - avio_rl32(pb); /* ClrUsed */ - avio_rl32(pb); /* ClrImportant */ - return tag1; -} - -void ff_get_guid(AVIOContext *s, ff_asf_guid *g) -{ - av_assert0(sizeof(*g) == 16); //compiler will optimize this out - if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) - memset(*g, 0, sizeof(*g)); -} - -enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) -{ - int i; - for (i = 0; guids[i].id != AV_CODEC_ID_NONE; i++) { - if (!ff_guidcmp(guids[i].guid, guid)) - return guids[i].id; - } - return AV_CODEC_ID_NONE; -} - -int ff_read_riff_info(AVFormatContext *s, int64_t size) -{ - int64_t start, end, cur; - AVIOContext *pb = s->pb; - - start = avio_tell(pb); - end = start + size; - - while ((cur = avio_tell(pb)) >= 0 && cur <= end - 8 /* = tag + size */) { - uint32_t chunk_code; - int64_t chunk_size; - char key[5] = {0}; - char *value; - - chunk_code = avio_rl32(pb); - chunk_size = avio_rl32(pb); - if (url_feof(pb)) { - if (chunk_code || chunk_size) { - av_log(s, AV_LOG_WARNING, "INFO subchunk truncated\n"); - return AVERROR_INVALIDDATA; - } - break; - } - if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) { - avio_seek(pb, -9, SEEK_CUR); - chunk_code = avio_rl32(pb); - chunk_size = avio_rl32(pb); - if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) { - av_log(s, AV_LOG_WARNING, "too big INFO subchunk\n"); - return AVERROR_INVALIDDATA; - } - } - - chunk_size += (chunk_size & 1); - - if (!chunk_code) { - if (chunk_size) - avio_skip(pb, chunk_size); - continue; - } - - value = av_mallocz(chunk_size + 1); - if (!value) { - av_log(s, AV_LOG_ERROR, "out of memory, unable to read INFO tag\n"); - return AVERROR(ENOMEM); - } - - AV_WL32(key, chunk_code); - - if (avio_read(pb, value, chunk_size) != chunk_size) { - av_log(s, AV_LOG_WARNING, "premature end of file while reading INFO tag\n"); - } - - av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL); - } - - return 0; + return ff_codec_wav_tags; } -#endif // CONFIG_DEMUXERS diff --git a/ffmpeg/libavformat/riff.h b/ffmpeg/libavformat/riff.h index 70b2f76..ce07869 100644 --- a/ffmpeg/libavformat/riff.h +++ b/ffmpeg/libavformat/riff.h @@ -34,7 +34,6 @@ #include "metadata.h" extern const AVMetadataConv ff_riff_info_conv[]; -extern const char ff_riff_tags[][5]; int64_t ff_start_tag(AVIOContext *pb, const char *tag); void ff_end_tag(AVIOContext *pb, int64_t start); @@ -46,7 +45,7 @@ void ff_end_tag(AVIOContext *pb, int64_t start); */ int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize); -void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf); +void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf, int ignore_extradata); int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc); enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps); int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size); @@ -56,14 +55,36 @@ extern const AVCodecTag ff_codec_wav_tags[]; void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale); +int ff_read_riff_info(AVFormatContext *s, int64_t size); + +/** + * Write all recognized RIFF tags from s->metadata + */ +void ff_riff_write_info(AVFormatContext *s); + +/** + * Write a single RIFF info tag + */ +void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str); + typedef uint8_t ff_asf_guid[16]; -int ff_read_riff_info(AVFormatContext *s, int64_t size); +typedef struct AVCodecGuid { + enum AVCodecID id; + ff_asf_guid guid; +} AVCodecGuid; + +extern const AVCodecGuid ff_codec_wav_guids[]; #define FF_PRI_GUID \ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + #define FF_ARG_GUID(g) \ - g[0],g[1],g[2],g[3],g[4],g[5],g[6],g[7],g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15] + g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7], \ + g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15] + +#define FF_MEDIASUBTYPE_BASE_GUID \ + 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 static av_always_inline int ff_guidcmp(const void *g1, const void *g2) { @@ -72,26 +93,6 @@ static av_always_inline int ff_guidcmp(const void *g1, const void *g2) void ff_get_guid(AVIOContext *s, ff_asf_guid *g); -typedef struct { - enum AVCodecID id; - ff_asf_guid guid; -} AVCodecGuid; - enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid); -extern const AVCodecGuid ff_codec_wav_guids[]; - -#define FF_MEDIASUBTYPE_BASE_GUID \ - 0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 - -/** - * Write all recognized RIFF tags from s->metadata - */ -void ff_riff_write_info(AVFormatContext *s); - -/** - * Write a single RIFF info tag - */ -void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str); - #endif /* AVFORMAT_RIFF_H */ diff --git a/ffmpeg/libavformat/rl2.c b/ffmpeg/libavformat/rl2.c index 800e12e..d354339 100644 --- a/ffmpeg/libavformat/rl2.c +++ b/ffmpeg/libavformat/rl2.c @@ -32,6 +32,8 @@ * optional background_frame */ +#include <stdint.h> + #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "avformat.h" @@ -125,19 +127,15 @@ static av_cold int rl2_read_header(AVFormatContext *s) if(signature == RLV3_TAG && back_size > 0) st->codec->extradata_size += back_size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - if(!st->codec->extradata) + if(ff_get_extradata(st->codec, pb, st->codec->extradata_size) < 0) return AVERROR(ENOMEM); - if(avio_read(pb,st->codec->extradata,st->codec->extradata_size) != - st->codec->extradata_size) - return AVERROR(EIO); - /** setup audio stream if present */ if(sound_rate){ - if(channels <= 0) + if (!channels || channels > 42) { + av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", channels); return AVERROR_INVALIDDATA; + } pts_num = def_sound_size; pts_den = rate; diff --git a/ffmpeg/libavformat/rmdec.c b/ffmpeg/libavformat/rmdec.c index 478b35b..8feef54 100644 --- a/ffmpeg/libavformat/rmdec.c +++ b/ffmpeg/libavformat/rmdec.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "avformat.h" @@ -30,7 +31,7 @@ #include "rmsipr.h" #include "rm.h" -#define DEINT_ID_GENR MKTAG('g', 'e', 'n', 'r') ///< interleaving for Cooker/Atrac +#define DEINT_ID_GENR MKTAG('g', 'e', 'n', 'r') ///< interleaving for Cooker/ATRAC #define DEINT_ID_INT0 MKTAG('I', 'n', 't', '0') ///< no interleaving needed #define DEINT_ID_INT4 MKTAG('I', 'n', 't', '4') ///< interleaving for 28.8 #define DEINT_ID_SIPR MKTAG('s', 'i', 'p', 'r') ///< interleaving for Sipro @@ -85,23 +86,19 @@ static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned si { if (size >= 1<<24) return -1; - avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!avctx->extradata) + if (ff_get_extradata(avctx, pb, size) < 0) return AVERROR(ENOMEM); - avctx->extradata_size = avio_read(pb, avctx->extradata, size); - memset(avctx->extradata + avctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); - if (avctx->extradata_size != size) - return AVERROR(EIO); return 0; } -static void rm_read_metadata(AVFormatContext *s, int wide) +static void rm_read_metadata(AVFormatContext *s, AVIOContext *pb, int wide) { char buf[1024]; int i; + for (i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) { - int len = wide ? avio_rb16(s->pb) : avio_r8(s->pb); - get_strl(s->pb, buf, sizeof(buf), len); + int len = wide ? avio_rb16(pb) : avio_r8(pb); + get_strl(pb, buf, sizeof(buf), len); av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0); } } @@ -134,7 +131,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, avio_skip(pb, 8); bytes_per_minute = avio_rb16(pb); avio_skip(pb, 4); - rm_read_metadata(s, 0); + rm_read_metadata(s, pb, 0); if ((startpos + header_size) >= avio_tell(pb) + 2) { // fourcc (should always be "lpcJ") avio_r8(pb); @@ -185,6 +182,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, avio_read(pb, buf, 4); buf[4] = 0; } else { + AV_WL32(buf, 0); get_str8(pb, buf, sizeof(buf)); /* desc */ ast->deint_id = AV_RL32(buf); get_str8(pb, buf, sizeof(buf)); /* desc */ @@ -257,22 +255,16 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, default: av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); } - if (ast->deint_id == DEINT_ID_INT4 || - ast->deint_id == DEINT_ID_GENR || - ast->deint_id == DEINT_ID_SIPR) { - if (st->codec->block_align <= 0 || - ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX || - ast->audio_framesize * sub_packet_h < st->codec->block_align) - return AVERROR_INVALIDDATA; - if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0) - return AVERROR(ENOMEM); - } switch (ast->deint_id) { case DEINT_ID_INT4: if (ast->coded_framesize > ast->audio_framesize || sub_packet_h <= 1 || ast->coded_framesize * sub_packet_h > (2 + (sub_packet_h & 1)) * ast->audio_framesize) return AVERROR_INVALIDDATA; + if (ast->coded_framesize * sub_packet_h != 2*ast->audio_framesize) { + avpriv_request_sample(s, "mismatching interleaver parameters"); + return AVERROR_INVALIDDATA; + } break; case DEINT_ID_GENR: if (ast->sub_packet_size <= 0 || @@ -288,12 +280,22 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, av_log(s, AV_LOG_ERROR, "Unknown interleaver %X\n", ast->deint_id); return AVERROR_INVALIDDATA; } + if (ast->deint_id == DEINT_ID_INT4 || + ast->deint_id == DEINT_ID_GENR || + ast->deint_id == DEINT_ID_SIPR) { + if (st->codec->block_align <= 0 || + ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX || + ast->audio_framesize * sub_packet_h < st->codec->block_align) + return AVERROR_INVALIDDATA; + if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0) + return AVERROR(ENOMEM); + } if (read_all) { avio_r8(pb); avio_r8(pb); avio_r8(pb); - rm_read_metadata(s, 0); + rm_read_metadata(s, pb, 0); } } return 0; @@ -375,11 +377,16 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb, if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (avio_tell(pb) - codec_pos))) < 0) return ret; - av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num, - 0x10000, fps, (1 << 30) - 1); + if (fps > 0) { + av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num, + 0x10000, fps, (1 << 30) - 1); #if FF_API_R_FRAME_RATE - st->r_frame_rate = st->avg_frame_rate; + st->r_frame_rate = st->avg_frame_rate; #endif + } else if (s->error_recognition & AV_EF_EXPLODE) { + av_log(s, AV_LOG_ERROR, "Invalid framerate\n"); + return AVERROR_INVALIDDATA; + } } skip: @@ -516,7 +523,7 @@ static int rm_read_header(AVFormatContext *s) flags = avio_rb16(pb); /* flags */ break; case MKTAG('C', 'O', 'N', 'T'): - rm_read_metadata(s, 1); + rm_read_metadata(s, pb, 1); break; case MKTAG('M', 'D', 'P', 'R'): st = avformat_new_stream(s, NULL); @@ -662,6 +669,7 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, int hdr; int seq = 0, pic_num = 0, len2 = 0, pos = 0; //init to silcense compiler warning int type; + int ret; hdr = avio_r8(pb); len--; type = hdr >> 6; @@ -674,23 +682,31 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, pos = get_num(pb, &len); pic_num = avio_r8(pb); len--; } - if(len<0) + if(len<0) { + av_log(s, AV_LOG_ERROR, "Insufficient data\n"); return -1; + } rm->remaining_len = len; if(type&1){ // frame, not slice if(type == 3){ // frame as a part of packet len= len2; *timestamp = pos; } - if(rm->remaining_len < len) + if(rm->remaining_len < len) { + av_log(s, AV_LOG_ERROR, "Insufficient remaining len\n"); return -1; + } rm->remaining_len -= len; if(av_new_packet(pkt, len + 9) < 0) return AVERROR(EIO); pkt->data[0] = 0; AV_WL32(pkt->data + 1, 1); AV_WL32(pkt->data + 5, 0); - avio_read(pb, pkt->data + 9, len); + if ((ret = avio_read(pb, pkt->data + 9, len)) != len) { + av_free_packet(pkt); + av_log(s, AV_LOG_ERROR, "Failed to read %d bytes\n", len); + return ret < 0 ? ret : AVERROR(EIO); + } return 0; } //now we have to deal with single slice @@ -706,6 +722,7 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, av_free_packet(&vst->pkt); //FIXME this should be output. if(av_new_packet(&vst->pkt, vst->videobufsize) < 0) return AVERROR(ENOMEM); + memset(vst->pkt.data, 0, vst->pkt.size); vst->videobufpos = 8*vst->slices + 1; vst->cur_slice = 0; vst->curpic_num = pic_num; @@ -714,12 +731,18 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, if(type == 2) len = FFMIN(len, pos); - if(++vst->cur_slice > vst->slices) + if(++vst->cur_slice > vst->slices) { + av_log(s, AV_LOG_ERROR, "cur slice %d, too large\n", vst->cur_slice); return 1; + } + if(!vst->pkt.data) + return AVERROR(ENOMEM); AV_WL32(vst->pkt.data - 7 + 8*vst->cur_slice, 1); AV_WL32(vst->pkt.data - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1); - if(vst->videobufpos + len > vst->videobufsize) + if(vst->videobufpos + len > vst->videobufsize) { + av_log(s, AV_LOG_ERROR, "outside videobufsize\n"); return 1; + } if (avio_read(pb, vst->pkt.data + vst->videobufpos, len) != len) return AVERROR(EIO); vst->videobufpos += len; @@ -732,7 +755,9 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, vst->pkt.size= 0; vst->pkt.buf = NULL; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS vst->pkt.destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices, @@ -768,11 +793,13 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, int *seq, int flags, int64_t timestamp) { RMDemuxContext *rm = s->priv_data; + int ret; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { rm->current_stream= st->id; - if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, ×tamp)) - return -1; //got partial frame + ret = rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, ×tamp); + if(ret) + return ret < 0 ? ret : -1; //got partial frame or error } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if ((ast->deint_id == DEINT_ID_GENR) || (ast->deint_id == DEINT_ID_INT4) || @@ -919,6 +946,8 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, &seq, flags, timestamp); + if (res < -1) + return res; if((flags&2) && (seq&0x7F) == 1) av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); if (res) diff --git a/ffmpeg/libavformat/rmenc.c b/ffmpeg/libavformat/rmenc.c index a96c429..17192ff 100644 --- a/ffmpeg/libavformat/rmenc.c +++ b/ffmpeg/libavformat/rmenc.c @@ -374,7 +374,6 @@ static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int } else { avio_write(pb, buf, size); } - avio_flush(pb); stream->nb_frames++; av_free(buf1); return 0; @@ -419,7 +418,6 @@ static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int avio_w8(pb, stream->nb_frames & 0xff); avio_write(pb, buf, size); - avio_flush(pb); stream->nb_frames++; return 0; diff --git a/ffmpeg/libavformat/rpl.c b/ffmpeg/libavformat/rpl.c index dcc7950..fb60379 100644 --- a/ffmpeg/libavformat/rpl.c +++ b/ffmpeg/libavformat/rpl.c @@ -19,11 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> +#include <stdlib.h> + #include "libavutil/avstring.h" #include "libavutil/dict.h" #include "avformat.h" #include "internal.h" -#include <stdlib.h> #define RPL_SIGNATURE "ARMovie\x0A" #define RPL_SIGNATURE_SIZE 8 @@ -168,9 +170,8 @@ static int rpl_read_header(AVFormatContext *s) vst->codec->codec_id = AV_CODEC_ID_ESCAPE130; break; default: - av_log(s, AV_LOG_WARNING, - "RPL video format %i not supported yet!\n", - vst->codec->codec_tag); + avpriv_report_missing_feature(s, "Video format %i", + vst->codec->codec_tag); vst->codec->codec_id = AV_CODEC_ID_NONE; } @@ -220,11 +221,8 @@ static int rpl_read_header(AVFormatContext *s) } break; } - if (ast->codec->codec_id == AV_CODEC_ID_NONE) { - av_log(s, AV_LOG_WARNING, - "RPL audio format %i not supported yet!\n", - audio_format); - } + if (ast->codec->codec_id == AV_CODEC_ID_NONE) + avpriv_request_sample(s, "Audio format %i", audio_format); avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate); } else { for (i = 0; i < 3; i++) @@ -255,9 +253,11 @@ static int rpl_read_header(AVFormatContext *s) for (i = 0; !error && i < number_of_chunks; i++) { int64_t offset, video_size, audio_size; error |= read_line(pb, line, sizeof(line)); - if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64, - &offset, &video_size, &audio_size)) + if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64, + &offset, &video_size, &audio_size)) { error = -1; + continue; + } av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, video_size, rpl->frames_per_chunk, 0); if (ast) diff --git a/ffmpeg/libavformat/rtmp.h b/ffmpeg/libavformat/rtmp.h index 7c9bb6d..8fc8040 100644 --- a/ffmpeg/libavformat/rtmp.h +++ b/ffmpeg/libavformat/rtmp.h @@ -1,6 +1,6 @@ /* * RTMP definitions - * Copyright (c) 2009 Kostya Shishkov + * Copyright (c) 2009 Konstantin Shishkov * * This file is part of FFmpeg. * diff --git a/ffmpeg/libavformat/rtmphttp.c b/ffmpeg/libavformat/rtmphttp.c index 3a51f7c..0334ba5 100644 --- a/ffmpeg/libavformat/rtmphttp.c +++ b/ffmpeg/libavformat/rtmphttp.c @@ -85,14 +85,15 @@ static int rtmp_http_send_cmd(URLContext *h, const char *cmd) static int rtmp_http_write(URLContext *h, const uint8_t *buf, int size) { RTMP_HTTPContext *rt = h->priv_data; - void *ptr; if (rt->out_size + size > rt->out_capacity) { + int err; rt->out_capacity = (rt->out_size + size) * 2; - ptr = av_realloc(rt->out_data, rt->out_capacity); - if (!ptr) - return AVERROR(ENOMEM); - rt->out_data = ptr; + if ((err = av_reallocp(&rt->out_data, rt->out_capacity)) < 0) { + rt->out_size = 0; + rt->out_capacity = 0; + return err; + } } memcpy(rt->out_data + rt->out_size, buf, size); @@ -112,7 +113,7 @@ static int rtmp_http_read(URLContext *h, uint8_t *buf, int size) if (ret < 0 && ret != AVERROR_EOF) return ret; - if (ret == AVERROR_EOF) { + if (!ret || ret == AVERROR_EOF) { if (rt->finishing) { /* Do not send new requests when the client wants to * close the connection. */ @@ -226,7 +227,7 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags) /* read the server reply which contains a unique ID */ for (;;) { ret = ffurl_read(rt->stream, rt->client_id + off, sizeof(rt->client_id) - off); - if (ret == AVERROR_EOF) + if (!ret || ret == AVERROR_EOF) break; if (ret < 0) goto fail; diff --git a/ffmpeg/libavformat/rtmppkt.c b/ffmpeg/libavformat/rtmppkt.c index 3bd28eb..375ae2f 100644 --- a/ffmpeg/libavformat/rtmppkt.c +++ b/ffmpeg/libavformat/rtmppkt.c @@ -1,6 +1,6 @@ /* * RTMP input format - * Copyright (c) 2009 Kostya Shishkov + * Copyright (c) 2009 Konstantin Shishkov * * This file is part of FFmpeg. * @@ -129,41 +129,69 @@ int ff_amf_read_null(GetByteContext *bc) return 0; } +int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt, + int channel) +{ + int nb_alloc; + RTMPPacket *ptr; + if (channel < *nb_prev_pkt) + return 0; + + nb_alloc = channel + 16; + // This can't use the av_reallocp family of functions, since we + // would need to free each element in the array before the array + // itself is freed. + ptr = av_realloc_array(*prev_pkt, nb_alloc, sizeof(**prev_pkt)); + if (!ptr) + return AVERROR(ENOMEM); + memset(ptr + *nb_prev_pkt, 0, (nb_alloc - *nb_prev_pkt) * sizeof(*ptr)); + *prev_pkt = ptr; + *nb_prev_pkt = nb_alloc; + return 0; +} + int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, - int chunk_size, RTMPPacket *prev_pkt) + int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt) { uint8_t hdr; if (ffurl_read(h, &hdr, 1) != 1) return AVERROR(EIO); - return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt, hdr); + return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt, + nb_prev_pkt, hdr); } -int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, - RTMPPacket *prev_pkt, uint8_t hdr) +static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, + int chunk_size, RTMPPacket **prev_pkt_ptr, + int *nb_prev_pkt, uint8_t hdr) { - uint8_t t, buf[16]; - int channel_id, timestamp, data_size, offset = 0; + uint8_t buf[16]; + int channel_id, timestamp, size; uint32_t extra = 0; enum RTMPPacketType type; - int size = 0; - int ret; + int written = 0; + int ret, toread; + RTMPPacket *prev_pkt; - size++; + written++; channel_id = hdr & 0x3F; if (channel_id < 2) { //special case for channel number >= 64 buf[1] = 0; if (ffurl_read_complete(h, buf, channel_id + 1) != channel_id + 1) return AVERROR(EIO); - size += channel_id + 1; + written += channel_id + 1; channel_id = AV_RL16(buf) + 64; } - data_size = prev_pkt[channel_id].data_size; - type = prev_pkt[channel_id].type; - extra = prev_pkt[channel_id].extra; + if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt, + channel_id)) < 0) + return ret; + prev_pkt = *prev_pkt_ptr; + size = prev_pkt[channel_id].size; + type = prev_pkt[channel_id].type; + extra = prev_pkt[channel_id].extra; hdr >>= 6; if (hdr == RTMP_PS_ONEBYTE) { @@ -171,21 +199,21 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, } else { if (ffurl_read_complete(h, buf, 3) != 3) return AVERROR(EIO); - size += 3; + written += 3; timestamp = AV_RB24(buf); if (hdr != RTMP_PS_FOURBYTES) { if (ffurl_read_complete(h, buf, 3) != 3) return AVERROR(EIO); - size += 3; - data_size = AV_RB24(buf); + written += 3; + size = AV_RB24(buf); if (ffurl_read_complete(h, buf, 1) != 1) return AVERROR(EIO); - size++; + written++; type = buf[0]; if (hdr == RTMP_PS_TWELVEBYTES) { if (ffurl_read_complete(h, buf, 4) != 4) return AVERROR(EIO); - size += 4; + written += 4; extra = AV_RL32(buf); } } @@ -198,47 +226,88 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, if (hdr != RTMP_PS_TWELVEBYTES) timestamp += prev_pkt[channel_id].timestamp; - if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp, - data_size)) < 0) - return ret; + if (!prev_pkt[channel_id].read) { + if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp, + size)) < 0) + return ret; + p->read = written; + p->offset = 0; + prev_pkt[channel_id].ts_delta = timestamp - + prev_pkt[channel_id].timestamp; + prev_pkt[channel_id].timestamp = timestamp; + } else { + // previous packet in this channel hasn't completed reading + RTMPPacket *prev = &prev_pkt[channel_id]; + p->data = prev->data; + p->size = prev->size; + p->channel_id = prev->channel_id; + p->type = prev->type; + p->ts_delta = prev->ts_delta; + p->extra = prev->extra; + p->offset = prev->offset; + p->read = prev->read + written; + p->timestamp = prev->timestamp; + prev->data = NULL; + } p->extra = extra; // save history prev_pkt[channel_id].channel_id = channel_id; prev_pkt[channel_id].type = type; - prev_pkt[channel_id].data_size = data_size; - prev_pkt[channel_id].ts_delta = timestamp - prev_pkt[channel_id].timestamp; - prev_pkt[channel_id].timestamp = timestamp; + prev_pkt[channel_id].size = size; prev_pkt[channel_id].extra = extra; - while (data_size > 0) { - int toread = FFMIN(data_size, chunk_size); - if (ffurl_read_complete(h, p->data + offset, toread) != toread) { - ff_rtmp_packet_destroy(p); + size = size - p->offset; + + toread = FFMIN(size, chunk_size); + if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) { + ff_rtmp_packet_destroy(p); + return AVERROR(EIO); + } + size -= toread; + p->read += toread; + p->offset += toread; + + if (size > 0) { + RTMPPacket *prev = &prev_pkt[channel_id]; + prev->data = p->data; + prev->read = p->read; + prev->offset = p->offset; + return AVERROR(EAGAIN); + } + + prev_pkt[channel_id].read = 0; // read complete; reset if needed + return p->read; +} + +int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, + RTMPPacket **prev_pkt, int *nb_prev_pkt, + uint8_t hdr) +{ + while (1) { + int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt, + nb_prev_pkt, hdr); + if (ret > 0 || ret != AVERROR(EAGAIN)) + return ret; + + if (ffurl_read(h, &hdr, 1) != 1) return AVERROR(EIO); - } - data_size -= chunk_size; - offset += chunk_size; - size += chunk_size; - if (data_size > 0) { - if ((ret = ffurl_read_complete(h, &t, 1)) < 0) { // marker - ff_rtmp_packet_destroy(p); - return ret; - } - size++; - if (t != (0xC0 + channel_id)) - return -1; - } } - return size; } int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, - int chunk_size, RTMPPacket *prev_pkt) + int chunk_size, RTMPPacket **prev_pkt_ptr, + int *nb_prev_pkt) { uint8_t pkt_hdr[16], *p = pkt_hdr; int mode = RTMP_PS_TWELVEBYTES; int off = 0; - int size = 0; + int written = 0; int ret; + RTMPPacket *prev_pkt; + + if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt, + pkt->channel_id)) < 0) + return ret; + prev_pkt = *prev_pkt_ptr; pkt->ts_delta = pkt->timestamp - prev_pkt[pkt->channel_id].timestamp; @@ -246,7 +315,7 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, if (prev_pkt[pkt->channel_id].channel_id && pkt->extra == prev_pkt[pkt->channel_id].extra) { if (pkt->type == prev_pkt[pkt->channel_id].type && - pkt->data_size == prev_pkt[pkt->channel_id].data_size) { + pkt->size == prev_pkt[pkt->channel_id].size) { mode = RTMP_PS_FOURBYTES; if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta) mode = RTMP_PS_ONEBYTE; @@ -270,7 +339,7 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, timestamp = pkt->ts_delta; bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp); if (mode != RTMP_PS_FOURBYTES) { - bytestream_put_be24(&p, pkt->data_size); + bytestream_put_be24(&p, pkt->size); bytestream_put_byte(&p, pkt->type); if (mode == RTMP_PS_TWELVEBYTES) bytestream_put_le32(&p, pkt->extra); @@ -281,7 +350,7 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, // save history prev_pkt[pkt->channel_id].channel_id = pkt->channel_id; prev_pkt[pkt->channel_id].type = pkt->type; - prev_pkt[pkt->channel_id].data_size = pkt->data_size; + prev_pkt[pkt->channel_id].size = pkt->size; prev_pkt[pkt->channel_id].timestamp = pkt->timestamp; if (mode != RTMP_PS_TWELVEBYTES) { prev_pkt[pkt->channel_id].ts_delta = pkt->ts_delta; @@ -292,20 +361,20 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0) return ret; - size = p - pkt_hdr + pkt->data_size; - while (off < pkt->data_size) { - int towrite = FFMIN(chunk_size, pkt->data_size - off); + written = p - pkt_hdr + pkt->size; + while (off < pkt->size) { + int towrite = FFMIN(chunk_size, pkt->size - off); if ((ret = ffurl_write(h, pkt->data + off, towrite)) < 0) return ret; off += towrite; - if (off < pkt->data_size) { + if (off < pkt->size) { uint8_t marker = 0xC0 | pkt->channel_id; if ((ret = ffurl_write(h, &marker, 1)) < 0) return ret; - size++; + written++; } } - return size; + return written; } int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, @@ -316,7 +385,7 @@ int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, if (!pkt->data) return AVERROR(ENOMEM); } - pkt->data_size = size; + pkt->size = size; pkt->channel_id = channel_id; pkt->type = type; pkt->timestamp = timestamp; @@ -331,34 +400,41 @@ void ff_rtmp_packet_destroy(RTMPPacket *pkt) if (!pkt) return; av_freep(&pkt->data); - pkt->data_size = 0; + pkt->size = 0; } int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end) { const uint8_t *base = data; + AMFDataType type; + unsigned nb = -1; + int parse_key = 1; if (data >= data_end) return -1; - switch (*data++) { + switch ((type = *data++)) { case AMF_DATA_TYPE_NUMBER: return 9; case AMF_DATA_TYPE_BOOL: return 2; case AMF_DATA_TYPE_STRING: return 3 + AV_RB16(data); case AMF_DATA_TYPE_LONG_STRING: return 5 + AV_RB32(data); case AMF_DATA_TYPE_NULL: return 1; case AMF_DATA_TYPE_ARRAY: - data += 4; + parse_key = 0; + case AMF_DATA_TYPE_MIXEDARRAY: + nb = bytestream_get_be32(&data); case AMF_DATA_TYPE_OBJECT: - for (;;) { - int size = bytestream_get_be16(&data); + while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) { int t; - if (!size) { - data++; - break; + if (parse_key) { + int size = bytestream_get_be16(&data); + if (!size) { + data++; + break; + } + if (size < 0 || size >= data_end - data) + return -1; + data += size; } - if (size < 0 || size >= data_end - data) - return -1; - data += size; t = ff_amf_tag_size(data, data_end); if (t < 0 || t >= data_end - data) return -1; @@ -438,14 +514,17 @@ static const char* rtmp_packet_type(int type) } } -static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *data_end) +static void amf_tag_contents(void *ctx, const uint8_t *data, + const uint8_t *data_end) { - unsigned int size; + unsigned int size, nb = -1; char buf[1024]; + AMFDataType type; + int parse_key = 1; if (data >= data_end) return; - switch (*data++) { + switch ((type = *data++)) { case AMF_DATA_TYPE_NUMBER: av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2double(AV_RB64(data))); return; @@ -454,7 +533,7 @@ static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *d return; case AMF_DATA_TYPE_STRING: case AMF_DATA_TYPE_LONG_STRING: - if (data[-1] == AMF_DATA_TYPE_STRING) { + if (type == AMF_DATA_TYPE_STRING) { size = bytestream_get_be16(&data); } else { size = bytestream_get_be32(&data); @@ -468,23 +547,29 @@ static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *d av_log(ctx, AV_LOG_DEBUG, " NULL\n"); return; case AMF_DATA_TYPE_ARRAY: - data += 4; + parse_key = 0; + case AMF_DATA_TYPE_MIXEDARRAY: + nb = bytestream_get_be32(&data); case AMF_DATA_TYPE_OBJECT: av_log(ctx, AV_LOG_DEBUG, " {\n"); - for (;;) { + while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) { int t; - size = bytestream_get_be16(&data); - av_strlcpy(buf, data, FFMIN(sizeof(buf), size + 1)); - if (!size) { - av_log(ctx, AV_LOG_DEBUG, " }\n"); - data++; - break; + if (parse_key) { + size = bytestream_get_be16(&data); + size = FFMIN(size, sizeof(buf) - 1); + if (!size) { + av_log(ctx, AV_LOG_DEBUG, " }\n"); + data++; + break; + } + memcpy(buf, data, size); + buf[size] = 0; + if (size >= data_end - data) + return; + data += size; + av_log(ctx, AV_LOG_DEBUG, " %s: ", buf); } - if (size >= data_end - data) - return; - data += size; - av_log(ctx, AV_LOG_DEBUG, " %s: ", buf); - ff_amf_tag_contents(ctx, data, data_end); + amf_tag_contents(ctx, data, data_end); t = ff_amf_tag_size(data, data_end); if (t < 0 || t >= data_end - data) return; @@ -502,12 +587,12 @@ static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *d void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p) { av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n", - rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->data_size); + rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->size); if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) { - uint8_t *src = p->data, *src_end = p->data + p->data_size; + uint8_t *src = p->data, *src_end = p->data + p->size; while (src < src_end) { int sz; - ff_amf_tag_contents(ctx, src, src_end); + amf_tag_contents(ctx, src, src_end); sz = ff_amf_tag_size(src, src_end); if (sz < 0) break; @@ -519,8 +604,41 @@ void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p) av_log(ctx, AV_LOG_DEBUG, "Client BW = %d\n", AV_RB32(p->data)); } else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) { int i; - for (i = 0; i < p->data_size; i++) + for (i = 0; i < p->size; i++) av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]); av_log(ctx, AV_LOG_DEBUG, "\n"); } } + +int ff_amf_match_string(const uint8_t *data, int size, const char *str) +{ + int len = strlen(str); + int amf_len, type; + + if (size < 1) + return 0; + + type = *data++; + + if (type != AMF_DATA_TYPE_LONG_STRING && + type != AMF_DATA_TYPE_STRING) + return 0; + + if (type == AMF_DATA_TYPE_LONG_STRING) { + if ((size -= 4 + 1) < 0) + return 0; + amf_len = bytestream_get_be32(&data); + } else { + if ((size -= 2 + 1) < 0) + return 0; + amf_len = bytestream_get_be16(&data); + } + + if (amf_len > size) + return 0; + + if (amf_len != len) + return 0; + + return !memcmp(data, str, len); +} diff --git a/ffmpeg/libavformat/rtmppkt.h b/ffmpeg/libavformat/rtmppkt.h index a942295..fb79fed 100644 --- a/ffmpeg/libavformat/rtmppkt.h +++ b/ffmpeg/libavformat/rtmppkt.h @@ -1,6 +1,6 @@ /* * RTMP packet utilities - * Copyright (c) 2009 Kostya Shishkov + * Copyright (c) 2009 Konstantin Shishkov * * This file is part of FFmpeg. * @@ -36,9 +36,9 @@ enum RTMPChannel { RTMP_NETWORK_CHANNEL = 2, ///< channel for network-related messages (bandwidth report, ping, etc) RTMP_SYSTEM_CHANNEL, ///< channel for sending server control messages - RTMP_SOURCE_CHANNEL, ///< channel for sending a/v to server - RTMP_VIDEO_CHANNEL = 8, ///< channel for video data RTMP_AUDIO_CHANNEL, ///< channel for audio data + RTMP_VIDEO_CHANNEL = 6, ///< channel for video data + RTMP_SOURCE_CHANNEL = 8, ///< channel for a/v invokes }; /** @@ -81,7 +81,9 @@ typedef struct RTMPPacket { uint32_t ts_delta; ///< timestamp increment to the previous one in milliseconds (latter only for media packets) uint32_t extra; ///< probably an additional channel ID used during streaming data uint8_t *data; ///< packet payload - int data_size; ///< packet payload size + int size; ///< packet payload size + int offset; ///< amount of data read so far + int read; ///< amount read, including headers } RTMPPacket; /** @@ -112,10 +114,12 @@ void ff_rtmp_packet_destroy(RTMPPacket *pkt); * @param chunk_size current chunk size * @param prev_pkt previously read packet headers for all channels * (may be needed for restoring incomplete packet header) + * @param nb_prev_pkt number of allocated elements in prev_pkt * @return number of bytes read on success, negative value otherwise */ int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, - int chunk_size, RTMPPacket *prev_pkt); + int chunk_size, RTMPPacket **prev_pkt, + int *nb_prev_pkt); /** * Read internal RTMP packet sent by the server. * @@ -124,11 +128,13 @@ int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, * @param chunk_size current chunk size * @param prev_pkt previously read packet headers for all channels * (may be needed for restoring incomplete packet header) + * @param nb_prev_pkt number of allocated elements in prev_pkt * @param c the first byte already read * @return number of bytes read on success, negative value otherwise */ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, - RTMPPacket *prev_pkt, uint8_t c); + RTMPPacket **prev_pkt, int *nb_prev_pkt, + uint8_t c); /** * Send RTMP packet to the server. @@ -138,10 +144,12 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, * @param chunk_size current chunk size * @param prev_pkt previously sent packet headers for all channels * (may be used for packet header compressing) + * @param nb_prev_pkt number of allocated elements in prev_pkt * @return number of bytes written on success, negative value otherwise */ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *p, - int chunk_size, RTMPPacket *prev_pkt); + int chunk_size, RTMPPacket **prev_pkt, + int *nb_prev_pkt); /** * Print information and contents of RTMP packet. @@ -152,6 +160,16 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *p, void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p); /** + * Enlarge the prev_pkt array to fit the given channel + * + * @param prev_pkt array with previously sent packet headers + * @param nb_prev_pkt number of allocated elements in prev_pkt + * @param channel the channel number that needs to be allocated + */ +int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt, + int channel); + +/** * @name Functions used to work with the AMF format (which is also used in .flv) * @see amf_* funcs in libavformat/flvdec.c * @{ @@ -282,6 +300,13 @@ int ff_amf_read_string(GetByteContext *gbc, uint8_t *str, */ int ff_amf_read_null(GetByteContext *gbc); +/** + * Match AMF string with a NULL-terminated string. + * + * @return 0 if the strings do not match. + */ + +int ff_amf_match_string(const uint8_t *data, int size, const char *str); /** @} */ // AMF funcs diff --git a/ffmpeg/libavformat/rtmpproto.c b/ffmpeg/libavformat/rtmpproto.c index d73e015..a4d7f0e 100644 --- a/ffmpeg/libavformat/rtmpproto.c +++ b/ffmpeg/libavformat/rtmpproto.c @@ -1,6 +1,6 @@ /* * RTMP network protocol - * Copyright (c) 2009 Kostya Shishkov + * Copyright (c) 2009 Konstantin Shishkov * * This file is part of FFmpeg. * @@ -48,13 +48,12 @@ #include <zlib.h> #endif -//#define DEBUG - #define APP_MAX_LENGTH 1024 #define PLAYPATH_MAX_LENGTH 256 #define TCURL_MAX_LENGTH 512 #define FLASHVER_MAX_LENGTH 64 #define RTMP_PKTDATA_DEFAULT_SIZE 4096 +#define RTMP_HEADER 11 /** RTMP protocol handler state */ typedef enum { @@ -62,8 +61,10 @@ typedef enum { STATE_HANDSHAKED, ///< client has performed handshake STATE_FCPUBLISH, ///< client FCPublishing stream (for output) STATE_PLAYING, ///< client has started receiving multimedia data from server + STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output) STATE_RECEIVING, ///< received a publish command (for input) + STATE_SENDING, ///< received a play command (for output) STATE_STOPPED, ///< the broadcast has been stopped } ClientState; @@ -76,7 +77,8 @@ typedef struct TrackedMethod { typedef struct RTMPContext { const AVClass *class; URLContext* stream; ///< TCP stream used in interactions with RTMP server - RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets + RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing) + int nb_prev_pkt[2]; ///< number of elements in prev_pkt int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into int is_input; ///< input/output flag @@ -85,7 +87,7 @@ typedef struct RTMPContext { char *app; ///< name of application char *conn; ///< append arbitrary AMF data to the Connect message ClientState state; ///< current state - int main_channel_id; ///< an additional channel ID which is used for some invocations + int stream_id; ///< ID assigned by the server for the stream uint8_t* flv_data; ///< buffer with data for demuxer int flv_size; ///< current buffer size int flv_off; ///< number of bytes read from current buffer @@ -95,7 +97,7 @@ typedef struct RTMPContext { uint32_t bytes_read; ///< number of bytes read from server uint32_t last_bytes_read; ///< number of bytes read last reported to server int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call - uint8_t flv_header[11]; ///< partial incoming flv packet header + uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header int flv_header_bytes; ///< number of initialized bytes in flv_header int nb_invokes; ///< keeps track of invoke messages char* tcurl; ///< url of the target stream @@ -150,15 +152,16 @@ static const uint8_t rtmp_server_key[] = { static int add_tracked_method(RTMPContext *rt, const char *name, int id) { - void *ptr; + int err; if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) { rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2; - ptr = av_realloc(rt->tracked_methods, - rt->tracked_methods_size * sizeof(*rt->tracked_methods)); - if (!ptr) - return AVERROR(ENOMEM); - rt->tracked_methods = ptr; + if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size * + sizeof(*rt->tracked_methods))) < 0) { + rt->nb_tracked_methods = 0; + rt->tracked_methods_size = 0; + return err; + } } rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name); @@ -186,7 +189,7 @@ static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset, int ret; int i; - bytestream2_init(&gbc, pkt->data + offset, pkt->data_size - offset); + bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset); if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0) return ret; @@ -224,7 +227,7 @@ static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track) double pkt_id; int len; - bytestream2_init(&gbc, pkt->data, pkt->data_size); + bytestream2_init(&gbc, pkt->data, pkt->size); if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0) goto fail; @@ -236,7 +239,7 @@ static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track) } ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); fail: ff_rtmp_packet_destroy(pkt); return ret; @@ -385,7 +388,7 @@ static int gen_connect(URLContext *s, RTMPContext *rt) } } - pkt.data_size = p - pkt.data; + pkt.size = p - pkt.data; return rtmp_send_packet(rt, &pkt, 1); } @@ -403,10 +406,10 @@ static int read_connect(URLContext *s, RTMPContext *rt) GetByteContext gbc; if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size, - rt->prev_pkt[1])) < 0) + &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0) return ret; cp = pkt.data; - bytestream2_init(&gbc, cp, pkt.data_size); + bytestream2_init(&gbc, cp, pkt.size); if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) { av_log(s, AV_LOG_ERROR, "Unable to read command string\n"); ff_rtmp_packet_destroy(&pkt); @@ -437,9 +440,9 @@ static int read_connect(URLContext *s, RTMPContext *rt) return ret; p = pkt.data; bytestream_put_be32(&p, rt->server_bw); - pkt.data_size = p - pkt.data; + pkt.size = p - pkt.data; ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&pkt); if (ret < 0) return ret; @@ -450,9 +453,9 @@ static int read_connect(URLContext *s, RTMPContext *rt) p = pkt.data; bytestream_put_be32(&p, rt->server_bw); bytestream_put_byte(&p, 2); // dynamic - pkt.data_size = p - pkt.data; + pkt.size = p - pkt.data; ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&pkt); if (ret < 0) return ret; @@ -466,7 +469,7 @@ static int read_connect(URLContext *s, RTMPContext *rt) bytestream_put_be16(&p, 0); // 0 -> Stream Begin bytestream_put_be32(&p, 0); ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&pkt); if (ret < 0) return ret; @@ -479,7 +482,7 @@ static int read_connect(URLContext *s, RTMPContext *rt) p = pkt.data; bytestream_put_be32(&p, rt->out_chunk_size); ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&pkt); if (ret < 0) return ret; @@ -512,9 +515,9 @@ static int read_connect(URLContext *s, RTMPContext *rt) ff_amf_write_number(&p, 0); ff_amf_write_object_end(&p); - pkt.data_size = p - pkt.data; + pkt.size = p - pkt.data; ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&pkt); if (ret < 0) return ret; @@ -527,9 +530,9 @@ static int read_connect(URLContext *s, RTMPContext *rt) ff_amf_write_number(&p, 0); ff_amf_write_null(&p); ff_amf_write_number(&p, 8192); - pkt.data_size = p - pkt.data; + pkt.size = p - pkt.data; ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&pkt); return ret; @@ -652,7 +655,7 @@ static int gen_delete_stream(URLContext *s, RTMPContext *rt) ff_amf_write_string(&p, "deleteStream"); ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); - ff_amf_write_number(&p, rt->main_channel_id); + ff_amf_write_number(&p, rt->stream_id); return rtmp_send_packet(rt, &pkt, 0); } @@ -672,7 +675,7 @@ static int gen_buffer_time(URLContext *s, RTMPContext *rt) p = pkt.data; bytestream_put_be16(&p, 3); - bytestream_put_be32(&p, rt->main_channel_id); + bytestream_put_be32(&p, rt->stream_id); bytestream_put_be32(&p, rt->client_buffer_time); return rtmp_send_packet(rt, &pkt, 0); @@ -690,18 +693,41 @@ static int gen_play(URLContext *s, RTMPContext *rt) av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath); - if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, + if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE, 0, 29 + strlen(rt->playpath))) < 0) return ret; - pkt.extra = rt->main_channel_id; + pkt.extra = rt->stream_id; p = pkt.data; ff_amf_write_string(&p, "play"); ff_amf_write_number(&p, ++rt->nb_invokes); ff_amf_write_null(&p); ff_amf_write_string(&p, rt->playpath); - ff_amf_write_number(&p, rt->live); + ff_amf_write_number(&p, rt->live * 1000); + + return rtmp_send_packet(rt, &pkt, 1); +} + +static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp) +{ + RTMPPacket pkt; + uint8_t *p; + int ret; + + av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n", + timestamp); + + if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0) + return ret; + + pkt.extra = rt->stream_id; + + p = pkt.data; + ff_amf_write_string(&p, "seek"); + ff_amf_write_number(&p, 0); //no tracking back responses + ff_amf_write_null(&p); //as usual, the first null param + ff_amf_write_number(&p, timestamp); //where we want to jump return rtmp_send_packet(rt, &pkt, 1); } @@ -721,7 +747,7 @@ static int gen_publish(URLContext *s, RTMPContext *rt) 0, 30 + strlen(rt->playpath))) < 0) return ret; - pkt.extra = rt->main_channel_id; + pkt.extra = rt->stream_id; p = pkt.data; ff_amf_write_string(&p, "publish"); @@ -742,9 +768,9 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt) uint8_t *p; int ret; - if (ppkt->data_size < 6) { + if (ppkt->size < 6) { av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n", - ppkt->data_size); + ppkt->size); return AVERROR_INVALIDDATA; } @@ -1323,7 +1349,7 @@ static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int, int inoutsize; AV_WB32(arraydata, first_int); - AV_WB32(arraydata + 4, first_int); + AV_WB32(arraydata + 4, second_int); inoutsize = ffurl_write(rt->stream, arraydata, RTMP_HANDSHAKE_PACKET_SIZE); if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) { @@ -1372,8 +1398,6 @@ static int rtmp_server_handshake(URLContext *s, RTMPContext *rt) av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n"); return ret; } - if (zeroes) - av_log(s, AV_LOG_WARNING, "Erroneous C1 Message zero != 0\n"); /* Send S1 */ /* By now same epoch will be sent */ hs_my_epoch = hs_epoch; @@ -1418,10 +1442,10 @@ static int handle_chunk_size(URLContext *s, RTMPPacket *pkt) RTMPContext *rt = s->priv_data; int ret; - if (pkt->data_size < 4) { + if (pkt->size < 4) { av_log(s, AV_LOG_ERROR, "Too short chunk size change packet (%d)\n", - pkt->data_size); + pkt->size); return AVERROR_INVALIDDATA; } @@ -1429,7 +1453,7 @@ static int handle_chunk_size(URLContext *s, RTMPPacket *pkt) /* Send the same chunk size change packet back to the server, * setting the outgoing chunk size to the same as the incoming one. */ if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size, - rt->prev_pkt[1])) < 0) + &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0) return ret; rt->out_chunk_size = AV_RB32(pkt->data); } @@ -1451,9 +1475,9 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt) RTMPContext *rt = s->priv_data; int t, ret; - if (pkt->data_size < 2) { + if (pkt->size < 2) { av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n", - pkt->data_size); + pkt->size); return AVERROR_INVALIDDATA; } @@ -1477,10 +1501,10 @@ static int handle_client_bw(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; - if (pkt->data_size < 4) { + if (pkt->size < 4) { av_log(s, AV_LOG_ERROR, "Client bandwidth report packet is less than 4 bytes long (%d)\n", - pkt->data_size); + pkt->size); return AVERROR_INVALIDDATA; } @@ -1501,10 +1525,10 @@ static int handle_server_bw(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; - if (pkt->data_size < 4) { + if (pkt->size < 4) { av_log(s, AV_LOG_ERROR, "Too short server bandwidth report packet (%d)\n", - pkt->data_size); + pkt->size); return AVERROR_INVALIDDATA; } @@ -1587,6 +1611,8 @@ static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce) av_md5_update(md5, method, strlen(method)); av_md5_update(md5, ":/", 2); av_md5_update(md5, rt->app, strlen(rt->app)); + if (!strchr(rt->app, '/')) + av_md5_update(md5, "/_definst_", strlen("/_definst_")); av_md5_final(md5, hash); ff_data_to_hex(hashstr2, hash, 16, 1); hashstr2[32] = '\0'; @@ -1704,7 +1730,7 @@ static int handle_connect_error(URLContext *s, const char *desc) static int handle_invoke_error(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; - const uint8_t *data_end = pkt->data + pkt->data_size; + const uint8_t *data_end = pkt->data + pkt->size; char *tracked_method = NULL; int level = AV_LOG_ERROR; uint8_t tmpstr[256]; @@ -1737,13 +1763,84 @@ static int handle_invoke_error(URLContext *s, RTMPPacket *pkt) return ret; } +static int write_begin(URLContext *s) +{ + RTMPContext *rt = s->priv_data; + PutByteContext pbc; + RTMPPacket spkt = { 0 }; + int ret; + + // Send Stream Begin 1 + if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL, + RTMP_PT_PING, 0, 6)) < 0) { + av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return ret; + } + + bytestream2_init_writer(&pbc, spkt.data, spkt.size); + bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin + bytestream2_put_be32(&pbc, rt->nb_streamid); + + ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); + + ff_rtmp_packet_destroy(&spkt); + + return ret; +} + +static int write_status(URLContext *s, RTMPPacket *pkt, + const char *status, const char *filename) +{ + RTMPContext *rt = s->priv_data; + RTMPPacket spkt = { 0 }; + char statusmsg[128]; + uint8_t *pp; + int ret; + + if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, + RTMP_PT_INVOKE, 0, + RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { + av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return ret; + } + + pp = spkt.data; + spkt.extra = pkt->extra; + ff_amf_write_string(&pp, "onStatus"); + ff_amf_write_number(&pp, 0); + ff_amf_write_null(&pp); + + ff_amf_write_object_start(&pp); + ff_amf_write_field_name(&pp, "level"); + ff_amf_write_string(&pp, "status"); + ff_amf_write_field_name(&pp, "code"); + ff_amf_write_string(&pp, status); + ff_amf_write_field_name(&pp, "description"); + snprintf(statusmsg, sizeof(statusmsg), + "%s is now published", filename); + ff_amf_write_string(&pp, statusmsg); + ff_amf_write_field_name(&pp, "details"); + ff_amf_write_string(&pp, filename); + ff_amf_write_field_name(&pp, "clientid"); + snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT); + ff_amf_write_string(&pp, statusmsg); + ff_amf_write_object_end(&pp); + + spkt.size = pp - spkt.data; + ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); + ff_rtmp_packet_destroy(&spkt); + + return ret; +} + static int send_invoke_response(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; double seqnum; char filename[64]; char command[64]; - char statusmsg[128]; int stringlen; char *pchar; const uint8_t *p = pkt->data; @@ -1752,7 +1849,7 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt) GetByteContext gbc; int ret; - bytestream2_init(&gbc, p, pkt->data_size); + bytestream2_init(&gbc, p, pkt->size); if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) { av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n"); @@ -1796,52 +1893,20 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt) pp = spkt.data; ff_amf_write_string(&pp, "onFCPublish"); } else if (!strcmp(command, "publish")) { - PutByteContext pbc; - // Send Stream Begin 1 - if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL, - RTMP_PT_PING, 0, 6)) < 0) { - av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); - return ret; - } - pp = spkt.data; - bytestream2_init_writer(&pbc, pp, spkt.data_size); - bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin - bytestream2_put_be32(&pbc, rt->nb_streamid); - ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, - rt->prev_pkt[1]); - ff_rtmp_packet_destroy(&spkt); + ret = write_begin(s); if (ret < 0) return ret; // Send onStatus(NetStream.Publish.Start) - if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, - RTMP_PT_INVOKE, 0, - RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { - av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); + return write_status(s, pkt, "NetStream.Publish.Start", + filename); + } else if (!strcmp(command, "play")) { + ret = write_begin(s); + if (ret < 0) return ret; - } - spkt.extra = pkt->extra; - pp = spkt.data; - ff_amf_write_string(&pp, "onStatus"); - ff_amf_write_number(&pp, 0); - ff_amf_write_null(&pp); - - ff_amf_write_object_start(&pp); - ff_amf_write_field_name(&pp, "level"); - ff_amf_write_string(&pp, "status"); - ff_amf_write_field_name(&pp, "code"); - ff_amf_write_string(&pp, "NetStream.Publish.Start"); - ff_amf_write_field_name(&pp, "description"); - snprintf(statusmsg, sizeof(statusmsg), - "%s is now published", filename); - ff_amf_write_string(&pp, statusmsg); - ff_amf_write_field_name(&pp, "details"); - ff_amf_write_string(&pp, filename); - ff_amf_write_field_name(&pp, "clientid"); - snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT); - ff_amf_write_string(&pp, statusmsg); - ff_amf_write_object_end(&pp); - + rt->state = STATE_SENDING; + return write_status(s, pkt, "NetStream.Play.Start", + filename); } else { if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, @@ -1863,9 +1928,9 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt) * if a client creates more than 2^32 - 2 streams. */ } } - spkt.data_size = pp - spkt.data; + spkt.size = pp - spkt.data; ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, - rt->prev_pkt[1]); + &rt->prev_pkt[1], &rt->nb_prev_pkt[1]); ff_rtmp_packet_destroy(&spkt); return ret; } @@ -1884,7 +1949,7 @@ static int handle_invoke_result(URLContext *s, RTMPPacket *pkt) return ret; } - if (!memcmp(tracked_method, "connect", 7)) { + if (!strcmp(tracked_method, "connect")) { if (!rt->is_input) { if ((ret = gen_release_stream(s, rt)) < 0) goto fail; @@ -1910,12 +1975,12 @@ static int handle_invoke_result(URLContext *s, RTMPPacket *pkt) goto fail; } } - } else if (!memcmp(tracked_method, "createStream", 12)) { + } else if (!strcmp(tracked_method, "createStream")) { //extract a number from the result if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) { av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n"); } else { - rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21)); + rt->stream_id = av_int2double(AV_RB64(pkt->data + 21)); } if (!rt->is_input) { @@ -1937,8 +2002,8 @@ fail: static int handle_invoke_status(URLContext *s, RTMPPacket *pkt) { RTMPContext *rt = s->priv_data; - const uint8_t *data_end = pkt->data + pkt->data_size; - const uint8_t *ptr = pkt->data + 11; + const uint8_t *data_end = pkt->data + pkt->size; + const uint8_t *ptr = pkt->data + RTMP_HEADER; uint8_t tmpstr[256]; int i, t; @@ -1951,8 +2016,12 @@ static int handle_invoke_status(URLContext *s, RTMPPacket *pkt) t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr)); if (!t && !strcmp(tmpstr, "error")) { - if (!ff_amf_get_field_value(ptr, data_end, - "description", tmpstr, sizeof(tmpstr))) + t = ff_amf_get_field_value(ptr, data_end, + "description", tmpstr, sizeof(tmpstr)); + if (t || !tmpstr[0]) + t = ff_amf_get_field_value(ptr, data_end, "code", + tmpstr, sizeof(tmpstr)); + if (!t) av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr); return -1; } @@ -1962,6 +2031,7 @@ static int handle_invoke_status(URLContext *s, RTMPPacket *pkt) if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED; if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED; if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING; + if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING; return 0; } @@ -1972,23 +2042,24 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt) int ret = 0; //TODO: check for the messages sent for wrong state? - if (!memcmp(pkt->data, "\002\000\006_error", 9)) { + if (ff_amf_match_string(pkt->data, pkt->size, "_error")) { if ((ret = handle_invoke_error(s, pkt)) < 0) return ret; - } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) { + } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) { if ((ret = handle_invoke_result(s, pkt)) < 0) return ret; - } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) { + } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) { if ((ret = handle_invoke_status(s, pkt)) < 0) return ret; - } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) { + } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) { if ((ret = gen_check_bw(s, rt)) < 0) return ret; - } else if (!memcmp(pkt->data, "\002\000\015releaseStream", 16) || - !memcmp(pkt->data, "\002\000\011FCPublish", 12) || - !memcmp(pkt->data, "\002\000\007publish", 10) || - !memcmp(pkt->data, "\002\000\010_checkbw", 11) || - !memcmp(pkt->data, "\002\000\014createStream", 15)) { + } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") || + ff_amf_match_string(pkt->data, pkt->size, "FCPublish") || + ff_amf_match_string(pkt->data, pkt->size, "publish") || + ff_amf_match_string(pkt->data, pkt->size, "play") || + ff_amf_match_string(pkt->data, pkt->size, "_checkbw") || + ff_amf_match_string(pkt->data, pkt->size, "createStream")) { if ((ret = send_invoke_response(s, pkt)) < 0) return ret; } @@ -1996,65 +2067,75 @@ static int handle_invoke(URLContext *s, RTMPPacket *pkt) return ret; } -static int handle_notify(URLContext *s, RTMPPacket *pkt) { +static int update_offset(RTMPContext *rt, int size) +{ + int old_flv_size; + + // generate packet header and put data into buffer for FLV demuxer + if (rt->flv_off < rt->flv_size) { + // There is old unread data in the buffer, thus append at the end + old_flv_size = rt->flv_size; + rt->flv_size += size; + } else { + // All data has been read, write the new data at the start of the buffer + old_flv_size = 0; + rt->flv_size = size; + rt->flv_off = 0; + } + + return old_flv_size; +} + +static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip) +{ + int old_flv_size, ret; + PutByteContext pbc; + const uint8_t *data = pkt->data + skip; + const int size = pkt->size - skip; + uint32_t ts = pkt->timestamp; + + old_flv_size = update_offset(rt, size + 15); + + if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) { + rt->flv_size = rt->flv_off = 0; + return ret; + } + bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size); + bytestream2_skip_p(&pbc, old_flv_size); + bytestream2_put_byte(&pbc, pkt->type); + bytestream2_put_be24(&pbc, size); + bytestream2_put_be24(&pbc, ts); + bytestream2_put_byte(&pbc, ts >> 24); + bytestream2_put_be24(&pbc, 0); + bytestream2_put_buffer(&pbc, data, size); + bytestream2_put_be32(&pbc, 0); + + return 0; +} + +static int handle_notify(URLContext *s, RTMPPacket *pkt) +{ RTMPContext *rt = s->priv_data; - const uint8_t *p = NULL; - uint8_t *cp = NULL; uint8_t commandbuffer[64]; char statusmsg[128]; - int stringlen; + int stringlen, ret, skip = 0; GetByteContext gbc; - PutByteContext pbc; - uint32_t ts; - int old_flv_size; - const uint8_t *datatowrite; - unsigned datatowritelength; - p = pkt->data; - bytestream2_init(&gbc, p, pkt->data_size); + bytestream2_init(&gbc, pkt->data, pkt->size); if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer), &stringlen)) return AVERROR_INVALIDDATA; + + // Skip the @setDataFrame string and validate it is a notification if (!strcmp(commandbuffer, "@setDataFrame")) { - datatowrite = gbc.buffer; - datatowritelength = bytestream2_get_bytes_left(&gbc); - if (ff_amf_read_string(&gbc, statusmsg, - sizeof(statusmsg), &stringlen)) + skip = gbc.buffer - pkt->data; + ret = ff_amf_read_string(&gbc, statusmsg, + sizeof(statusmsg), &stringlen); + if (ret < 0) return AVERROR_INVALIDDATA; - if (strcmp(statusmsg, "onMetaData")) { - av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n", - statusmsg); - return 0; - } - - /* Provide ECMAArray to flv */ - ts = pkt->timestamp; - - // generate packet header and put data into buffer for FLV demuxer - if (rt->flv_off < rt->flv_size) { - old_flv_size = rt->flv_size; - rt->flv_size += datatowritelength + 15; - } else { - old_flv_size = 0; - rt->flv_size = datatowritelength + 15; - rt->flv_off = 0; - } - - cp = av_realloc(rt->flv_data, rt->flv_size); - if (!cp) - return AVERROR(ENOMEM); - rt->flv_data = cp; - bytestream2_init_writer(&pbc, cp, rt->flv_size); - bytestream2_skip_p(&pbc, old_flv_size); - bytestream2_put_byte(&pbc, pkt->type); - bytestream2_put_be24(&pbc, datatowritelength); - bytestream2_put_be24(&pbc, ts); - bytestream2_put_byte(&pbc, ts >> 24); - bytestream2_put_be24(&pbc, 0); - bytestream2_put_buffer(&pbc, datatowrite, datatowritelength); - bytestream2_put_be32(&pbc, 0); } - return 0; + + return append_flv_data(rt, pkt, skip); } /** @@ -2108,6 +2189,55 @@ static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt) return 0; } +static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt) +{ + int ret, old_flv_size, type; + const uint8_t *next; + uint8_t *p; + uint32_t size; + uint32_t ts, cts, pts = 0; + + old_flv_size = update_offset(rt, pkt->size); + + if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) { + rt->flv_size = rt->flv_off = 0; + return ret; + } + + next = pkt->data; + p = rt->flv_data + old_flv_size; + + /* copy data while rewriting timestamps */ + ts = pkt->timestamp; + + while (next - pkt->data < pkt->size - RTMP_HEADER) { + type = bytestream_get_byte(&next); + size = bytestream_get_be24(&next); + cts = bytestream_get_be24(&next); + cts |= bytestream_get_byte(&next) << 24; + if (!pts) + pts = cts; + ts += cts - pts; + pts = cts; + if (size + 3 + 4 > pkt->data + pkt->size - next) + break; + bytestream_put_byte(&p, type); + bytestream_put_be24(&p, size); + bytestream_put_be24(&p, ts); + bytestream_put_byte(&p, ts >> 24); + memcpy(p, next, size + 3 + 4); + next += size + 3 + 4; + p += size + 3 + 4; + } + if (p != rt->flv_data + rt->flv_size) { + av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in " + "RTMP_PT_METADATA packet\n"); + rt->flv_size = p - rt->flv_data; + } + + return 0; +} + /** * Interact with the server by receiving and sending RTMP packets until * there is some significant data (media data or expected status notification). @@ -2123,10 +2253,6 @@ static int get_packet(URLContext *s, int for_header) { RTMPContext *rt = s->priv_data; int ret; - uint8_t *p; - const uint8_t *next; - uint32_t data_size; - uint32_t ts, cts, pts=0; if (rt->state == STATE_STOPPED) return AVERROR_EOF; @@ -2134,7 +2260,8 @@ static int get_packet(URLContext *s, int for_header) for (;;) { RTMPPacket rpkt = { 0 }; if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt, - rt->in_chunk_size, rt->prev_pkt[0])) <= 0) { + rt->in_chunk_size, &rt->prev_pkt[0], + &rt->nb_prev_pkt[0])) <= 0) { if (ret == 0) { return AVERROR(EAGAIN); } else { @@ -2150,6 +2277,17 @@ static int get_packet(URLContext *s, int for_header) } ret = rtmp_parse_result(s, rt, &rpkt); + + // At this point we must check if we are in the seek state and continue + // with the next packet. handle_invoke will get us out of this state + // when the right message is encountered + if (rt->state == STATE_SEEKING) { + ff_rtmp_packet_destroy(&rpkt); + // We continue, let the natural flow of things happen: + // AVERROR(EAGAIN) or handle_invoke gets us out of here + continue; + } + if (ret < 0) {//serious error in current packet ff_rtmp_packet_destroy(&rpkt); return ret; @@ -2164,62 +2302,25 @@ static int get_packet(URLContext *s, int for_header) } if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING || + rt->state == STATE_SENDING || rt->state == STATE_RECEIVING)) { ff_rtmp_packet_destroy(&rpkt); return 0; } - if (!rpkt.data_size || !rt->is_input) { + if (!rpkt.size || !rt->is_input) { ff_rtmp_packet_destroy(&rpkt); continue; } - if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO || - (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) { - ts = rpkt.timestamp; - - // generate packet header and put data into buffer for FLV demuxer - rt->flv_off = 0; - rt->flv_size = rpkt.data_size + 15; - rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size); - bytestream_put_byte(&p, rpkt.type); - bytestream_put_be24(&p, rpkt.data_size); - bytestream_put_be24(&p, ts); - bytestream_put_byte(&p, ts >> 24); - bytestream_put_be24(&p, 0); - bytestream_put_buffer(&p, rpkt.data, rpkt.data_size); - bytestream_put_be32(&p, 0); + if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) { + ret = append_flv_data(rt, &rpkt, 0); ff_rtmp_packet_destroy(&rpkt); - return 0; + return ret; } else if (rpkt.type == RTMP_PT_NOTIFY) { ret = handle_notify(s, &rpkt); ff_rtmp_packet_destroy(&rpkt); - if (ret) { - av_log(s, AV_LOG_ERROR, "Handle notify error\n"); - return ret; - } - return 0; + return ret; } else if (rpkt.type == RTMP_PT_METADATA) { - // we got raw FLV data, make it available for FLV demuxer - rt->flv_off = 0; - rt->flv_size = rpkt.data_size; - rt->flv_data = av_realloc(rt->flv_data, rt->flv_size); - /* rewrite timestamps */ - next = rpkt.data; - ts = rpkt.timestamp; - while (next - rpkt.data < rpkt.data_size - 11) { - next++; - data_size = bytestream_get_be24(&next); - p=next; - cts = bytestream_get_be24(&next); - cts |= bytestream_get_byte(&next) << 24; - if (pts==0) - pts=cts; - ts += cts - pts; - pts = cts; - bytestream_put_be24(&p, ts); - bytestream_put_byte(&p, ts >> 24); - next += data_size + 3 + 4; - } - memcpy(rt->flv_data, rpkt.data, rpkt.data_size); + ret = handle_metadata(rt, &rpkt); ff_rtmp_packet_destroy(&rpkt); return 0; } @@ -2230,17 +2331,22 @@ static int get_packet(URLContext *s, int for_header) static int rtmp_close(URLContext *h) { RTMPContext *rt = h->priv_data; - int ret = 0; + int ret = 0, i, j; if (!rt->is_input) { rt->flv_data = NULL; - if (rt->out_pkt.data_size) + if (rt->out_pkt.size) ff_rtmp_packet_destroy(&rt->out_pkt); if (rt->state > STATE_FCPUBLISH) ret = gen_fcunpublish_stream(h, rt); } if (rt->state > STATE_HANDSHAKED) ret = gen_delete_stream(h, rt); + for (i = 0; i < 2; i++) { + for (j = 0; j < rt->nb_prev_pkt[i]; j++) + ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]); + av_freep(&rt->prev_pkt[i]); + } free_tracked_methods(rt); av_freep(&rt->flv_data); @@ -2276,6 +2382,13 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) hostname, sizeof(hostname), &port, path, sizeof(path), s->filename); + if (strchr(path, ' ')) { + av_log(s, AV_LOG_WARNING, + "Detected librtmp style URL parameters, these aren't supported " + "by the libavformat internal RTMP handler currently enabled. " + "See the documentation for the correct way to pass parameters.\n"); + } + if (auth[0]) { char *ptr = strchr(auth, ':'); if (ptr) { @@ -2445,29 +2558,33 @@ reconnect: } else { if (read_connect(s, s->priv_data) < 0) goto fail; - rt->is_input = 1; } do { ret = get_packet(s, 1); - } while (ret == EAGAIN); + } while (ret == AVERROR(EAGAIN)); if (ret < 0) goto fail; if (rt->do_reconnect) { + int i; ffurl_close(rt->stream); rt->stream = NULL; rt->do_reconnect = 0; rt->nb_invokes = 0; - memset(rt->prev_pkt, 0, sizeof(rt->prev_pkt)); + for (i = 0; i < 2; i++) + memset(rt->prev_pkt[i], 0, + sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]); free_tracked_methods(rt); goto reconnect; } if (rt->is_input) { + int err; // generate FLV header for demuxer rt->flv_size = 13; - rt->flv_data = av_realloc(rt->flv_data, rt->flv_size); + if ((err = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) + return err; rt->flv_off = 0; memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size); } else { @@ -2514,6 +2631,26 @@ static int rtmp_read(URLContext *s, uint8_t *buf, int size) return orig_size; } +static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp, + int flags) +{ + RTMPContext *rt = s->priv_data; + int ret; + av_log(s, AV_LOG_DEBUG, + "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n", + stream_index, timestamp, flags); + if ((ret = gen_seek(s, rt, timestamp)) < 0) { + av_log(s, AV_LOG_ERROR, + "Unable to send seek command on stream index %d at timestamp " + "%"PRId64" with flags %08x\n", + stream_index, timestamp, flags); + return ret; + } + rt->flv_off = rt->flv_size; + rt->state = STATE_SEEKING; + return timestamp; +} + static int rtmp_write(URLContext *s, const uint8_t *buf, int size) { RTMPContext *rt = s->priv_data; @@ -2533,13 +2670,14 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) continue; } - if (rt->flv_header_bytes < 11) { + if (rt->flv_header_bytes < RTMP_HEADER) { const uint8_t *header = rt->flv_header; - int copy = FFMIN(11 - rt->flv_header_bytes, size_temp); + int copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp); + int channel = RTMP_AUDIO_CHANNEL; bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy); rt->flv_header_bytes += copy; size_temp -= copy; - if (rt->flv_header_bytes < 11) + if (rt->flv_header_bytes < RTMP_HEADER) break; pkttype = bytestream_get_byte(&header); @@ -2549,20 +2687,27 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) bytestream_get_be24(&header); rt->flv_size = pktsize; + if (pkttype == RTMP_PT_VIDEO) + channel = RTMP_VIDEO_CHANNEL; + //force 12bytes header if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) || pkttype == RTMP_PT_NOTIFY) { if (pkttype == RTMP_PT_NOTIFY) pktsize += 16; - rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0; + if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1], + &rt->nb_prev_pkt[1], + channel)) < 0) + return ret; + rt->prev_pkt[1][channel].channel_id = 0; } //this can be a big packet, it's better to send it right here - if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, + if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel, pkttype, ts, pktsize)) < 0) return ret; - rt->out_pkt.extra = rt->main_channel_id; + rt->out_pkt.extra = rt->stream_id; rt->flv_data = rt->out_pkt.data; if (pkttype == RTMP_PT_NOTIFY) @@ -2614,7 +2759,8 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt, rt->in_chunk_size, - rt->prev_pkt[0], c)) <= 0) + &rt->prev_pkt[0], + &rt->nb_prev_pkt[0], c)) <= 0) return ret; if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0) @@ -2649,6 +2795,7 @@ static const AVOption rtmp_options[] = { {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC}, {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, + {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" }, { NULL }, }; @@ -2665,6 +2812,7 @@ URLProtocol ff_##flavor##_protocol = { \ .name = #flavor, \ .url_open = rtmp_open, \ .url_read = rtmp_read, \ + .url_read_seek = rtmp_seek, \ .url_write = rtmp_write, \ .url_close = rtmp_close, \ .priv_data_size = sizeof(RTMPContext), \ diff --git a/ffmpeg/libavformat/rtp.c b/ffmpeg/libavformat/rtp.c index c4dcf6a..4d41350 100644 --- a/ffmpeg/libavformat/rtp.c +++ b/ffmpeg/libavformat/rtp.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avstring.h" #include "libavutil/opt.h" #include "avformat.h" @@ -144,7 +145,7 @@ enum AVCodecID ff_rtp_codec_id(const char *buf, enum AVMediaType codec_type) int i; for (i = 0; rtp_payload_types[i].pt >= 0; i++) - if (!strcmp(buf, rtp_payload_types[i].enc_name) && (codec_type == rtp_payload_types[i].codec_type)) + if (!av_strcasecmp(buf, rtp_payload_types[i].enc_name) && (codec_type == rtp_payload_types[i].codec_type)) return rtp_payload_types[i].codec_id; return AV_CODEC_ID_NONE; diff --git a/ffmpeg/libavformat/rtp.h b/ffmpeg/libavformat/rtp.h index 1732af8..66a4f3a 100644 --- a/ffmpeg/libavformat/rtp.h +++ b/ffmpeg/libavformat/rtp.h @@ -23,6 +23,7 @@ #include "libavformat/avformat.h" #include "libavcodec/avcodec.h" +#include "libavutil/mathematics.h" /** * Return the payload type for a given stream used in the given format context. @@ -109,4 +110,6 @@ enum RTCPType { #define RTP_PT_IS_RTCP(x) (((x) >= RTCP_FIR && (x) <= RTCP_IJ) || \ ((x) >= RTCP_SR && (x) <= RTCP_TOKEN)) +#define NTP_TO_RTP_FORMAT(x) av_rescale((x), INT64_C(1) << 32, 1000000) + #endif /* AVFORMAT_RTP_H */ diff --git a/ffmpeg/libavformat/rtpdec.c b/ffmpeg/libavformat/rtpdec.c index b512b89..ed118b0 100644 --- a/ffmpeg/libavformat/rtpdec.c +++ b/ffmpeg/libavformat/rtpdec.c @@ -32,6 +32,12 @@ #define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */ +static RTPDynamicProtocolHandler gsm_dynamic_handler = { + .enc_name = "GSM", + .codec_type = AVMEDIA_TYPE_AUDIO, + .codec_id = AV_CODEC_ID_GSM, +}; + static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = { .enc_name = "X-MP3-draft-00", .codec_type = AVMEDIA_TYPE_AUDIO, @@ -58,7 +64,7 @@ void ff_register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) rtp_first_dynamic_payload_handler = handler; } -void av_register_rtp_dynamic_payload_handlers(void) +void ff_register_rtp_dynamic_payload_handlers(void) { ff_register_dynamic_payload_handler(&ff_amr_nb_dynamic_handler); ff_register_dynamic_payload_handler(&ff_amr_wb_dynamic_handler); @@ -78,8 +84,8 @@ void av_register_rtp_dynamic_payload_handlers(void) ff_register_dynamic_payload_handler(&ff_mpeg_video_dynamic_handler); ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler); ff_register_dynamic_payload_handler(&ff_mpegts_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler); + ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); ff_register_dynamic_payload_handler(&ff_qcelp_dynamic_handler); ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); ff_register_dynamic_payload_handler(&ff_qt_rtp_aud_handler); @@ -90,6 +96,7 @@ void av_register_rtp_dynamic_payload_handlers(void) ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler); ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler); ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler); + ff_register_dynamic_payload_handler(&gsm_dynamic_handler); ff_register_dynamic_payload_handler(&opus_dynamic_handler); ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler); ff_register_dynamic_payload_handler(&speex_dynamic_handler); diff --git a/ffmpeg/libavformat/rtpdec.h b/ffmpeg/libavformat/rtpdec.h index e469c0f..9321066 100644 --- a/ffmpeg/libavformat/rtpdec.h +++ b/ffmpeg/libavformat/rtpdec.h @@ -33,7 +33,7 @@ typedef struct PayloadContext PayloadContext; typedef struct RTPDynamicProtocolHandler RTPDynamicProtocolHandler; #define RTP_MIN_PACKET_LENGTH 12 -#define RTP_MAX_PACKET_LENGTH 1500 +#define RTP_MAX_PACKET_LENGTH 8192 #define RTP_REORDER_QUEUE_DEFAULT_SIZE 10 @@ -51,10 +51,6 @@ int ff_rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, void ff_rtp_parse_close(RTPDemuxContext *s); int64_t ff_rtp_queued_packet_time(RTPDemuxContext *s); void ff_rtp_reset_packet_queue(RTPDemuxContext *s); -int ff_rtp_get_local_rtp_port(URLContext *h); -int ff_rtp_get_local_rtcp_port(URLContext *h); - -int ff_rtp_set_remote_url(URLContext *h, const char *uri); /** * Send a dummy packet on both port pairs to set up the connection @@ -209,7 +205,7 @@ int ff_parse_fmtp(AVStream *stream, PayloadContext *data, const char *p, PayloadContext *data, char *attr, char *value)); -void av_register_rtp_dynamic_payload_handlers(void); +void ff_register_rtp_dynamic_payload_handlers(void); /** * Close the dynamic buffer and make a packet from it. diff --git a/ffmpeg/libavformat/rtpdec_asf.c b/ffmpeg/libavformat/rtpdec_asf.c index 35603f2..123894f 100644 --- a/ffmpeg/libavformat/rtpdec_asf.c +++ b/ffmpeg/libavformat/rtpdec_asf.c @@ -239,14 +239,11 @@ static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf, int cur_len = start_off + len_off - off; int prev_len = out_len; - void *newmem; out_len += cur_len; if (FFMIN(cur_len, len - off) < 0) return -1; - newmem = av_realloc(asf->buf, out_len); - if (!newmem) - return -1; - asf->buf = newmem; + if ((res = av_reallocp(&asf->buf, out_len)) < 0) + return res; memcpy(asf->buf + prev_len, buf + off, FFMIN(cur_len, len - off)); avio_skip(pb, cur_len); diff --git a/ffmpeg/libavformat/rtpdec_g726.c b/ffmpeg/libavformat/rtpdec_g726.c index ec37f09..7e9ef56 100644 --- a/ffmpeg/libavformat/rtpdec_g726.c +++ b/ffmpeg/libavformat/rtpdec_g726.c @@ -18,11 +18,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "avformat.h" #include "rtpdec_formats.h" #define RTP_G726_HANDLER(bitrate) \ -static int g726_ ## bitrate ##_init(AVFormatContext *s, int st_index, PayloadContext *data) \ +static av_cold int g726_ ## bitrate ##_init(AVFormatContext *s, int st_index, \ + PayloadContext *data) \ { \ AVStream *stream = s->streams[st_index]; \ AVCodecContext *codec = stream->codec; \ diff --git a/ffmpeg/libavformat/rtpdec_h263.c b/ffmpeg/libavformat/rtpdec_h263.c index dd7aa60..ae4cc27 100644 --- a/ffmpeg/libavformat/rtpdec_h263.c +++ b/ffmpeg/libavformat/rtpdec_h263.c @@ -21,9 +21,11 @@ #include "avformat.h" #include "rtpdec_formats.h" +#include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" -static int h263_init(AVFormatContext *ctx, int st_index, PayloadContext *data) +static av_cold int h263_init(AVFormatContext *ctx, int st_index, + PayloadContext *data) { if (st_index < 0) return 0; diff --git a/ffmpeg/libavformat/rtpdec_h263_rfc2190.c b/ffmpeg/libavformat/rtpdec_h263_rfc2190.c index 4b6e996..a227901 100644 --- a/ffmpeg/libavformat/rtpdec_h263_rfc2190.c +++ b/ffmpeg/libavformat/rtpdec_h263_rfc2190.c @@ -8,25 +8,26 @@ * Copyright 2007 Collabora Ltd, Philippe Kalaf * Copyright 2010 Mark Nauwelaerts * - * 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 */ #include "avformat.h" #include "rtpdec_formats.h" +#include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" #include "libavcodec/get_bits.h" @@ -55,7 +56,7 @@ static void h263_free_context(PayloadContext *data) av_free(data); } -static int h263_init(AVFormatContext *ctx, int st_index, PayloadContext *data) +static av_cold int h263_init(AVFormatContext *ctx, int st_index, PayloadContext *data) { if (st_index < 0) return 0; diff --git a/ffmpeg/libavformat/rtpdec_h264.c b/ffmpeg/libavformat/rtpdec_h264.c index d1133b7..1ca78bc 100644 --- a/ffmpeg/libavformat/rtpdec_h264.c +++ b/ffmpeg/libavformat/rtpdec_h264.c @@ -33,6 +33,7 @@ * FU-B packet types) */ +#include "libavutil/attributes.h" #include "libavutil/base64.h" #include "libavutil/avstring.h" #include "libavcodec/get_bits.h" @@ -189,7 +190,8 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, switch (type) { case 0: // undefined, but pass them through case 1: - av_new_packet(pkt, len + sizeof(start_sequence)); + if ((result = av_new_packet(pkt, len + sizeof(start_sequence))) < 0) + return result; memcpy(pkt->data, start_sequence, sizeof(start_sequence)); memcpy(pkt->data + sizeof(start_sequence), buf, len); COUNT_NAL_TYPE(data, nal); @@ -246,7 +248,8 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, if (pass == 0) { /* now we know the total size of the packet (with the * start sequences added) */ - av_new_packet(pkt, total_length); + if ((result = av_new_packet(pkt, total_length)) < 0) + return result; dst = pkt->data; } else { assert(dst - pkt->data == total_length); @@ -291,12 +294,14 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, COUNT_NAL_TYPE(data, nal_type); if (start_bit) { /* copy in the start sequence, and the reconstructed nal */ - av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len); + if ((result = av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len)) < 0) + return result; memcpy(pkt->data, start_sequence, sizeof(start_sequence)); pkt->data[sizeof(start_sequence)] = reconstructed_nal; memcpy(pkt->data + sizeof(start_sequence) + sizeof(nal), buf, len); } else { - av_new_packet(pkt, len); + if ((result = av_new_packet(pkt, len)) < 0) + return result; memcpy(pkt->data, buf, len); } } else { @@ -338,7 +343,8 @@ static void h264_free_context(PayloadContext *data) av_free(data); } -static int h264_init(AVFormatContext *s, int st_index, PayloadContext *data) +static av_cold int h264_init(AVFormatContext *s, int st_index, + PayloadContext *data) { if (st_index < 0) return 0; diff --git a/ffmpeg/libavformat/rtpdec_latm.c b/ffmpeg/libavformat/rtpdec_latm.c index a2ad071..fdeff3a 100644 --- a/ffmpeg/libavformat/rtpdec_latm.c +++ b/ffmpeg/libavformat/rtpdec_latm.c @@ -130,10 +130,7 @@ static int parse_fmtp_config(AVStream *st, char *value) goto end; } av_freep(&st->codec->extradata); - st->codec->extradata_size = (get_bits_left(&gb) + 7)/8; - st->codec->extradata = av_mallocz(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { + if (ff_alloc_extradata(st->codec, (get_bits_left(&gb) + 7)/8)) { ret = AVERROR(ENOMEM); goto end; } diff --git a/ffmpeg/libavformat/rtpdec_mpeg12.c b/ffmpeg/libavformat/rtpdec_mpeg12.c index 82e58a0..d73ff1e 100644 --- a/ffmpeg/libavformat/rtpdec_mpeg12.c +++ b/ffmpeg/libavformat/rtpdec_mpeg12.c @@ -19,10 +19,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "rtpdec_formats.h" +#include "libavutil/attributes.h" #include "libavutil/intreadwrite.h" +#include "rtpdec_formats.h" -static int mpeg_init(AVFormatContext *ctx, int st_index, PayloadContext *data) +static av_cold int mpeg_init(AVFormatContext *ctx, int st_index, PayloadContext *data) { if (st_index < 0) return 0; diff --git a/ffmpeg/libavformat/rtpdec_mpeg4.c b/ffmpeg/libavformat/rtpdec_mpeg4.c index 3f1f244..0ea5594 100644 --- a/ffmpeg/libavformat/rtpdec_mpeg4.c +++ b/ffmpeg/libavformat/rtpdec_mpeg4.c @@ -29,6 +29,7 @@ #include "rtpdec_formats.h" #include "internal.h" +#include "libavutil/attributes.h" #include "libavutil/avstring.h" #include "libavcodec/get_bits.h" @@ -104,10 +105,8 @@ static int parse_fmtp_config(AVCodecContext *codec, char *value) /* decode the hexa encoded parameter */ int len = ff_hex_to_data(NULL, value); av_free(codec->extradata); - codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); - if (!codec->extradata) + if (ff_alloc_extradata(codec, len)) return AVERROR(ENOMEM); - codec->extradata_size = len; ff_hex_to_data(codec->extradata, value); return 0; } @@ -252,7 +251,8 @@ static int parse_sdp_line(AVFormatContext *s, int st_index, return 0; } -static int init_video(AVFormatContext *s, int st_index, PayloadContext *data) +static av_cold int init_video(AVFormatContext *s, int st_index, + PayloadContext *data) { if (st_index < 0) return 0; diff --git a/ffmpeg/libavformat/rtpdec_mpegts.c b/ffmpeg/libavformat/rtpdec_mpegts.c index cbb8eb4..5b851c4 100644 --- a/ffmpeg/libavformat/rtpdec_mpegts.c +++ b/ffmpeg/libavformat/rtpdec_mpegts.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/attributes.h" #include "mpegts.h" #include "rtpdec_formats.h" @@ -43,7 +44,8 @@ static void mpegts_free_context(PayloadContext *data) av_free(data); } -static int mpegts_init(AVFormatContext *ctx, int st_index, PayloadContext *data) +static av_cold int mpegts_init(AVFormatContext *ctx, int st_index, + PayloadContext *data) { data->ts = ff_mpegts_parse_open(ctx); if (!data->ts) diff --git a/ffmpeg/libavformat/rtpdec_qdm2.c b/ffmpeg/libavformat/rtpdec_qdm2.c index 6ce776d..e1dd62f 100644 --- a/ffmpeg/libavformat/rtpdec_qdm2.c +++ b/ffmpeg/libavformat/rtpdec_qdm2.c @@ -29,6 +29,7 @@ #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavcodec/avcodec.h" +#include "internal.h" #include "rtp.h" #include "rtpdec.h" #include "rtpdec_formats.h" @@ -104,9 +105,7 @@ static int qdm2_parse_config(PayloadContext *qdm, AVStream *st, if (item_len < 30) return AVERROR_INVALIDDATA; av_freep(&st->codec->extradata); - st->codec->extradata_size = 26 + item_len; - if (!(st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE))) { - st->codec->extradata_size = 0; + if (ff_alloc_extradata(st->codec, 26 + item_len)) { return AVERROR(ENOMEM); } AV_WB32(st->codec->extradata, 12); diff --git a/ffmpeg/libavformat/rtpdec_qt.c b/ffmpeg/libavformat/rtpdec_qt.c index 8e887a5..ee8a48a 100644 --- a/ffmpeg/libavformat/rtpdec_qt.c +++ b/ffmpeg/libavformat/rtpdec_qt.c @@ -172,17 +172,21 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt, switch (packing_scheme) { case 3: /* one data packet spread over 1 or multiple RTP packets */ if (qt->pkt.size > 0 && qt->timestamp == *timestamp) { - qt->pkt.data = av_realloc(qt->pkt.data, qt->pkt.size + alen + - FF_INPUT_BUFFER_PADDING_SIZE); + int err; + if ((err = av_reallocp(&qt->pkt.data, qt->pkt.size + alen + + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { + qt->pkt.size = 0; + return err; + } } else { av_freep(&qt->pkt.data); av_init_packet(&qt->pkt); - qt->pkt.data = av_malloc(alen + FF_INPUT_BUFFER_PADDING_SIZE); + qt->pkt.data = av_realloc(NULL, alen + FF_INPUT_BUFFER_PADDING_SIZE); + if (!qt->pkt.data) + return AVERROR(ENOMEM); qt->pkt.size = 0; qt->timestamp = *timestamp; } - if (!qt->pkt.data) - return AVERROR(ENOMEM); memcpy(qt->pkt.data + qt->pkt.size, buf + avio_tell(&pb), alen); qt->pkt.size += alen; if (has_marker_bit) { @@ -211,7 +215,7 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt, pkt->stream_index = st->index; if (qt->remaining > 0) { av_freep(&qt->pkt.data); - qt->pkt.data = av_malloc(qt->remaining * qt->bytes_per_frame); + qt->pkt.data = av_realloc(NULL, qt->remaining * qt->bytes_per_frame); if (!qt->pkt.data) { av_free_packet(pkt); return AVERROR(ENOMEM); diff --git a/ffmpeg/libavformat/rtpdec_svq3.c b/ffmpeg/libavformat/rtpdec_svq3.c index 106b785..98e8b58 100644 --- a/ffmpeg/libavformat/rtpdec_svq3.c +++ b/ffmpeg/libavformat/rtpdec_svq3.c @@ -28,6 +28,7 @@ #include <string.h> #include "libavutil/intreadwrite.h" +#include "internal.h" #include "rtp.h" #include "rtpdec.h" #include "rtpdec_formats.h" @@ -60,11 +61,9 @@ static int svq3_parse_packet (AVFormatContext *s, PayloadContext *sv, av_freep(&st->codec->extradata); st->codec->extradata_size = 0; - if (len < 2 || !(st->codec->extradata = - av_malloc(len + 8 + FF_INPUT_BUFFER_PADDING_SIZE))) + if (len < 2 || ff_alloc_extradata(st->codec, len + 8)) return AVERROR_INVALIDDATA; - st->codec->extradata_size = len + 8; memcpy(st->codec->extradata, "SEQH", 4); AV_WB32(st->codec->extradata + 4, len); memcpy(st->codec->extradata + 8, buf, len); diff --git a/ffmpeg/libavformat/rtpdec_xiph.c b/ffmpeg/libavformat/rtpdec_xiph.c index eddb781..887a65e 100644 --- a/ffmpeg/libavformat/rtpdec_xiph.c +++ b/ffmpeg/libavformat/rtpdec_xiph.c @@ -27,11 +27,13 @@ * @author Josh Allmann <joshua.allmann@gmail.com> */ +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/base64.h" #include "libavcodec/bytestream.h" +#include "internal.h" #include "rtpdec.h" #include "rtpdec_formats.h" @@ -69,8 +71,8 @@ static void xiph_free_context(PayloadContext * data) av_free(data); } -static int xiph_vorbis_init(AVFormatContext *ctx, int st_index, - PayloadContext *data) +static av_cold int xiph_vorbis_init(AVFormatContext *ctx, int st_index, + PayloadContext *data) { if (st_index < 0) return 0; @@ -287,11 +289,11 @@ parse_packed_headers(const uint8_t * packed_headers, * -- FF_INPUT_BUFFER_PADDING_SIZE required */ extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE; - ptr = codec->extradata = av_malloc(extradata_alloc); - if (!ptr) { + if (ff_alloc_extradata(codec, extradata_alloc)) { av_log(codec, AV_LOG_ERROR, "Out of memory\n"); return AVERROR(ENOMEM); } + ptr = codec->extradata; *ptr++ = 2; ptr += av_xiphlacing(ptr, length1); ptr += av_xiphlacing(ptr, length2); diff --git a/ffmpeg/libavformat/rtpenc.c b/ffmpeg/libavformat/rtpenc.c index 7adf687..f010008 100644 --- a/ffmpeg/libavformat/rtpenc.c +++ b/ffmpeg/libavformat/rtpenc.c @@ -28,8 +28,6 @@ #include "rtpenc.h" -//#define DEBUG - static const AVOption options[] = { FF_RTP_FLAG_OPTS(RTPMuxContext, flags), { "payload_type", "Specify RTP payload type", offsetof(RTPMuxContext, payload_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 127, AV_OPT_FLAG_ENCODING_PARAM }, @@ -264,7 +262,7 @@ fail: } /* send an rtcp sender report packet */ -static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time) +static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time, int bye) { RTPMuxContext *s = s1->priv_data; uint32_t rtp_ts; @@ -274,12 +272,11 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time) s->last_rtcp_ntp_time = ntp_time; rtp_ts = av_rescale_q(ntp_time - s->first_rtcp_ntp_time, (AVRational){1, 1000000}, s1->streams[0]->time_base) + s->base_timestamp; - avio_w8(s1->pb, (RTP_VERSION << 6)); + avio_w8(s1->pb, RTP_VERSION << 6); avio_w8(s1->pb, RTCP_SR); avio_wb16(s1->pb, 6); /* length in words - 1 */ avio_wb32(s1->pb, s->ssrc); - avio_wb32(s1->pb, ntp_time / 1000000); - avio_wb32(s1->pb, ((ntp_time % 1000000) << 32) / 1000000); + avio_wb64(s1->pb, NTP_TO_RTP_FORMAT(ntp_time)); avio_wb32(s1->pb, rtp_ts); avio_wb32(s1->pb, s->packet_count); avio_wb32(s1->pb, s->octet_count); @@ -299,6 +296,13 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time) avio_w8(s1->pb, 0); } + if (bye) { + avio_w8(s1->pb, (RTP_VERSION << 6) | 1); + avio_w8(s1->pb, RTCP_BYE); + avio_wb16(s1->pb, 1); /* length in words - 1 */ + avio_wb32(s1->pb, s->ssrc); + } + avio_flush(s1->pb); } @@ -311,7 +315,7 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m) av_dlog(s1, "rtp_send_data size=%d\n", len); /* build the RTP header */ - avio_w8(s1->pb, (RTP_VERSION << 6)); + avio_w8(s1->pb, RTP_VERSION << 6); avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7)); avio_wb16(s1->pb, s->seq); avio_wb32(s1->pb, s->timestamp); @@ -497,7 +501,7 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) if ((s->first_packet || ((rtcp_bytes >= RTCP_SR_SIZE) && (ff_ntp_time() - s->last_rtcp_ntp_time > 5000000))) && !(s->flags & FF_RTP_FLAG_SKIP_RTCP)) { - rtcp_send_sr(s1, ff_ntp_time()); + rtcp_send_sr(s1, ff_ntp_time(), 0); s->last_octet_count = s->octet_count; s->first_packet = 0; } @@ -553,6 +557,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) const uint8_t *mb_info = av_packet_get_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, &mb_info_size); + if (!mb_info) { + av_log(s1, AV_LOG_ERROR, "failed to allocate side data\n"); + return AVERROR(ENOMEM); + } ff_rtp_send_h263_rfc2190(s1, pkt->data, size, mb_info, mb_info_size); break; } @@ -593,6 +601,10 @@ static int rtp_write_trailer(AVFormatContext *s1) { RTPMuxContext *s = s1->priv_data; + /* If the caller closes and recreates ->pb, this might actually + * be NULL here even if it was successfully allocated at the start. */ + if (s1->pb && (s->flags & FF_RTP_FLAG_SEND_BYE)) + rtcp_send_sr(s1, ff_ntp_time(), 1); av_freep(&s->buf); return 0; diff --git a/ffmpeg/libavformat/rtpenc.h b/ffmpeg/libavformat/rtpenc.h index 72a5fa4..913d05a 100644 --- a/ffmpeg/libavformat/rtpenc.h +++ b/ffmpeg/libavformat/rtpenc.h @@ -38,11 +38,9 @@ struct RTPMuxContext { int max_payload_size; int num_frames; - /* rtcp sender statistics receive */ + /* rtcp sender statistics */ int64_t last_rtcp_ntp_time; int64_t first_rtcp_ntp_time; - - /* rtcp sender statistics */ unsigned int packet_count; unsigned int octet_count; unsigned int last_octet_count; @@ -70,13 +68,15 @@ typedef struct RTPMuxContext RTPMuxContext; #define FF_RTP_FLAG_RFC2190 2 #define FF_RTP_FLAG_SKIP_RTCP 4 #define FF_RTP_FLAG_H264_MODE0 8 +#define FF_RTP_FLAG_SEND_BYE 16 #define FF_RTP_FLAG_OPTS(ctx, fieldname) \ { "rtpflags", "RTP muxer flags", offsetof(ctx, fieldname), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ { "latm", "Use MP4A-LATM packetization instead of MPEG4-GENERIC for AAC", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_MP4A_LATM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ { "rfc2190", "Use RFC 2190 packetization instead of RFC 4629 for H.263", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_RFC2190}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ { "skip_rtcp", "Don't send RTCP sender reports", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_SKIP_RTCP}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ - { "h264_mode0", "Use mode 0 for H264 in RTP", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_H264_MODE0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" } \ + { "h264_mode0", "Use mode 0 for H264 in RTP", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_H264_MODE0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ + { "send_bye", "Send RTCP BYE packets when finishing", 0, AV_OPT_TYPE_CONST, {.i64 = FF_RTP_FLAG_SEND_BYE}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" } \ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); diff --git a/ffmpeg/libavformat/rtpenc_chain.c b/ffmpeg/libavformat/rtpenc_chain.c index 70d68ce..dea1f70 100644 --- a/ffmpeg/libavformat/rtpenc_chain.c +++ b/ffmpeg/libavformat/rtpenc_chain.c @@ -22,7 +22,6 @@ #include "avformat.h" #include "avio_internal.h" #include "rtpenc_chain.h" -#include "avio_internal.h" #include "rtp.h" #include "libavutil/opt.h" @@ -78,16 +77,19 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s, avcodec_copy_context(rtpctx->streams[0]->codec, st->codec); if (handle) { - ffio_fdopen(&rtpctx->pb, handle); + ret = ffio_fdopen(&rtpctx->pb, handle); + if (ret < 0) + ffurl_close(handle); } else - ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size); - ret = avformat_write_header(rtpctx, &opts); + ret = ffio_open_dyn_packet_buf(&rtpctx->pb, packet_size); + if (!ret) + ret = avformat_write_header(rtpctx, &opts); av_dict_free(&opts); if (ret) { - if (handle) { + if (handle && rtpctx->pb) { avio_close(rtpctx->pb); - } else { + } else if (rtpctx->pb) { uint8_t *ptr; avio_close_dyn_buf(rtpctx->pb, &ptr); av_free(ptr); diff --git a/ffmpeg/libavformat/rtpenc_h263_rfc2190.c b/ffmpeg/libavformat/rtpenc_h263_rfc2190.c index f714d01..0493008 100644 --- a/ffmpeg/libavformat/rtpenc_h263_rfc2190.c +++ b/ffmpeg/libavformat/rtpenc_h263_rfc2190.c @@ -2,20 +2,20 @@ * RTP packetization for H.263 video * Copyright (c) 2012 Martin Storsjo * - * 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 */ diff --git a/ffmpeg/libavformat/rtpenc_latm.c b/ffmpeg/libavformat/rtpenc_latm.c index 7535a0f..4430c44 100644 --- a/ffmpeg/libavformat/rtpenc_latm.c +++ b/ffmpeg/libavformat/rtpenc_latm.c @@ -9,13 +9,13 @@ * 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 */ diff --git a/ffmpeg/libavformat/rtpenc_mpv.c b/ffmpeg/libavformat/rtpenc_mpv.c index 2708dd1..4b45f51 100644 --- a/ffmpeg/libavformat/rtpenc_mpv.c +++ b/ffmpeg/libavformat/rtpenc_mpv.c @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavcodec/mpegvideo.h" +#include "libavcodec/internal.h" #include "avformat.h" #include "rtpenc.h" @@ -56,7 +56,7 @@ void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size) r1 = buf1; while (1) { start_code = -1; - r = avpriv_mpv_find_start_code(r1, end, &start_code); + r = avpriv_find_start_code(r1, end, &start_code); if((start_code & 0xFFFFFF00) == 0x100) { /* New start code found */ if (start_code == 0x100) { diff --git a/ffmpeg/libavformat/rtpproto.c b/ffmpeg/libavformat/rtpproto.c index 62ec4c9..a8cbd97 100644 --- a/ffmpeg/libavformat/rtpproto.c +++ b/ffmpeg/libavformat/rtpproto.c @@ -28,7 +28,8 @@ #include "libavutil/avstring.h" #include "avformat.h" #include "avio_internal.h" -#include "rtpdec.h" +#include "rtp.h" +#include "rtpproto.h" #include "url.h" #include <stdarg.h> @@ -42,7 +43,11 @@ typedef struct RTPContext { URLContext *rtp_hd, *rtcp_hd; - int rtp_fd, rtcp_fd; + int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs; + struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs; + int write_to_source; + struct sockaddr_storage last_rtp_source, last_rtcp_source; + socklen_t last_rtp_source_len, last_rtcp_source_len; } RTPContext; /** @@ -59,22 +64,109 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri) { RTPContext *s = h->priv_data; char hostname[256]; - int port; + int port, rtcp_port; + const char *p; char buf[1024]; char path[1024]; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); + rtcp_port = port + 1; + + p = strchr(uri, '?'); + if (p) { + if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) { + rtcp_port = strtol(buf, NULL, 10); + } + } ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path); ff_udp_set_remote_url(s->rtp_hd, buf); - ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path); + ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, rtcp_port, "%s", path); ff_udp_set_remote_url(s->rtcp_hd, buf); return 0; } +static struct addrinfo* rtp_resolve_host(const char *hostname, int port, + int type, int family, int flags) +{ + struct addrinfo hints = { 0 }, *res = 0; + int error; + char service[16]; + + snprintf(service, sizeof(service), "%d", port); + hints.ai_socktype = type; + hints.ai_family = family; + hints.ai_flags = flags; + if ((error = getaddrinfo(hostname, service, &hints, &res))) { + res = NULL; + av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error)); + } + + return res; +} + +static int compare_addr(const struct sockaddr_storage *a, + const struct sockaddr_storage *b) +{ + if (a->ss_family != b->ss_family) + return 1; + if (a->ss_family == AF_INET) { + return (((const struct sockaddr_in *)a)->sin_addr.s_addr != + ((const struct sockaddr_in *)b)->sin_addr.s_addr); + } + +#if HAVE_STRUCT_SOCKADDR_IN6 + if (a->ss_family == AF_INET6) { + const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr; + const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr; + return memcmp(s6_addr_a, s6_addr_b, 16); + } +#endif + return 1; +} + +static int get_port(const struct sockaddr_storage *ss) +{ + if (ss->ss_family == AF_INET) + return ntohs(((const struct sockaddr_in *)ss)->sin_port); +#if HAVE_STRUCT_SOCKADDR_IN6 + if (ss->ss_family == AF_INET6) + return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port); +#endif + return 0; +} + +static void set_port(struct sockaddr_storage *ss, int port) +{ + if (ss->ss_family == AF_INET) + ((struct sockaddr_in *)ss)->sin_port = htons(port); +#if HAVE_STRUCT_SOCKADDR_IN6 + else if (ss->ss_family == AF_INET6) + ((struct sockaddr_in6 *)ss)->sin6_port = htons(port); +#endif +} + +static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr) +{ + int i; + if (s->nb_ssm_exclude_addrs) { + for (i = 0; i < s->nb_ssm_exclude_addrs; i++) { + if (!compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i])) + return 1; + } + } + if (s->nb_ssm_include_addrs) { + for (i = 0; i < s->nb_ssm_include_addrs; i++) { + if (!compare_addr(source_addr_ptr, s->ssm_include_addrs[i])) + return 0; + } + return 1; + } + return 0; +} /** * add option to url of the form: @@ -99,7 +191,9 @@ static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const static void build_udp_url(char *buf, int buf_size, const char *hostname, int port, int local_port, int ttl, - int max_packet_size, int connect) + int max_packet_size, int connect, + const char *include_sources, + const char *exclude_sources) { ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL); if (local_port >= 0) @@ -111,6 +205,50 @@ static void build_udp_url(char *buf, int buf_size, if (connect) url_add_option(buf, buf_size, "connect=1"); url_add_option(buf, buf_size, "fifo_size=0"); + if (include_sources && include_sources[0]) + url_add_option(buf, buf_size, "sources=%s", include_sources); + if (exclude_sources && exclude_sources[0]) + url_add_option(buf, buf_size, "block=%s", exclude_sources); +} + +static void rtp_parse_addr_list(URLContext *h, char *buf, + struct sockaddr_storage ***address_list_ptr, + int *address_list_size_ptr) +{ + struct addrinfo *ai = NULL; + struct sockaddr_storage *source_addr; + char tmp = '\0', *p = buf, *next; + + /* Resolve all of the IPs */ + + while (p && p[0]) { + next = strchr(p, ','); + + if (next) { + tmp = *next; + *next = '\0'; + } + + ai = rtp_resolve_host(p, 0, SOCK_DGRAM, AF_UNSPEC, 0); + if (ai) { + source_addr = av_mallocz(sizeof(struct sockaddr_storage)); + if (!source_addr) + break; + + memcpy(source_addr, ai->ai_addr, ai->ai_addrlen); + freeaddrinfo(ai); + dynarray_add(address_list_ptr, address_list_size_ptr, source_addr); + } else { + av_log(h, AV_LOG_WARNING, "Unable to resolve %s\n", p); + } + + if (next) { + *next = tmp; + p = next + 1; + } else { + p = NULL; + } + } } /** @@ -121,6 +259,9 @@ static void build_udp_url(char *buf, int buf_size, * 'localrtcpport=n' : set the local rtcp port to n * 'pkt_size=n' : set max packet size * 'connect=0/1' : do a connect() on the UDP socket + * 'sources=ip[,ip]' : list allowed source IP addresses + * 'block=ip[,ip]' : list disallowed source IP addresses + * 'write_to_source=0/1' : send packets to the source address of the latest received packet * deprecated option: * 'localport=n' : set the local port to n * @@ -136,10 +277,11 @@ static int rtp_open(URLContext *h, const char *uri, int flags) int rtp_port, rtcp_port, ttl, connect, local_rtp_port, local_rtcp_port, max_packet_size; - char hostname[256]; + char hostname[256], include_sources[1024] = "", exclude_sources[1024] = ""; char buf[1024]; char path[1024]; const char *p; + int i, max_retry_count = 3; av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, path, sizeof(path), uri); @@ -174,21 +316,48 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { connect = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) { + s->write_to_source = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { + av_strlcpy(include_sources, buf, sizeof(include_sources)); + rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs); + } + if (av_find_info_tag(buf, sizeof(buf), "block", p)) { + av_strlcpy(exclude_sources, buf, sizeof(exclude_sources)); + rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs); + } } - build_udp_url(buf, sizeof(buf), - hostname, rtp_port, local_rtp_port, ttl, max_packet_size, - connect); - if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) - goto fail; - if (local_rtp_port>=0 && local_rtcp_port<0) - local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1; - - build_udp_url(buf, sizeof(buf), - hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, - connect); - if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) - goto fail; + for (i = 0;i < max_retry_count;i++) { + build_udp_url(buf, sizeof(buf), + hostname, rtp_port, local_rtp_port, ttl, max_packet_size, + connect, include_sources, exclude_sources); + if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) + goto fail; + local_rtp_port = ff_udp_get_local_port(s->rtp_hd); + if(local_rtp_port == 65535) { + local_rtp_port = -1; + continue; + } + if (local_rtcp_port<0) { + local_rtcp_port = local_rtp_port + 1; + build_udp_url(buf, sizeof(buf), + hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, + connect, include_sources, exclude_sources); + if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) { + local_rtp_port = local_rtcp_port = -1; + continue; + } + break; + } + build_udp_url(buf, sizeof(buf), + hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, + connect, include_sources, exclude_sources); + if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) + goto fail; + break; + } /* just to ease handle access. XXX: need to suppress direct handle access */ @@ -210,48 +379,41 @@ static int rtp_open(URLContext *h, const char *uri, int flags) static int rtp_read(URLContext *h, uint8_t *buf, int size) { RTPContext *s = h->priv_data; - struct sockaddr_storage from; - socklen_t from_len; - int len, n; + int len, n, i; struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}}; + int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100; + struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source }; + socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len }; for(;;) { if (ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; - /* build fdset to listen to RTP and RTCP packets */ - n = poll(p, 2, 100); + n = poll(p, 2, poll_delay); if (n > 0) { - /* first try RTCP */ - if (p[1].revents & POLLIN) { - from_len = sizeof(from); - len = recvfrom (s->rtcp_fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); + /* first try RTCP, then RTP */ + for (i = 1; i >= 0; i--) { + if (!(p[i].revents & POLLIN)) + continue; + *addr_lens[i] = sizeof(*addrs[i]); + len = recvfrom(p[i].fd, buf, size, 0, + (struct sockaddr *)addrs[i], addr_lens[i]); if (len < 0) { if (ff_neterrno() == AVERROR(EAGAIN) || ff_neterrno() == AVERROR(EINTR)) continue; return AVERROR(EIO); } - break; - } - /* then RTP */ - if (p[0].revents & POLLIN) { - from_len = sizeof(from); - len = recvfrom (s->rtp_fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); - if (len < 0) { - if (ff_neterrno() == AVERROR(EAGAIN) || - ff_neterrno() == AVERROR(EINTR)) - continue; - return AVERROR(EIO); - } - break; + if (rtp_check_source_lists(s, addrs[i])) + continue; + return len; } } else if (n < 0) { if (ff_neterrno() == AVERROR(EINTR)) continue; return AVERROR(EIO); } + if (h->flags & AVIO_FLAG_NONBLOCK) + return AVERROR(EAGAIN); } return len; } @@ -262,6 +424,60 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) int ret; URLContext *hd; + if (size < 2) + return AVERROR(EINVAL); + + if (s->write_to_source) { + int fd; + struct sockaddr_storage *source, temp_source; + socklen_t *source_len, temp_len; + if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) { + av_log(h, AV_LOG_ERROR, + "Unable to send packet to source, no packets received yet\n"); + // Intentionally not returning an error here + return size; + } + + if (RTP_PT_IS_RTCP(buf[1])) { + fd = s->rtcp_fd; + source = &s->last_rtcp_source; + source_len = &s->last_rtcp_source_len; + } else { + fd = s->rtp_fd; + source = &s->last_rtp_source; + source_len = &s->last_rtp_source_len; + } + if (!source->ss_family) { + source = &temp_source; + source_len = &temp_len; + if (RTP_PT_IS_RTCP(buf[1])) { + temp_source = s->last_rtp_source; + temp_len = s->last_rtp_source_len; + set_port(source, get_port(source) + 1); + av_log(h, AV_LOG_INFO, + "Not received any RTCP packets yet, inferring peer port " + "from the RTP port\n"); + } else { + temp_source = s->last_rtcp_source; + temp_len = s->last_rtcp_source_len; + set_port(source, get_port(source) - 1); + av_log(h, AV_LOG_INFO, + "Not received any RTP packets yet, inferring peer port " + "from the RTCP port\n"); + } + } + + if (!(h->flags & AVIO_FLAG_NONBLOCK)) { + ret = ff_network_wait_fd(fd, 1); + if (ret < 0) + return ret; + } + ret = sendto(fd, buf, size, 0, (struct sockaddr *) source, + *source_len); + + return ret < 0 ? ff_neterrno() : ret; + } + if (RTP_PT_IS_RTCP(buf[1])) { /* RTCP payload type */ hd = s->rtcp_hd; @@ -277,6 +493,14 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) static int rtp_close(URLContext *h) { RTPContext *s = h->priv_data; + int i; + + for (i = 0; i < s->nb_ssm_include_addrs; i++) + av_free(s->ssm_include_addrs[i]); + av_freep(&s->ssm_include_addrs); + for (i = 0; i < s->nb_ssm_exclude_addrs; i++) + av_free(s->ssm_exclude_addrs[i]); + av_freep(&s->ssm_exclude_addrs); ffurl_close(s->rtp_hd); ffurl_close(s->rtcp_hd); diff --git a/ffmpeg/libavformat/rtsp.c b/ffmpeg/libavformat/rtsp.c index 317893c..9ee016c 100644 --- a/ffmpeg/libavformat/rtsp.c +++ b/ffmpeg/libavformat/rtsp.c @@ -42,6 +42,7 @@ #include "rtsp.h" #include "rtpdec.h" +#include "rtpproto.h" #include "rdt.h" #include "rtpdec_formats.h" #include "rtpenc_chain.h" @@ -49,8 +50,6 @@ #include "rtpenc.h" #include "mpegts.h" -//#define DEBUG - /* Timeout values for socket poll, in ms, * and read_packet(), in seconds */ #define POLL_TIMEOUT_MS 100 @@ -66,8 +65,7 @@ #define RTSP_FLAG_OPTS(name, longname) \ { name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \ - { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }, \ - { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" } + { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" } #define RTSP_MEDIATYPE_OPTS(name, longname) \ { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_DATA+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \ @@ -87,17 +85,21 @@ const AVOption ff_rtsp_options[] = { { "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" }, { "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" }, RTSP_FLAG_OPTS("rtsp_flags", "RTSP flags"), + { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }, RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"), { "min_port", "Minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC }, { "max_port", "Maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC }, { "timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies flag listen", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, + { "stimeout", "timeout (in micro seconds) of socket i/o operations.", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC }, RTSP_REORDERING_OPTS(), + { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC }, { NULL }, }; static const AVOption sdp_options[] = { RTSP_FLAG_OPTS("sdp_flags", "SDP flags"), { "custom_io", "Use custom IO", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" }, + { "rtcp_to_source", "Send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" }, RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"), RTSP_REORDERING_OPTS(), { NULL }, @@ -289,8 +291,27 @@ typedef struct SDPParseState { struct sockaddr_storage default_ip; int default_ttl; int skip_media; ///< set if an unknown m= line occurs + int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */ + struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */ + int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */ + struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */ } SDPParseState; +static void copy_default_source_addrs(struct RTSPSource **addrs, int count, + struct RTSPSource ***dest, int *dest_count) +{ + RTSPSource *rtsp_src, *rtsp_src2; + int i; + for (i = 0; i < count; i++) { + rtsp_src = addrs[i]; + rtsp_src2 = av_malloc(sizeof(*rtsp_src2)); + if (!rtsp_src2) + continue; + memcpy(rtsp_src2, rtsp_src, sizeof(*rtsp_src)); + dynarray_add(dest, dest_count, rtsp_src2); + } +} + static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, int letter, const char *buf) { @@ -301,6 +322,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, int payload_type, i; AVStream *st; RTSPStream *rtsp_st; + RTSPSource *rtsp_src; struct sockaddr_storage sdp_ip; int ttl; @@ -369,6 +391,15 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, rtsp_st->sdp_ip = s1->default_ip; rtsp_st->sdp_ttl = s1->default_ttl; + copy_default_source_addrs(s1->default_include_source_addrs, + s1->nb_default_include_source_addrs, + &rtsp_st->include_source_addrs, + &rtsp_st->nb_include_source_addrs); + copy_default_source_addrs(s1->default_exclude_source_addrs, + s1->nb_default_exclude_source_addrs, + &rtsp_st->exclude_source_addrs, + &rtsp_st->nb_exclude_source_addrs); + get_word(buf1, sizeof(buf1), &p); /* port */ rtsp_st->sdp_port = atoi(buf1); @@ -498,6 +529,43 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, p += strspn(p, SPACE_CHARS); if (av_strstart(p, "inline:", &p)) get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p); + } else if (av_strstart(p, "source-filter:", &p)) { + int exclude = 0; + get_word(buf1, sizeof(buf1), &p); + if (strcmp(buf1, "incl") && strcmp(buf1, "excl")) + return; + exclude = !strcmp(buf1, "excl"); + + get_word(buf1, sizeof(buf1), &p); + if (strcmp(buf1, "IN") != 0) + return; + get_word(buf1, sizeof(buf1), &p); + if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*")) + return; + // not checking that the destination address actually matches or is wildcard + get_word(buf1, sizeof(buf1), &p); + + while (*p != '\0') { + rtsp_src = av_mallocz(sizeof(*rtsp_src)); + if (!rtsp_src) + return; + get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p); + if (exclude) { + if (s->nb_streams == 0) { + dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src); + } else { + rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; + dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src); + } + } else { + if (s->nb_streams == 0) { + dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src); + } else { + rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; + dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src); + } + } + } } else { if (rt->server_type == RTSP_SERVER_WMS) ff_wms_parse_sdp_a_line(s, p); @@ -522,7 +590,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content) { RTSPState *rt = s->priv_data; const char *p; - int letter; + int letter, i; /* Some SDP lines, particularly for Realmedia or ASF RTSP streams, * contain long SDP lines containing complete ASF Headers (several * kB) or arrays of MDPR (RM stream descriptor) headers plus @@ -559,13 +627,21 @@ int ff_sdp_parse(AVFormatContext *s, const char *content) if (*p == '\n') p++; } + + for (i = 0; i < s1->nb_default_include_source_addrs; i++) + av_free(s1->default_include_source_addrs[i]); + av_freep(&s1->default_include_source_addrs); + for (i = 0; i < s1->nb_default_exclude_source_addrs; i++) + av_free(s1->default_exclude_source_addrs[i]); + av_freep(&s1->default_exclude_source_addrs); + rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1)); if (!rt->p) return AVERROR(ENOMEM); return 0; } #endif /* CONFIG_RTPDEC */ -void ff_rtsp_undo_setup(AVFormatContext *s) +void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets) { RTSPState *rt = s->priv_data; int i; @@ -580,6 +656,8 @@ void ff_rtsp_undo_setup(AVFormatContext *s) av_write_trailer(rtpctx); if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) { uint8_t *ptr; + if (CONFIG_RTSP_MUXER && rtpctx->pb && send_packets) + ff_rtsp_tcp_write_packet(s, rtsp_st); avio_close_dyn_buf(rtpctx->pb, &ptr); av_free(ptr); } else { @@ -602,16 +680,23 @@ void ff_rtsp_undo_setup(AVFormatContext *s) void ff_rtsp_close_streams(AVFormatContext *s) { RTSPState *rt = s->priv_data; - int i; + int i, j; RTSPStream *rtsp_st; - ff_rtsp_undo_setup(s); + ff_rtsp_undo_setup(s, 0); for (i = 0; i < rt->nb_rtsp_streams; i++) { rtsp_st = rt->rtsp_streams[i]; if (rtsp_st) { if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) rtsp_st->dynamic_handler->free( rtsp_st->dynamic_protocol_context); + for (j = 0; j < rtsp_st->nb_include_source_addrs; j++) + av_free(rtsp_st->include_source_addrs[j]); + av_freep(&rtsp_st->include_source_addrs); + for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++) + av_free(rtsp_st->exclude_source_addrs[j]); + av_freep(&rtsp_st->exclude_source_addrs); + av_free(rtsp_st); } } @@ -644,8 +729,8 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) s->ctx_flags |= AVFMTCTX_NOHEADER; if (s->oformat && CONFIG_RTSP_MUXER) { - int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, s, st, - rtsp_st->rtp_handle, + int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, + s, st, rtsp_st->rtp_handle, RTSP_TCP_MAX_PACKET_SIZE, rtsp_st->stream_index); /* Ownership of rtp_handle is passed to the rtp mux context */ @@ -1119,11 +1204,11 @@ start: * * @return zero if success, nonzero otherwise */ -static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s, - const char *method, const char *url, - const char *headers, - const unsigned char *send_content, - int send_content_length) +static int rtsp_send_cmd_with_content_async(AVFormatContext *s, + const char *method, const char *url, + const char *headers, + const unsigned char *send_content, + int send_content_length) { RTSPState *rt = s->priv_data; char buf[4096], *out_buf; @@ -1136,6 +1221,7 @@ static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s, if (headers) av_strlcat(buf, headers, sizeof(buf)); av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq); + av_strlcatf(buf, sizeof(buf), "User-Agent: %s\r\n", rt->user_agent); if (rt->session_id[0] != '\0' && (!headers || !strstr(headers, "\nIf-Match:"))) { av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id); @@ -1176,7 +1262,7 @@ static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s, int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method, const char *url, const char *headers) { - return ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0); + return rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0); } int ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url, @@ -1201,9 +1287,9 @@ int ff_rtsp_send_cmd_with_content(AVFormatContext *s, retry: cur_auth_type = rt->auth_state.auth_type; - if ((ret = ff_rtsp_send_cmd_with_content_async(s, method, url, header, - send_content, - send_content_length))) + if ((ret = rtsp_send_cmd_with_content_async(s, method, url, header, + send_content, + send_content_length))) return ret; if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0) @@ -1398,18 +1484,15 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, case RTSP_LOWER_TRANSPORT_UDP: { char url[1024], options[30] = ""; + const char *peer = host; if (rt->rtsp_flags & RTSP_FLAG_FILTER_SRC) av_strlcpy(options, "?connect=1", sizeof(options)); /* Use source address if specified */ - if (reply->transports[0].source[0]) { - ff_url_join(url, sizeof(url), "rtp", NULL, - reply->transports[0].source, - reply->transports[0].server_port_min, "%s", options); - } else { - ff_url_join(url, sizeof(url), "rtp", NULL, host, - reply->transports[0].server_port_min, "%s", options); - } + if (reply->transports[0].source[0]) + peer = reply->transports[0].source; + ff_url_join(url, sizeof(url), "rtp", NULL, peer, + reply->transports[0].server_port_min, "%s", options); if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) && ff_rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { err = AVERROR_INVALIDDATA; @@ -1466,7 +1549,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, return 0; fail: - ff_rtsp_undo_setup(s); + ff_rtsp_undo_setup(s, 0); return err; } @@ -1618,7 +1701,8 @@ redirect: } } else { /* open the tcp connection */ - ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL); + ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, + "?timeout=%d", rt->stimeout); if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, NULL) < 0) { err = AVERROR(EIO); @@ -2028,7 +2112,7 @@ static int sdp_probe(AVProbeData *p1) while (p < p_end && *p != '\0') { if (p + sizeof("c=IN IP") - 1 < p_end && av_strstart(p, "c=IN IP", NULL)) - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; while (p < p_end - 1 && *p != '\n') p++; if (++p >= p_end) @@ -2039,6 +2123,17 @@ static int sdp_probe(AVProbeData *p1) return 0; } +static void append_source_addrs(char *buf, int size, const char *name, + int count, struct RTSPSource **addrs) +{ + int i; + if (!count) + return; + av_strlcatf(buf, size, "&%s=%s", name, addrs[0]->addr); + for (i = 1; i < count; i++) + av_strlcatf(buf, size, ",%s", addrs[i]->addr); +} + static int sdp_read_header(AVFormatContext *s) { RTSPState *rt = s->priv_data; @@ -2079,9 +2174,17 @@ static int sdp_read_header(AVFormatContext *s) namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); ff_url_join(url, sizeof(url), "rtp", NULL, namebuf, rtsp_st->sdp_port, - "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port, - rtsp_st->sdp_ttl, - rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0); + "?localport=%d&ttl=%d&connect=%d&write_to_source=%d", + rtsp_st->sdp_port, rtsp_st->sdp_ttl, + rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0, + rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0); + + append_source_addrs(url, sizeof(url), "sources", + rtsp_st->nb_include_source_addrs, + rtsp_st->include_source_addrs); + append_source_addrs(url, sizeof(url), "block", + rtsp_st->nb_exclude_source_addrs, + rtsp_st->exclude_source_addrs); if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, NULL) < 0) { err = AVERROR_INVALIDDATA; @@ -2134,7 +2237,7 @@ static int rtp_probe(AVProbeData *p) static int rtp_read_header(AVFormatContext *s) { - uint8_t recvbuf[1500]; + uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; char host[500], sdp[500]; int ret, port; URLContext* in = NULL; diff --git a/ffmpeg/libavformat/rtsp.h b/ffmpeg/libavformat/rtsp.h index 321cd7a..76c7f18 100644 --- a/ffmpeg/libavformat/rtsp.h +++ b/ffmpeg/libavformat/rtsp.h @@ -391,9 +391,19 @@ typedef struct RTSPState { int initial_timeout; /** + * timeout of socket i/o operations. + */ + int stimeout; + + /** * Size of RTP packet reordering queue. */ int reordering_queue_size; + + /** + * User-Agent string + */ + char *user_agent; } RTSPState; #define RTSP_FLAG_FILTER_SRC 0x1 /**< Filter incoming UDP packets - @@ -401,6 +411,12 @@ typedef struct RTSPState { source address and port. */ #define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */ #define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */ +#define RTSP_FLAG_RTCP_TO_SOURCE 0x8 /**< Send RTCP packets to the source + address of received packets. */ + +typedef struct RTSPSource { + char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */ +} RTSPSource; /** * Describe a single stream, as identified by a single m= line block in the @@ -425,6 +441,10 @@ typedef struct RTSPStream { //@{ int sdp_port; /**< port (from SDP content) */ struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */ + int nb_include_source_addrs; /**< Number of source-specific multicast include source IP addresses (from SDP content) */ + struct RTSPSource **include_source_addrs; /**< Source-specific multicast include source IP addresses (from SDP content) */ + int nb_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP addresses (from SDP content) */ + struct RTSPSource **exclude_source_addrs; /**< Source-specific multicast exclude source IP addresses (from SDP content) */ int sdp_ttl; /**< IP Time-To-Live (from SDP content) */ int sdp_payload_type; /**< payload type */ //@} @@ -578,6 +598,11 @@ int ff_rtsp_tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, uint8_t *buf, int buf_size); /** + * Send buffered packets over TCP. + */ +int ff_rtsp_tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st); + +/** * Receive one packet from the RTSPStreams set up in the AVFormatContext * (which should contain a RTSPState struct as priv_data). */ @@ -595,7 +620,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, * Undo the effect of ff_rtsp_make_setup_request, close the * transport_priv and rtp_handle fields. */ -void ff_rtsp_undo_setup(AVFormatContext *s); +void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets); /** * Open RTSP transport context. diff --git a/ffmpeg/libavformat/rtspdec.c b/ffmpeg/libavformat/rtspdec.c index da571a8..74a7bf6 100644 --- a/ffmpeg/libavformat/rtspdec.c +++ b/ffmpeg/libavformat/rtspdec.c @@ -29,6 +29,7 @@ #include "internal.h" #include "network.h" #include "os_support.h" +#include "rtpproto.h" #include "rtsp.h" #include "rdt.h" #include "url.h" @@ -768,7 +769,7 @@ static int resetup_tcp(AVFormatContext *s) av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, s->filename); - ff_rtsp_undo_setup(s); + ff_rtsp_undo_setup(s, 0); return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP, rt->real_challenge); } @@ -876,7 +877,7 @@ retry: rt->get_parameter_supported)) { ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL); } else { - ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL); + ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL); } /* The stale flag should be reset when creating the auth response in * ff_rtsp_send_cmd_async, but reset it here just in case we never diff --git a/ffmpeg/libavformat/rtspenc.c b/ffmpeg/libavformat/rtspenc.c index bad6fbd..d76ae87 100644 --- a/ffmpeg/libavformat/rtspenc.c +++ b/ffmpeg/libavformat/rtspenc.c @@ -136,7 +136,7 @@ static int rtsp_write_header(AVFormatContext *s) return 0; } -static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) +int ff_rtsp_tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) { RTSPState *rt = s->priv_data; AVFormatContext *rtpctx = rtsp_st->transport_priv; @@ -145,6 +145,7 @@ static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) uint8_t *interleave_header, *interleaved_packet; size = avio_close_dyn_buf(rtpctx->pb, &buf); + rtpctx->pb = NULL; ptr = buf; while (size > 4) { uint32_t packet_len = AV_RB32(ptr); @@ -171,8 +172,7 @@ static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) size -= packet_len; } av_free(buf); - ffio_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); - return 0; + return ffio_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); } static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) @@ -217,7 +217,7 @@ static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) * packets, so we need to send them out on the TCP connection separately. */ if (!ret && rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) - ret = tcp_write_packet(s, rtsp_st); + ret = ff_rtsp_tcp_write_packet(s, rtsp_st); return ret; } @@ -225,6 +225,11 @@ static int rtsp_write_close(AVFormatContext *s) { RTSPState *rt = s->priv_data; + // If we want to send RTCP_BYE packets, these are sent by av_write_trailer. + // Thus call this on all streams before doing the teardown. This is + // done within ff_rtsp_undo_setup. + ff_rtsp_undo_setup(s, 1); + ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL); ff_rtsp_close_streams(s); diff --git a/ffmpeg/libavformat/sapdec.c b/ffmpeg/libavformat/sapdec.c index ed3e857..fe7bd82 100644 --- a/ffmpeg/libavformat/sapdec.c +++ b/ffmpeg/libavformat/sapdec.c @@ -27,6 +27,7 @@ #include "internal.h" #include "avio_internal.h" #include "url.h" +#include "rtpdec.h" #if HAVE_POLL_H #include <poll.h> #endif @@ -63,7 +64,7 @@ static int sap_read_header(AVFormatContext *s) { struct SAPState *sap = s->priv_data; char host[1024], path[1024], url[1024]; - uint8_t recvbuf[1500]; + uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; int port; int ret, i; AVInputFormat* infmt; @@ -186,7 +187,7 @@ static int sap_fetch_packet(AVFormatContext *s, AVPacket *pkt) int fd = ffurl_get_file_handle(sap->ann_fd); int n, ret; struct pollfd p = {fd, POLLIN, 0}; - uint8_t recvbuf[1500]; + uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; if (sap->eof) return AVERROR_EOF; diff --git a/ffmpeg/libavformat/sapenc.c b/ffmpeg/libavformat/sapenc.c index 6b1cd18..9fc78a8 100644 --- a/ffmpeg/libavformat/sapenc.c +++ b/ffmpeg/libavformat/sapenc.c @@ -26,7 +26,6 @@ #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "libavutil/time.h" -#include "libavutil/dict.h" #include "internal.h" #include "network.h" #include "os_support.h" diff --git a/ffmpeg/libavformat/sbgdec.c b/ffmpeg/libavformat/sbgdec.c index 30c3b49..36cd8a3 100644 --- a/ffmpeg/libavformat/sbgdec.c +++ b/ffmpeg/libavformat/sbgdec.c @@ -1333,11 +1333,9 @@ static int encode_intervals(struct sbg_script *s, AVCodecContext *avc, if (edata_size < 0) return AVERROR(ENOMEM); } - edata = av_malloc(edata_size); - if (!edata) + if (ff_alloc_extradata(avc, edata_size)) return AVERROR(ENOMEM); - avc->extradata = edata; - avc->extradata_size = edata_size; + edata = avc->extradata; #define ADD_EDATA32(v) do { AV_WL32(edata, (v)); edata += 4; } while(0) #define ADD_EDATA64(v) do { AV_WL64(edata, (v)); edata += 8; } while(0) diff --git a/ffmpeg/libavformat/sctp.c b/ffmpeg/libavformat/sctp.c index 2fd5400..f88cd27 100644 --- a/ffmpeg/libavformat/sctp.c +++ b/ffmpeg/libavformat/sctp.c @@ -2,20 +2,20 @@ * SCTP protocol * Copyright (c) 2012 Luca Barbato * - * 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 */ @@ -56,10 +56,10 @@ /* * The sctp_recvmsg and sctp_sendmsg functions are part of the user - * library that offers support - * for the SCTP kernel Implementation. The main purpose of this - * code is to provide the SCTP Socket API mappings for user - * application to interface with the SCTP in kernel. + * library that offers support for the SCTP kernel Implementation. + * To avoid build-time clashes the functions sport an ff_-prefix here. + * The main purpose of this code is to provide the SCTP Socket API + * mappings for user applications to interface with SCTP in the kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in <draft-ietf-tsvwg-sctpsocket-10.txt> @@ -198,7 +198,7 @@ static int sctp_open(URLContext *h, const char *uri, int flags) cur_ai = ai; - fd = socket(cur_ai->ai_family, SOCK_STREAM, IPPROTO_SCTP); + fd = ff_socket(cur_ai->ai_family, SOCK_STREAM, IPPROTO_SCTP); if (fd < 0) goto fail; diff --git a/ffmpeg/libavformat/sdp.c b/ffmpeg/libavformat/sdp.c index 0124218..55ea0d9 100644 --- a/ffmpeg/libavformat/sdp.c +++ b/ffmpeg/libavformat/sdp.c @@ -513,13 +513,6 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, break; case AV_CODEC_ID_THEORA: { const char *pix_fmt; - if (c->extradata_size) - config = xiph_extradata2config(c); - else - av_log(c, AV_LOG_ERROR, "Theora configuation info missing\n"); - if (!config) - return NULL; - switch (c->pix_fmt) { case AV_PIX_FMT_YUV420P: pix_fmt = "YCbCr-4:2:0"; @@ -535,6 +528,13 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, return NULL; } + if (c->extradata_size) + config = xiph_extradata2config(c); + else + av_log(c, AV_LOG_ERROR, "Theora configuation info missing\n"); + if (!config) + return NULL; + av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n" "a=fmtp:%d delivery-method=inline; " "width=%d; height=%d; sampling=%s; " diff --git a/ffmpeg/libavformat/seek-test.c b/ffmpeg/libavformat/seek-test.c index 34ac4de..8b0611d 100644 --- a/ffmpeg/libavformat/seek-test.c +++ b/ffmpeg/libavformat/seek-test.c @@ -64,6 +64,7 @@ int main(int argc, char **argv) int64_t seekfirst = AV_NOPTS_VALUE; int firstback=0; int frame_count = 1; + int duration = 4; for(i=2; i<argc; i+=2){ if (!strcmp(argv[i], "-seekforw")){ @@ -73,6 +74,8 @@ int main(int argc, char **argv) firstback = 1; } else if(!strcmp(argv[i], "-frames")){ frame_count = atoi(argv[i+1]); + } else if(!strcmp(argv[i], "-duration")){ + duration = atoi(argv[i+1]); } else { argc = 1; } @@ -133,7 +136,7 @@ int main(int argc, char **argv) if(i>25) break; stream_id= (i>>1)%(ic->nb_streams+1) - 1; - timestamp= (i*19362894167LL) % (4*AV_TIME_BASE) - AV_TIME_BASE; + timestamp= (i*19362894167LL) % (duration*AV_TIME_BASE) - AV_TIME_BASE; if(stream_id>=0){ st= ic->streams[stream_id]; timestamp= av_rescale_q(timestamp, AV_TIME_BASE_Q, st->time_base); diff --git a/ffmpeg/libavformat/seek.c b/ffmpeg/libavformat/seek.c index 0ae99eb..bb5ca87 100644 --- a/ffmpeg/libavformat/seek.c +++ b/ffmpeg/libavformat/seek.c @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "seek.h" #include "libavutil/mathematics.h" #include "libavutil/mem.h" @@ -428,13 +430,11 @@ AVParserState *ff_store_parser_state(AVFormatContext *s) ss->parser = st->parser; ss->last_IP_pts = st->last_IP_pts; ss->cur_dts = st->cur_dts; - ss->reference_dts = st->reference_dts; ss->probe_packets = st->probe_packets; st->parser = NULL; st->last_IP_pts = AV_NOPTS_VALUE; st->cur_dts = AV_NOPTS_VALUE; - st->reference_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; } @@ -467,7 +467,6 @@ void ff_restore_parser_state(AVFormatContext *s, AVParserState *state) st->parser = ss->parser; st->last_IP_pts = ss->last_IP_pts; st->cur_dts = ss->cur_dts; - st->reference_dts = ss->reference_dts; st->probe_packets = ss->probe_packets; } diff --git a/ffmpeg/libavformat/seek.h b/ffmpeg/libavformat/seek.h index b27cb42..3fa7ae3 100644 --- a/ffmpeg/libavformat/seek.h +++ b/ffmpeg/libavformat/seek.h @@ -33,7 +33,6 @@ typedef struct AVParserStreamState { AVCodecParserContext *parser; int64_t last_IP_pts; int64_t cur_dts; - int64_t reference_dts; int probe_packets; } AVParserStreamState; diff --git a/ffmpeg/libavformat/segafilm.c b/ffmpeg/libavformat/segafilm.c index a33ad85..8a0e8bc 100644 --- a/ffmpeg/libavformat/segafilm.c +++ b/ffmpeg/libavformat/segafilm.c @@ -62,10 +62,6 @@ typedef struct FilmDemuxContext { unsigned int base_clock; unsigned int version; - - /* buffer used for interleaving stereo PCM data */ - unsigned char *stereo_buffer; - int stereo_buffer_size; } FilmDemuxContext; static int film_probe(AVProbeData *p) @@ -73,6 +69,9 @@ static int film_probe(AVProbeData *p) if (AV_RB32(&p->buf[0]) != FILM_TAG) return 0; + if (AV_RB32(&p->buf[16]) != FDSC_TAG) + return 0; + return AVPROBE_SCORE_MAX; } @@ -87,8 +86,6 @@ static int film_read_header(AVFormatContext *s) unsigned int audio_frame_counter; film->sample_table = NULL; - film->stereo_buffer = NULL; - film->stereo_buffer_size = 0; /* load the main FILM header */ if (avio_read(pb, scratch, 16) != 16) @@ -117,9 +114,9 @@ static int film_read_header(AVFormatContext *s) film->audio_type = AV_CODEC_ID_ADPCM_ADX; else if (film->audio_channels > 0) { if (film->audio_bits == 8) - film->audio_type = AV_CODEC_ID_PCM_S8; + film->audio_type = AV_CODEC_ID_PCM_S8_PLANAR; else if (film->audio_bits == 16) - film->audio_type = AV_CODEC_ID_PCM_S16BE; + film->audio_type = AV_CODEC_ID_PCM_S16BE_PLANAR; else film->audio_type = AV_CODEC_ID_NONE; } else @@ -209,12 +206,14 @@ static int film_read_header(AVFormatContext *s) for (i = 0; i < film->sample_count; i++) { /* load the next sample record and transfer it to an internal struct */ if (avio_read(pb, scratch, 16) != 16) { - av_free(film->sample_table); + av_freep(&film->sample_table); return AVERROR(EIO); } film->sample_table[i].sample_offset = data_offset + AV_RB32(&scratch[0]); film->sample_table[i].sample_size = AV_RB32(&scratch[4]); + if (film->sample_table[i].sample_size > INT_MAX / 4) + return AVERROR_INVALIDDATA; if (AV_RB32(&scratch[8]) == 0xFFFFFFFF) { film->sample_table[i].stream = film->audio_stream_index; film->sample_table[i].pts = audio_frame_counter; @@ -244,8 +243,6 @@ static int film_read_packet(AVFormatContext *s, AVIOContext *pb = s->pb; film_sample *sample; int ret = 0; - int i; - int left, right; if (film->current_sample >= film->sample_count) return AVERROR_EOF; @@ -262,45 +259,6 @@ static int film_read_packet(AVFormatContext *s, if (av_new_packet(pkt, sample->sample_size)) return AVERROR(ENOMEM); avio_read(pb, pkt->data, sample->sample_size); - } else if ((sample->stream == film->audio_stream_index) && - (film->audio_channels == 2) && - (film->audio_type != AV_CODEC_ID_ADPCM_ADX)) { - /* stereo PCM needs to be interleaved */ - - if (ffio_limit(pb, sample->sample_size) != sample->sample_size) - return AVERROR(EIO); - if (av_new_packet(pkt, sample->sample_size)) - return AVERROR(ENOMEM); - - /* make sure the interleave buffer is large enough */ - if (sample->sample_size > film->stereo_buffer_size) { - av_free(film->stereo_buffer); - film->stereo_buffer_size = sample->sample_size; - film->stereo_buffer = av_malloc(film->stereo_buffer_size); - if (!film->stereo_buffer) { - film->stereo_buffer_size = 0; - return AVERROR(ENOMEM); - } - } - - pkt->pos= avio_tell(pb); - ret = avio_read(pb, film->stereo_buffer, sample->sample_size); - if (ret != sample->sample_size) - ret = AVERROR(EIO); - - left = 0; - right = sample->sample_size / 2; - for (i = 0; i + 1 + 2*(film->audio_bits != 8) < sample->sample_size; ) { - if (film->audio_bits == 8) { - pkt->data[i++] = film->stereo_buffer[left++]; - pkt->data[i++] = film->stereo_buffer[right++]; - } else { - pkt->data[i++] = film->stereo_buffer[left++]; - pkt->data[i++] = film->stereo_buffer[left++]; - pkt->data[i++] = film->stereo_buffer[right++]; - pkt->data[i++] = film->stereo_buffer[right++]; - } - } } else { ret= av_get_packet(pb, pkt, sample->sample_size); if (ret != sample->sample_size) @@ -319,8 +277,7 @@ static int film_read_close(AVFormatContext *s) { FilmDemuxContext *film = s->priv_data; - av_free(film->sample_table); - av_free(film->stereo_buffer); + av_freep(&film->sample_table); return 0; } diff --git a/ffmpeg/libavformat/segment.c b/ffmpeg/libavformat/segment.c index dbcfe89..91c1432 100644 --- a/ffmpeg/libavformat/segment.c +++ b/ffmpeg/libavformat/segment.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2011, Luca Barbato * - * 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 */ @@ -43,7 +43,8 @@ typedef struct SegmentListEntry { int index; double start_time, end_time; int64_t start_pts; - char filename[1024]; + int64_t offset_pts; + char *filename; struct SegmentListEntry *next; } SegmentListEntry; @@ -71,6 +72,7 @@ typedef struct { char *list; ///< filename for the segment list file int list_flags; ///< flags affecting list generation int list_size; ///< number of entries for the segment list file + char *list_entry_prefix; ///< prefix to add to list entry filenames ListType list_type; ///< set the list type AVIOContext *list_pb; ///< list file put-byte context char *time_str; ///< segment duration specification string @@ -85,12 +87,12 @@ typedef struct { int nb_frames; ///< number of elments in the frames array int frame_count; - char *time_delta_str; ///< approximation value duration used for the segment times int64_t time_delta; int individual_header_trailer; /**< Set by a private option. */ int write_header_trailer; /**< Set by a private option. */ int reset_timestamps; ///< reset timestamps at the begin of each segment + int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds char *reference_stream_specifier; ///< reference stream specifier int reference_stream_index; @@ -157,6 +159,7 @@ static int set_segment_filename(AVFormatContext *s) { SegmentContext *seg = s->priv_data; AVFormatContext *oc = seg->avf; + size_t size; if (seg->segment_idx_wrap) seg->segment_idx %= seg->segment_idx_wrap; @@ -165,7 +168,19 @@ static int set_segment_filename(AVFormatContext *s) av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename); return AVERROR(EINVAL); } - av_strlcpy(seg->cur_entry.filename, oc->filename, sizeof(seg->cur_entry.filename)); + + /* copy modified name in list entry */ + size = strlen(av_basename(oc->filename)) + 1; + if (seg->list_entry_prefix) + size += strlen(seg->list_entry_prefix); + + seg->cur_entry.filename = av_mallocz(size); + if (!seg->cur_entry.filename) + return AVERROR(ENOMEM); + snprintf(seg->cur_entry.filename, size, "%s%s", + seg->list_entry_prefix ? seg->list_entry_prefix : "", + av_basename(oc->filename)); + return 0; } @@ -186,11 +201,12 @@ static int segment_start(AVFormatContext *s, int write_header) seg->segment_idx++; if ((err = set_segment_filename(s)) < 0) return err; - seg->segment_count++; if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) + &s->interrupt_callback, NULL)) < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); return err; + } if (oc->oformat->priv_class && oc->priv_data) av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */ @@ -211,8 +227,10 @@ static int segment_list_open(AVFormatContext *s) ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); - if (ret < 0) + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list); return ret; + } if (seg->list_type == LIST_TYPE_M3U8 && seg->segment_list_entries) { SegmentListEntry *entry; @@ -303,6 +321,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) if (seg->list_size && seg->segment_count > seg->list_size) { entry = seg->segment_list_entries; seg->segment_list_entries = seg->segment_list_entries->next; + av_free(entry->filename); av_freep(&entry); } @@ -319,6 +338,10 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) avio_flush(seg->list_pb); } + av_log(s, AV_LOG_VERBOSE, "segment:'%s' count:%d ended\n", + seg->avf->filename, seg->segment_count); + seg->segment_count++; + end: avio_close(oc->pb); @@ -554,15 +577,6 @@ static int seg_write_header(AVFormatContext *s) } } - if (seg->time_delta_str) { - if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) { - av_log(s, AV_LOG_ERROR, - "Invalid time duration specification '%s' for delta option\n", - seg->time_delta_str); - return ret; - } - } - if (seg->list) { if (seg->list_type == LIST_TYPE_UNDEFINED) { if (av_match_ext(seg->list, "csv" )) seg->list_type = LIST_TYPE_CSV; @@ -602,12 +616,13 @@ static int seg_write_header(AVFormatContext *s) if ((ret = set_segment_filename(s)) < 0) goto fail; - seg->segment_count++; if (seg->write_header_trailer) { if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE, - &s->interrupt_callback, NULL)) < 0) + &s->interrupt_callback, NULL)) < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); goto fail; + } } else { if ((ret = open_null_ctx(&oc->pb)) < 0) goto fail; @@ -644,18 +659,18 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) SegmentContext *seg = s->priv_data; AVFormatContext *oc = seg->avf; AVStream *st = s->streams[pkt->stream_index]; - int64_t end_pts = INT64_MAX; + int64_t end_pts = INT64_MAX, offset; int start_frame = INT_MAX; int ret; if (seg->times) { - end_pts = seg->segment_count <= seg->nb_times ? - seg->times[seg->segment_count-1] : INT64_MAX; + end_pts = seg->segment_count < seg->nb_times ? + seg->times[seg->segment_count] : INT64_MAX; } else if (seg->frames) { start_frame = seg->segment_count <= seg->nb_frames ? - seg->frames[seg->segment_count-1] : INT_MAX; + seg->frames[seg->segment_count] : INT_MAX; } else { - end_pts = seg->time * seg->segment_count; + end_pts = seg->time * (seg->segment_count+1); } av_dlog(s, "packet stream:%d pts:%s pts_time:%s is_key:%d frame:%d\n", @@ -669,12 +684,10 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) (pkt->pts != AV_NOPTS_VALUE && av_compare_ts(pkt->pts, st->time_base, end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) { - ret = segment_end(s, seg->individual_header_trailer, 0); - - if (!ret) - ret = segment_start(s, seg->individual_header_trailer); + if ((ret = segment_end(s, seg->individual_header_trailer, 0)) < 0) + goto fail; - if (ret) + if ((ret = segment_start(s, seg->individual_header_trailer)) < 0) goto fail; oc = seg->avf; @@ -688,29 +701,29 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) } if (seg->is_first_pkt) { - av_log(s, AV_LOG_DEBUG, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", + av_log(s, AV_LOG_VERBOSE, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", seg->avf->filename, pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count); seg->is_first_pkt = 0; } - if (seg->reset_timestamps) { - av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s", - pkt->stream_index, - av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q), - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); + av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s", + pkt->stream_index, + av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q), + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - /* compute new timestamps */ - if (pkt->pts != AV_NOPTS_VALUE) - pkt->pts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base); - if (pkt->dts != AV_NOPTS_VALUE) - pkt->dts -= av_rescale_q(seg->cur_entry.start_pts, AV_TIME_BASE_Q, st->time_base); + /* compute new timestamps */ + offset = av_rescale_q(seg->initial_offset - (seg->reset_timestamps ? seg->cur_entry.start_pts : 0), + AV_TIME_BASE_Q, st->time_base); + if (pkt->pts != AV_NOPTS_VALUE) + pkt->pts += offset; + if (pkt->dts != AV_NOPTS_VALUE) + pkt->dts += offset; - av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n", - av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), - av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); - } + av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n", + av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), + av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base)); ret = ff_write_chained(oc, pkt->stream_index, pkt, s); @@ -754,6 +767,7 @@ fail: cur = seg->segment_list_entries; while (cur) { next = cur->next; + av_free(cur->filename); av_free(cur); cur = next; } @@ -774,6 +788,7 @@ static const AVOption options[] = { { "live", "enable live-friendly list generation (useful for HLS)", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_LIVE }, INT_MIN, INT_MAX, E, "list_flags"}, { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, + { "segment_list_entry_prefix", "set prefix to prepend to each list entry filename", OFFSET(list_entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "segment_list_type", "set the segment list type", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_TYPE_UNDEFINED}, -1, LIST_TYPE_NB-1, E, "list_type" }, { "flat", "flat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, E, "list_type" }, @@ -784,7 +799,7 @@ static const AVOption options[] = { { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" }, { "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, - { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E }, + { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E }, { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, @@ -793,6 +808,7 @@ static const AVOption options[] = { { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, { "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E }, { "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E }, + { "initial_offset", "set initial timestamp offset", OFFSET(initial_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E }, { NULL }, }; diff --git a/ffmpeg/libavformat/sierravmd.c b/ffmpeg/libavformat/sierravmd.c index b0b582d..9bd42b4 100644 --- a/ffmpeg/libavformat/sierravmd.c +++ b/ffmpeg/libavformat/sierravmd.c @@ -64,8 +64,8 @@ typedef struct VmdDemuxContext { static int vmd_probe(AVProbeData *p) { - int w, h; - if (p->buf_size < 16) + int w, h, sample_rate; + if (p->buf_size < 806) return 0; /* check if the first 2 bytes of the file contain the appropriate size * of a VMD header chunk */ @@ -73,23 +73,26 @@ static int vmd_probe(AVProbeData *p) return 0; w = AV_RL16(&p->buf[12]); h = AV_RL16(&p->buf[14]); - if (!w || w > 2048 || !h || h > 2048) + sample_rate = AV_RL16(&p->buf[804]); + if ((!w || w > 2048 || !h || h > 2048) && + sample_rate != 22050) return 0; /* only return half certainty since this check is a bit sketchy */ - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; } static int vmd_read_header(AVFormatContext *s) { VmdDemuxContext *vmd = s->priv_data; AVIOContext *pb = s->pb; - AVStream *st = NULL, *vst; + AVStream *st = NULL, *vst = NULL; unsigned int toc_offset; unsigned char *raw_frame_table; int raw_frame_table_size; int64_t current_offset; - int i, j; + int i, j, ret; + int width, height; unsigned int total_frames; int64_t current_audio_pts = 0; unsigned char chunk[BYTES_PER_FRAME_RECORD]; @@ -101,28 +104,33 @@ static int vmd_read_header(AVFormatContext *s) if (avio_read(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE) return AVERROR(EIO); - if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3') - vmd->is_indeo3 = 1; - else - vmd->is_indeo3 = 0; - /* start up the decoders */ - vst = avformat_new_stream(s, NULL); - if (!vst) - return AVERROR(ENOMEM); - avpriv_set_pts_info(vst, 33, 1, 10); - vmd->video_stream_index = vst->index; - vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; - vst->codec->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO; - vst->codec->codec_tag = 0; /* no fourcc */ - vst->codec->width = AV_RL16(&vmd->vmd_header[12]); - vst->codec->height = AV_RL16(&vmd->vmd_header[14]); - if(vmd->is_indeo3 && vst->codec->width > 320){ - vst->codec->width >>= 1; - vst->codec->height >>= 1; + width = AV_RL16(&vmd->vmd_header[12]); + height = AV_RL16(&vmd->vmd_header[14]); + if (width && height) { + if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3') { + vmd->is_indeo3 = 1; + } else { + vmd->is_indeo3 = 0; + } + /* start up the decoders */ + vst = avformat_new_stream(s, NULL); + if (!vst) + return AVERROR(ENOMEM); + avpriv_set_pts_info(vst, 33, 1, 10); + vmd->video_stream_index = vst->index; + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; + vst->codec->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO; + vst->codec->codec_tag = 0; /* no fourcc */ + vst->codec->width = width; + vst->codec->height = height; + if(vmd->is_indeo3 && vst->codec->width > 320){ + vst->codec->width >>= 1; + vst->codec->height >>= 1; + } + if (ff_alloc_extradata(vst->codec, VMD_HEADER_SIZE)) + return AVERROR(ENOMEM); + memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE); } - vst->codec->extradata_size = VMD_HEADER_SIZE; - vst->codec->extradata = av_mallocz(VMD_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); - memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE); /* if sample rate is 0, assume no audio */ vmd->sample_rate = AV_RL16(&vmd->vmd_header[804]); @@ -156,7 +164,8 @@ static int vmd_read_header(AVFormatContext *s) num = st->codec->block_align; den = st->codec->sample_rate * st->codec->channels; av_reduce(&num, &den, num, den, (1UL<<31)-1); - avpriv_set_pts_info(vst, 33, num, den); + if (vst) + avpriv_set_pts_info(vst, 33, num, den); avpriv_set_pts_info(st, 33, num, den); } @@ -176,15 +185,13 @@ static int vmd_read_header(AVFormatContext *s) raw_frame_table = av_malloc(raw_frame_table_size); vmd->frame_table = av_malloc((vmd->frame_count * vmd->frames_per_block + sound_buffers) * sizeof(vmd_frame)); if (!raw_frame_table || !vmd->frame_table) { - av_free(raw_frame_table); - av_free(vmd->frame_table); - return AVERROR(ENOMEM); + ret = AVERROR(ENOMEM); + goto error; } if (avio_read(pb, raw_frame_table, raw_frame_table_size) != raw_frame_table_size) { - av_free(raw_frame_table); - av_free(vmd->frame_table); - return AVERROR(EIO); + ret = AVERROR(EIO); + goto error; } total_frames = 0; @@ -197,9 +204,19 @@ static int vmd_read_header(AVFormatContext *s) int type; uint32_t size; - avio_read(pb, chunk, BYTES_PER_FRAME_RECORD); + if ((ret = avio_read(pb, chunk, BYTES_PER_FRAME_RECORD)) != BYTES_PER_FRAME_RECORD) { + av_log(s, AV_LOG_ERROR, "Failed to read frame record\n"); + if (ret >= 0) + ret = AVERROR_INVALIDDATA; + goto error; + } type = chunk[0]; size = AV_RL32(&chunk[2]); + if (size > INT_MAX / 2) { + av_log(s, AV_LOG_ERROR, "Invalid frame size\n"); + ret = AVERROR_INVALIDDATA; + goto error; + } if(!size && type != 1) continue; switch(type) { @@ -236,6 +253,11 @@ static int vmd_read_header(AVFormatContext *s) vmd->frame_count = total_frames; return 0; + +error: + av_freep(&raw_frame_table); + av_freep(&vmd->frame_table); + return ret; } static int vmd_read_packet(AVFormatContext *s, @@ -285,7 +307,7 @@ static int vmd_read_close(AVFormatContext *s) { VmdDemuxContext *vmd = s->priv_data; - av_free(vmd->frame_table); + av_freep(&vmd->frame_table); return 0; } diff --git a/ffmpeg/libavformat/smacker.c b/ffmpeg/libavformat/smacker.c index 883a2b7..0d38588 100644 --- a/ffmpeg/libavformat/smacker.c +++ b/ffmpeg/libavformat/smacker.c @@ -92,11 +92,14 @@ static const uint8_t smk_pal[64] = { static int smacker_probe(AVProbeData *p) { - if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K' - && (p->buf[3] == '2' || p->buf[3] == '4')) - return AVPROBE_SCORE_MAX; - else + if ( AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2') + && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4')) return 0; + + if (AV_RL32(p->buf+4) > 32768U || AV_RL32(p->buf+8) > 32768U) + return AVPROBE_SCORE_MAX/4; + + return AVPROBE_SCORE_MAX; } static int smacker_read_header(AVFormatContext *s) @@ -142,8 +145,13 @@ static int smacker_read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames); return AVERROR_INVALIDDATA; } - smk->frm_size = av_malloc(smk->frames * 4); + smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size)); smk->frm_flags = av_malloc(smk->frames); + if (!smk->frm_size || !smk->frm_flags) { + av_freep(&smk->frm_size); + av_freep(&smk->frm_flags); + return AVERROR(ENOMEM); + } smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2')); @@ -180,6 +188,8 @@ static int smacker_read_header(AVFormatContext *s) smk->indexes[i] = -1; if (smk->rates[i]) { ast[i] = avformat_new_stream(s, NULL); + if (!ast[i]) + return AVERROR(ENOMEM); smk->indexes[i] = ast[i]->index; ast[i]->codec->codec_type = AVMEDIA_TYPE_AUDIO; if (smk->aflags[i] & SMK_AUD_BINKAUD) { @@ -210,18 +220,16 @@ static int smacker_read_header(AVFormatContext *s) /* load trees to extradata, they will be unpacked by decoder */ - st->codec->extradata = av_malloc(smk->treesize + 16 + FF_INPUT_BUFFER_PADDING_SIZE); - st->codec->extradata_size = smk->treesize + 16; - if(!st->codec->extradata){ + if(ff_alloc_extradata(st->codec, smk->treesize + 16)){ av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16); - av_free(smk->frm_size); - av_free(smk->frm_flags); + av_freep(&smk->frm_size); + av_freep(&smk->frm_flags); return AVERROR(ENOMEM); } ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16); if(ret != st->codec->extradata_size - 16){ - av_free(smk->frm_size); - av_free(smk->frm_flags); + av_freep(&smk->frm_size); + av_freep(&smk->frm_flags); return AVERROR(EIO); } ((int32_t*)st->codec->extradata)[0] = av_le2ne32(smk->mmap_size); @@ -276,7 +284,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) } else if(t & 0x40){ /* copy with offset */ off = avio_r8(s->pb); j = (t & 0x3F) + 1; - if (off + j > 0xff) { + if (off + j > 0x100) { av_log(s, AV_LOG_ERROR, "Invalid palette update, offset=%d length=%d extends beyond palette size\n", off, j); @@ -305,19 +313,21 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) /* if audio chunks are present, put them to stack and retrieve later */ for(i = 0; i < 7; i++) { if(flags & 1) { - unsigned int size; - uint8_t *tmpbuf; + uint32_t size; + int err; size = avio_rl32(s->pb) - 4; - if(size + 4L > frame_size) + if (!size || size + 4L > frame_size) { + av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); return AVERROR_INVALIDDATA; + } frame_size -= size; frame_size -= 4; smk->curstream++; - tmpbuf = av_realloc(smk->bufs[smk->curstream], size); - if (!tmpbuf) - return AVERROR(ENOMEM); - smk->bufs[smk->curstream] = tmpbuf; + if ((err = av_reallocp(&smk->bufs[smk->curstream], size)) < 0) { + smk->buf_sizes[smk->curstream] = 0; + return err; + } smk->buf_sizes[smk->curstream] = size; ret = avio_read(s->pb, smk->bufs[smk->curstream], size); if(ret != size) @@ -326,7 +336,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) } flags >>= 1; } - if (frame_size < 0) + if (frame_size < 0 || frame_size >= INT_MAX/2) return AVERROR_INVALIDDATA; if (av_new_packet(pkt, frame_size + 769)) return AVERROR(ENOMEM); @@ -338,10 +348,13 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) if(ret != frame_size) return AVERROR(EIO); pkt->stream_index = smk->videoindex; + pkt->pts = smk->cur_frame; pkt->size = ret + 769; smk->cur_frame++; smk->nextpos = avio_tell(s->pb); } else { + if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream]) + return AVERROR_INVALIDDATA; if (av_new_packet(pkt, smk->buf_sizes[smk->curstream])) return AVERROR(ENOMEM); memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); @@ -361,9 +374,9 @@ static int smacker_read_close(AVFormatContext *s) int i; for(i = 0; i < 7; i++) - av_free(smk->bufs[i]); - av_free(smk->frm_size); - av_free(smk->frm_flags); + av_freep(&smk->bufs[i]); + av_freep(&smk->frm_size); + av_freep(&smk->frm_flags); return 0; } diff --git a/ffmpeg/libavformat/smjpegenc.c b/ffmpeg/libavformat/smjpegenc.c index 0a27687..430a497 100644 --- a/ffmpeg/libavformat/smjpegenc.c +++ b/ffmpeg/libavformat/smjpegenc.c @@ -109,7 +109,6 @@ static int smjpeg_write_packet(AVFormatContext *s, AVPacket *pkt) avio_wb32(pb, pkt->pts); avio_wb32(pb, pkt->size); avio_write(pb, pkt->data, pkt->size); - avio_flush(pb); smc->duration = FFMAX(smc->duration, pkt->pts + pkt->duration); return 0; diff --git a/ffmpeg/libavformat/smoothstreamingenc.c b/ffmpeg/libavformat/smoothstreamingenc.c index 096bf79..fe18a95 100644 --- a/ffmpeg/libavformat/smoothstreamingenc.c +++ b/ffmpeg/libavformat/smoothstreamingenc.c @@ -210,14 +210,15 @@ static int write_manifest(AVFormatContext *s, int final) { SmoothStreamingContext *c = s->priv_data; AVIOContext *out; - char filename[1024]; + char filename[1024], temp_filename[1024]; int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0; int64_t duration = 0; snprintf(filename, sizeof(filename), "%s/Manifest", s->filename); - ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); + snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->filename); + ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", filename); + av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); return ret; } avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); @@ -278,6 +279,7 @@ static int write_manifest(AVFormatContext *s, int final) avio_printf(out, "</SmoothStreamingMedia>\n"); avio_flush(out); avio_close(out); + rename(temp_filename, filename); return 0; } @@ -428,7 +430,7 @@ static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *sta if (len < 8 || len >= *moof_size) goto fail; if (tag == MKTAG('u','u','i','d')) { - const uint8_t tfxd[] = { + static const uint8_t tfxd[] = { 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6, 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2 }; @@ -451,12 +453,16 @@ fail: static int add_fragment(OutputStream *os, const char *file, const char *infofile, int64_t start_time, int64_t duration, int64_t start_pos, int64_t size) { + int err; Fragment *frag; if (os->nb_fragments >= os->fragments_size) { os->fragments_size = (os->fragments_size + 1) * 2; - os->fragments = av_realloc(os->fragments, sizeof(*os->fragments)*os->fragments_size); - if (!os->fragments) - return AVERROR(ENOMEM); + if ((err = av_reallocp(&os->fragments, sizeof(*os->fragments) * + os->fragments_size)) < 0) { + os->fragments_size = 0; + os->nb_fragments = 0; + return err; + } } frag = av_mallocz(sizeof(*frag)); if (!frag) diff --git a/ffmpeg/libavformat/smush.c b/ffmpeg/libavformat/smush.c index 9c8997c..e9c1937 100644 --- a/ffmpeg/libavformat/smush.c +++ b/ffmpeg/libavformat/smush.c @@ -145,11 +145,9 @@ static int smush_read_header(AVFormatContext *ctx) avpriv_set_pts_info(vst, 64, 66667, 1000000); if (!smush->version) { - vst->codec->extradata = av_malloc(1024 + 2 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!vst->codec->extradata) + if (ff_alloc_extradata(vst->codec, 1024 + 2)) return AVERROR(ENOMEM); - vst->codec->extradata_size = 1024 + 2; AV_WL16(vst->codec->extradata, subversion); for (i = 0; i < 256; i++) AV_WL32(vst->codec->extradata + 2 + i * 4, palette[i]); diff --git a/ffmpeg/libavformat/spdif.h b/ffmpeg/libavformat/spdif.h index 0a0d962..fee4ff7 100644 --- a/ffmpeg/libavformat/spdif.h +++ b/ffmpeg/libavformat/spdif.h @@ -41,9 +41,9 @@ enum IEC61937DataType { IEC61937_DTS1 = 0x0B, ///< DTS type I (512 samples) IEC61937_DTS2 = 0x0C, ///< DTS type II (1024 samples) IEC61937_DTS3 = 0x0D, ///< DTS type III (2048 samples) - IEC61937_ATRAC = 0x0E, ///< Atrac data - IEC61937_ATRAC3 = 0x0F, ///< Atrac 3 data - IEC61937_ATRACX = 0x10, ///< Atrac 3 plus data + IEC61937_ATRAC = 0x0E, ///< ATRAC data + IEC61937_ATRAC3 = 0x0F, ///< ATRAC3 data + IEC61937_ATRACX = 0x10, ///< ATRAC3+ data IEC61937_DTSHD = 0x11, ///< DTS HD data IEC61937_WMAPRO = 0x12, ///< WMA 9 Professional data IEC61937_MPEG2_AAC_LSF_2048 = 0x13, ///< MPEG-2 AAC ADTS half-rate low sampling frequency diff --git a/ffmpeg/libavformat/spdifdec.c b/ffmpeg/libavformat/spdifdec.c index 726a85c..7da16c9 100644 --- a/ffmpeg/libavformat/spdifdec.c +++ b/ffmpeg/libavformat/spdifdec.c @@ -57,7 +57,7 @@ static int spdif_get_offset_and_codec(AVFormatContext *s, break; case IEC61937_MPEG2_AAC: init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8); - if (avpriv_aac_parse_header(&gbc, &aac_hdr)) { + if (avpriv_aac_parse_header(&gbc, &aac_hdr) < 0) { if (s) /* be silent during a probe */ av_log(s, AV_LOG_ERROR, "Invalid AAC packet in IEC 61937\n"); return AVERROR_INVALIDDATA; @@ -154,10 +154,10 @@ int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec) if (sync_codes >= 6) /* good amount of sync codes but with unexpected offsets */ - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; /* some sync codes were found */ - return AVPROBE_SCORE_MAX / 8; + return AVPROBE_SCORE_EXTENSION / 4; } static int spdif_read_header(AVFormatContext *s) diff --git a/ffmpeg/libavformat/spdifenc.c b/ffmpeg/libavformat/spdifenc.c index 778ab88..210d63f 100644 --- a/ffmpeg/libavformat/spdifenc.c +++ b/ffmpeg/libavformat/spdifenc.c @@ -92,7 +92,7 @@ static const AVOption options[] = { { NULL }, }; -static const AVClass class = { +static const AVClass spdif_class = { .class_name = "spdif", .item_name = av_default_item_name, .option = options, @@ -395,15 +395,15 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) { IEC61937Context *ctx = s->priv_data; int mat_code_length = 0; - const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 }; + static const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 }; if (!ctx->hd_buf_count) { - const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 }; + static const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 }; mat_code_length = sizeof(mat_start_code) + BURST_HEADER_SIZE; memcpy(ctx->hd_buf, mat_start_code, sizeof(mat_start_code)); } else if (ctx->hd_buf_count == 12) { - const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 }; + static const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 }; mat_code_length = sizeof(mat_middle_code) + MAT_MIDDLE_CODE_OFFSET; memcpy(&ctx->hd_buf[12 * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + MAT_MIDDLE_CODE_OFFSET], mat_middle_code, sizeof(mat_middle_code)); @@ -538,7 +538,6 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_DEBUG, "type=%x len=%i pkt_offset=%i\n", ctx->data_type, ctx->out_bytes, ctx->pkt_offset); - avio_flush(s->pb); return 0; } @@ -553,5 +552,5 @@ AVOutputFormat ff_spdif_muxer = { .write_packet = spdif_write_packet, .write_trailer = spdif_write_trailer, .flags = AVFMT_NOTIMESTAMPS, - .priv_class = &class, + .priv_class = &spdif_class, }; diff --git a/ffmpeg/libavformat/srtdec.c b/ffmpeg/libavformat/srtdec.c index 76e06e4..7f911bd 100644 --- a/ffmpeg/libavformat/srtdec.c +++ b/ffmpeg/libavformat/srtdec.c @@ -37,12 +37,14 @@ static int srt_probe(AVProbeData *p) if (AV_RB24(ptr) == 0xEFBBBF) ptr += 3; /* skip UTF-8 BOM */ + while (*ptr == '\r' || *ptr == '\n') + ptr++; for (i=0; i<2; i++) { if ((num == i || num + 1 == i) && sscanf(ptr, "%*d:%*2d:%*2d%*1[,.]%*3d --> %*d:%*2d:%*2d%*1[,.]%3d", &v) == 1) return AVPROBE_SCORE_MAX; num = atoi(ptr); - ptr += strcspn(ptr, "\n") + 1; + ptr += ff_subtitles_next_line(ptr); } return 0; } @@ -63,10 +65,10 @@ static int64_t get_pts(const char **buf, int *duration, int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1; int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2; *duration = end - start; - *buf += strcspn(*buf, "\n") + 1; + *buf += ff_subtitles_next_line(*buf); return start; } - *buf += strcspn(*buf, "\n") + 1; + *buf += ff_subtitles_next_line(*buf); } return AV_NOPTS_VALUE; } diff --git a/ffmpeg/libavformat/srtenc.c b/ffmpeg/libavformat/srtenc.c index e02c4ef..b43504b 100644 --- a/ffmpeg/libavformat/srtenc.c +++ b/ffmpeg/libavformat/srtenc.c @@ -98,7 +98,6 @@ static int srt_write_packet(AVFormatContext *avf, AVPacket *pkt) avio_write(avf->pb, pkt->data, pkt->size); if (write_ts) avio_write(avf->pb, "\n\n", 2); - avio_flush(avf->pb); srt->index++; return 0; } diff --git a/ffmpeg/libavformat/srtp.c b/ffmpeg/libavformat/srtp.c index 65309d0..b6e8211 100644 --- a/ffmpeg/libavformat/srtp.c +++ b/ffmpeg/libavformat/srtp.c @@ -25,6 +25,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "rtp.h" +#include "rtpdec.h" #include "srtp.h" void ff_srtp_free(struct SRTPContext *s) @@ -419,7 +420,7 @@ static void test_encrypt(const uint8_t *data, int in_len, const char *suite, { struct SRTPContext enc = { 0 }, dec = { 0 }; int len; - char buf[1500]; + char buf[RTP_MAX_PACKET_LENGTH]; ff_srtp_set_crypto(&enc, suite, key); ff_srtp_set_crypto(&dec, suite, key); len = ff_srtp_encrypt(&enc, data, in_len, buf, sizeof(buf)); @@ -441,7 +442,7 @@ int main(void) static const char *aes128_32_suite = "AES_CM_128_HMAC_SHA1_32"; static const char *aes128_80_32_suite = "SRTP_AES128_CM_HMAC_SHA1_32"; static const char *test_key = "abcdefghijklmnopqrstuvwxyz1234567890ABCD"; - uint8_t buf[1500]; + uint8_t buf[RTP_MAX_PACKET_LENGTH]; struct SRTPContext srtp = { 0 }; int len; ff_srtp_set_crypto(&srtp, aes128_80_suite, aes128_80_key); diff --git a/ffmpeg/libavformat/srtpproto.c b/ffmpeg/libavformat/srtpproto.c index f5e3d14..f9d6b17 100644 --- a/ffmpeg/libavformat/srtpproto.c +++ b/ffmpeg/libavformat/srtpproto.c @@ -25,6 +25,7 @@ #include "url.h" #include "internal.h" +#include "rtpdec.h" #include "srtp.h" typedef struct SRTPProtoContext { @@ -33,7 +34,7 @@ typedef struct SRTPProtoContext { const char *out_suite, *out_params; const char *in_suite, *in_params; struct SRTPContext srtp_out, srtp_in; - uint8_t encryptbuf[1500]; + uint8_t encryptbuf[RTP_MAX_PACKET_LENGTH]; } SRTPProtoContext; #define D AV_OPT_FLAG_DECODING_PARAM diff --git a/ffmpeg/libavformat/subtitles.c b/ffmpeg/libavformat/subtitles.c index 2af0450..fce2bf1 100644 --- a/ffmpeg/libavformat/subtitles.c +++ b/ffmpeg/libavformat/subtitles.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Clément Bœsch + * Copyright (c) 2012-2013 Clément Bœsch <u pkh me> * * This file is part of FFmpeg. * @@ -57,7 +57,7 @@ AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, return sub; } -static int cmp_pkt_sub(const void *a, const void *b) +static int cmp_pkt_sub_ts_pos(const void *a, const void *b) { const AVPacket *s1 = a; const AVPacket *s2 = b; @@ -69,11 +69,25 @@ static int cmp_pkt_sub(const void *a, const void *b) return s1->pts > s2->pts ? 1 : -1; } +static int cmp_pkt_sub_pos_ts(const void *a, const void *b) +{ + const AVPacket *s1 = a; + const AVPacket *s2 = b; + if (s1->pos == s2->pos) { + if (s1->pts == s2->pts) + return 0; + return s1->pts > s2->pts ? 1 : -1; + } + return s1->pos > s2->pos ? 1 : -1; +} + void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q) { int i; - qsort(q->subs, q->nb_subs, sizeof(*q->subs), cmp_pkt_sub); + qsort(q->subs, q->nb_subs, sizeof(*q->subs), + q->sort == SUB_SORT_TS_POS ? cmp_pkt_sub_ts_pos + : cmp_pkt_sub_pos_ts); for (i = 0; i < q->nb_subs; i++) if (q->subs[i].duration == -1 && i < q->nb_subs - 1) q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts; @@ -85,13 +99,37 @@ int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt) if (q->current_sub_idx == q->nb_subs) return AVERROR_EOF; - av_copy_packet(pkt, sub); + if (av_copy_packet(pkt, sub) < 0) { + return AVERROR(ENOMEM); + } pkt->dts = pkt->pts; q->current_sub_idx++; return 0; } +static int search_sub_ts(const FFDemuxSubtitlesQueue *q, int64_t ts) +{ + int s1 = 0, s2 = q->nb_subs - 1; + + if (s2 < s1) + return AVERROR(ERANGE); + + for (;;) { + int mid; + + if (s1 == s2) + return s1; + if (s1 == s2 - 1) + return q->subs[s1].pts <= q->subs[s2].pts ? s1 : s2; + mid = (s1 + s2) / 2; + if (q->subs[mid].pts <= ts) + s1 = mid; + else + s2 = mid; + } +} + int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags) { @@ -102,30 +140,43 @@ int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int st return AVERROR(ERANGE); q->current_sub_idx = ts; } else { - int i, idx = -1; - int64_t min_ts_diff = INT64_MAX; + int i, idx = search_sub_ts(q, ts); int64_t ts_selected; - /* TODO: q->subs[] is sorted by pts so we could do a binary search */ - for (i = 0; i < q->nb_subs; i++) { - int64_t pts = q->subs[i].pts; - uint64_t ts_diff = FFABS(pts - ts); - if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) { - min_ts_diff = ts_diff; - idx = i; - } - } + if (idx < 0) + return idx; + for (i = idx; i < q->nb_subs && q->subs[i].pts < min_ts; i++) + if (stream_index == -1 || q->subs[i].stream_index == stream_index) + idx = i; + for (i = idx; i > 0 && q->subs[i].pts > max_ts; i--) + if (stream_index == -1 || q->subs[i].stream_index == stream_index) + idx = i; + + ts_selected = q->subs[idx].pts; + if (ts_selected < min_ts || ts_selected > max_ts) return AVERROR(ERANGE); + /* look back in the latest subtitles for overlapping subtitles */ - ts_selected = q->subs[idx].pts; for (i = idx - 1; i >= 0; i--) { - if (q->subs[i].duration <= 0) + int64_t pts = q->subs[i].pts; + if (q->subs[i].duration <= 0 || + (stream_index != -1 && q->subs[i].stream_index != stream_index)) continue; - if (q->subs[i].pts > ts_selected - q->subs[i].duration) + if (pts >= min_ts && pts > ts_selected - q->subs[i].duration) idx = i; else break; } + + /* If the queue is used to store multiple subtitles streams (like with + * VobSub) and the stream index is not specified, we need to make sure + * to focus on the smallest file position offset for a same timestamp; + * queue is ordered by pts and then filepos, so we can take the first + * entry for a given timestamp. */ + if (stream_index == -1) + while (idx > 0 && q->subs[idx - 1].pts == q->subs[idx].pts) + idx--; + q->current_sub_idx = idx; } return 0; @@ -191,7 +242,7 @@ static inline int is_eol(char c) void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf) { - char eol_buf[5]; + char eol_buf[5], last_was_cr = 0; int n = 0, i = 0, nb_eol = 0; av_bprint_clear(buf); @@ -208,12 +259,13 @@ void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf) /* line break buffering: we don't want to add the trailing \r\n */ if (is_eol(c)) { - nb_eol += c == '\n'; + nb_eol += c == '\n' || last_was_cr; if (nb_eol == 2) break; eol_buf[i++] = c; if (i == sizeof(eol_buf) - 1) break; + last_was_cr = c == '\r'; continue; } diff --git a/ffmpeg/libavformat/subtitles.h b/ffmpeg/libavformat/subtitles.h index 455b374..b5a96ec 100644 --- a/ffmpeg/libavformat/subtitles.h +++ b/ffmpeg/libavformat/subtitles.h @@ -25,11 +25,17 @@ #include "avformat.h" #include "libavutil/bprint.h" +enum sub_sort { + SUB_SORT_TS_POS = 0, ///< sort by timestamps, then position + SUB_SORT_POS_TS, ///< sort by position, then timestamps +}; + typedef struct { AVPacket *subs; ///< array of subtitles packets int nb_subs; ///< number of subtitles packets int allocated_size; ///< allocated size for subs int current_sub_idx; ///< current position for the read packet callback + enum sub_sort sort; ///< sort method to use when finalizing subtitles } FFDemuxSubtitlesQueue; /** @@ -96,4 +102,23 @@ const char *ff_smil_get_attr_ptr(const char *s, const char *attr); */ void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf); +/** + * Get the number of characters to increment to jump to the next line, or to + * the end of the string. + * The function handles the following line breaks schemes: + * LF, CRLF (MS), or standalone CR (old MacOS). + */ +static av_always_inline int ff_subtitles_next_line(const char *ptr) +{ + int n = strcspn(ptr, "\r\n"); + ptr += n; + if (*ptr == '\r') { + ptr++; + n++; + } + if (*ptr == '\n') + n++; + return n; +} + #endif /* AVFORMAT_SUBTITLES_H */ diff --git a/ffmpeg/libavformat/subviewer1dec.c b/ffmpeg/libavformat/subviewer1dec.c index 0dc1942..1b831b7 100644 --- a/ffmpeg/libavformat/subviewer1dec.c +++ b/ffmpeg/libavformat/subviewer1dec.c @@ -36,7 +36,7 @@ static int subviewer1_probe(AVProbeData *p) const unsigned char *ptr = p->buf; if (strstr(ptr, "******** START SCRIPT ********")) - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; return 0; } diff --git a/ffmpeg/libavformat/subviewerdec.c b/ffmpeg/libavformat/subviewerdec.c index 7cacd97..9e645d2 100644 --- a/ffmpeg/libavformat/subviewerdec.c +++ b/ffmpeg/libavformat/subviewerdec.c @@ -44,7 +44,7 @@ static int subviewer_probe(AVProbeData *p) if (AV_RB24(ptr) == 0xEFBBBF) ptr += 3; /* skip UTF-8 BOM */ if (sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1) - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; if (!strncmp(ptr, "[INFORMATION]", 13)) return AVPROBE_SCORE_MAX/3; return 0; diff --git a/ffmpeg/libavformat/swf.h b/ffmpeg/libavformat/swf.h index b9722c1..c1667b3 100644 --- a/ffmpeg/libavformat/swf.h +++ b/ffmpeg/libavformat/swf.h @@ -120,9 +120,6 @@ enum { #define VIDEO_ID 0 #define SHAPE_ID 1 -#undef NDEBUG -#include <assert.h> - typedef struct SWFContext { int64_t duration_pos; int64_t tag_pos; diff --git a/ffmpeg/libavformat/swfdec.c b/ffmpeg/libavformat/swfdec.c index 54e0f6d..c95b18e 100644 --- a/ffmpeg/libavformat/swfdec.c +++ b/ffmpeg/libavformat/swfdec.c @@ -55,12 +55,18 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr) static int swf_probe(AVProbeData *p) { + if(p->buf_size < 15) + return 0; + /* check file header */ - if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' && - p->buf[2] == 'S') - return AVPROBE_SCORE_MAX; - else + if ( AV_RB24(p->buf) != AV_RB24("CWS") + && AV_RB24(p->buf) != AV_RB24("FWS")) return 0; + + if (p->buf[3] >= 20) + return AVPROBE_SCORE_MAX / 4; + + return AVPROBE_SCORE_MAX; } #if CONFIG_ZLIB @@ -440,16 +446,30 @@ bitmap_end_skip: goto skip; if ((res = av_new_packet(pkt, len)) < 0) return res; - avio_read(pb, pkt->data, 4); + if (avio_read(pb, pkt->data, 4) != 4) { + av_free_packet(pkt); + return AVERROR_INVALIDDATA; + } if (AV_RB32(pkt->data) == 0xffd8ffd9 || AV_RB32(pkt->data) == 0xffd9ffd8) { /* old SWF files containing SOI/EOI as data start */ /* files created by swink have reversed tag */ pkt->size -= 4; - avio_read(pb, pkt->data, pkt->size); + memset(pkt->data+pkt->size, 0, 4); + res = avio_read(pb, pkt->data, pkt->size); } else { - avio_read(pb, pkt->data + 4, pkt->size - 4); + res = avio_read(pb, pkt->data + 4, pkt->size - 4); + if (res >= 0) + res += 4; + } + if (res != pkt->size) { + if (res < 0) { + av_free_packet(pkt); + return res; + } + av_shrink_packet(pkt, res); } + pkt->pos = pos; pkt->stream_index = st->index; return pkt->size; diff --git a/ffmpeg/libavformat/swfenc.c b/ffmpeg/libavformat/swfenc.c index 5b7fd1f..8d9cf0c 100644 --- a/ffmpeg/libavformat/swfenc.c +++ b/ffmpeg/libavformat/swfenc.c @@ -234,7 +234,7 @@ static int swf_write_header(AVFormatContext *s) } if (!swf->audio_enc) - swf->samples_per_frame = (44100. * rate_base) / rate; + swf->samples_per_frame = (44100.0 * rate_base) / rate; else swf->samples_per_frame = (swf->audio_enc->sample_rate * rate_base) / rate; @@ -441,8 +441,6 @@ static int swf_write_video(AVFormatContext *s, put_swf_tag(s, TAG_SHOWFRAME); put_swf_end_tag(s); - avio_flush(s->pb); - return 0; } diff --git a/ffmpeg/libavformat/takdec.c b/ffmpeg/libavformat/takdec.c index 377c10c..2ed8a1e 100644 --- a/ffmpeg/libavformat/takdec.c +++ b/ffmpeg/libavformat/takdec.c @@ -19,8 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/crc.h" #include "libavcodec/tak.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "rawdec.h" #include "apetag.h" @@ -33,10 +35,16 @@ typedef struct TAKDemuxContext { static int tak_probe(AVProbeData *p) { if (!memcmp(p->buf, "tBaK", 4)) - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; return 0; } +static unsigned long tak_check_crc(unsigned long checksum, const uint8_t *buf, + unsigned int len) +{ + return av_crc(av_crc_get_table(AV_CRC_24_IEEE), checksum, buf, len); +} + static int tak_read_header(AVFormatContext *s) { TAKDemuxContext *tc = s->priv_data; @@ -71,16 +79,27 @@ static int tak_read_header(AVFormatContext *s) case TAK_METADATA_STREAMINFO: case TAK_METADATA_LAST_FRAME: case TAK_METADATA_ENCODER: - buffer = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + if (size <= 3) + return AVERROR_INVALIDDATA; + + buffer = av_malloc(size - 3 + FF_INPUT_BUFFER_PADDING_SIZE); if (!buffer) return AVERROR(ENOMEM); - if (avio_read(pb, buffer, size) != size) { + ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U); + if (avio_read(pb, buffer, size - 3) != size - 3) { av_freep(&buffer); return AVERROR(EIO); } + if (ffio_get_checksum(s->pb) != avio_rb24(pb)) { + av_log(s, AV_LOG_ERROR, "%d metadata block CRC error.\n", type); + if (s->error_recognition & AV_EF_EXPLODE) { + av_freep(&buffer); + return AVERROR_INVALIDDATA; + } + } - init_get_bits(&gb, buffer, size * 8); + init_get_bits8(&gb, buffer, size - 3); break; case TAK_METADATA_MD5: { uint8_t md5[16]; @@ -88,8 +107,14 @@ static int tak_read_header(AVFormatContext *s) if (size != 19) return AVERROR_INVALIDDATA; + ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U); avio_read(pb, md5, 16); - avio_skip(pb, 3); + if (ffio_get_checksum(s->pb) != avio_rb24(pb)) { + av_log(s, AV_LOG_ERROR, "MD5 metadata block CRC error.\n"); + if (s->error_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + } + av_log(s, AV_LOG_VERBOSE, "MD5="); for (i = 0; i < 16; i++) av_log(s, AV_LOG_VERBOSE, "%02x", md5[i]); @@ -127,7 +152,7 @@ static int tak_read_header(AVFormatContext *s) st->start_time = 0; avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); st->codec->extradata = buffer; - st->codec->extradata_size = size; + st->codec->extradata_size = size - 3; buffer = NULL; } else if (type == TAK_METADATA_LAST_FRAME) { if (size != 11) @@ -155,7 +180,7 @@ static int raw_read_packet(AVFormatContext *s, AVPacket *pkt) AVIOContext *pb = s->pb; int64_t size, left; - left = tc->data_end - avio_tell(s->pb); + left = tc->data_end - avio_tell(pb); size = FFMIN(left, 1024); if (size <= 0) return AVERROR_EOF; diff --git a/ffmpeg/libavformat/tcp.c b/ffmpeg/libavformat/tcp.c index 0d792e7..e457fba 100644 --- a/ffmpeg/libavformat/tcp.c +++ b/ffmpeg/libavformat/tcp.c @@ -34,6 +34,7 @@ typedef struct TCPContext { const AVClass *class; int fd; int listen; + int open_timeout; int rw_timeout; int listen_timeout; } TCPContext; @@ -43,8 +44,8 @@ typedef struct TCPContext { #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { {"listen", "listen on port instead of connecting", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, -{"timeout", "timeout of socket i/o operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, -{"listen_timeout", "connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, +{"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, +{"listen_timeout", "set connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E }, {NULL} }; @@ -64,10 +65,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) const char *p; char buf[256]; int ret; - socklen_t optlen; char hostname[1024],proto[1024],path[1024]; char portstr[10]; - h->rw_timeout = 5000000; + s->open_timeout = 5000000; av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); @@ -79,8 +79,13 @@ static int tcp_open(URLContext *h, const char *uri, int flags) } p = strchr(uri, '?'); if (p) { - if (av_find_info_tag(buf, sizeof(buf), "listen", p)) - s->listen = 1; + if (av_find_info_tag(buf, sizeof(buf), "listen", p)) { + char *endptr = NULL; + s->listen = strtol(buf, &endptr, 10); + /* assume if no digits were found it is a request to enable it */ + if (buf == endptr) + s->listen = 1; + } if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { s->rw_timeout = strtol(buf, NULL, 10); } @@ -88,7 +93,10 @@ static int tcp_open(URLContext *h, const char *uri, int flags) s->listen_timeout = strtol(buf, NULL, 10); } } - h->rw_timeout = s->rw_timeout; + if (s->rw_timeout >= 0) { + s->open_timeout = + h->rw_timeout = s->rw_timeout; + } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); @@ -108,89 +116,31 @@ static int tcp_open(URLContext *h, const char *uri, int flags) cur_ai = ai; restart: - ret = AVERROR(EIO); - fd = socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); - if (fd < 0) + fd = ff_socket(cur_ai->ai_family, + cur_ai->ai_socktype, + cur_ai->ai_protocol); + if (fd < 0) { + ret = ff_neterrno(); goto fail; + } if (s->listen) { - int fd1; - int reuse = 1; - struct pollfd lp = { fd, POLLIN, 0 }; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); - ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); - if (ret) { - ret = ff_neterrno(); - goto fail1; - } - ret = listen(fd, 1); - if (ret) { - ret = ff_neterrno(); - goto fail1; - } - ret = poll(&lp, 1, s->listen_timeout >= 0 ? s->listen_timeout : -1); - if (ret <= 0) { - ret = AVERROR(ETIMEDOUT); - goto fail1; - } - fd1 = accept(fd, NULL, NULL); - if (fd1 < 0) { - ret = ff_neterrno(); + if ((fd = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + s->listen_timeout, h)) < 0) { + ret = fd; goto fail1; } - closesocket(fd); - fd = fd1; - ff_socket_nonblock(fd, 1); } else { - redo: - ff_socket_nonblock(fd, 1); - ret = connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); - } + if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) { - if (ret < 0) { - struct pollfd p = {fd, POLLOUT, 0}; - int64_t wait_started; - ret = ff_neterrno(); - if (ret == AVERROR(EINTR)) { - if (ff_check_interrupt(&h->interrupt_callback)) { - ret = AVERROR_EXIT; + if (ret == AVERROR_EXIT) goto fail1; - } - goto redo; - } - if (ret != AVERROR(EINPROGRESS) && - ret != AVERROR(EAGAIN)) - goto fail; - - /* wait until we are connected or until abort */ - wait_started = av_gettime(); - do { - if (ff_check_interrupt(&h->interrupt_callback)) { - ret = AVERROR_EXIT; - goto fail1; - } - ret = poll(&p, 1, 100); - if (ret > 0) - break; - } while (!h->rw_timeout || (av_gettime() - wait_started < h->rw_timeout)); - if (ret <= 0) { - ret = AVERROR(ETIMEDOUT); - goto fail; - } - /* test error */ - optlen = sizeof(ret); - if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) - ret = AVUNERROR(ff_neterrno()); - if (ret != 0) { - char errbuf[100]; - ret = AVERROR(ret); - av_strerror(ret, errbuf, sizeof(errbuf)); - av_log(h, AV_LOG_ERROR, - "TCP connection to %s:%d failed: %s\n", - hostname, port, errbuf); - goto fail; + else + goto fail; } } + h->is_streamed = 1; s->fd = fd; freeaddrinfo(ai); @@ -202,6 +152,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) cur_ai = cur_ai->ai_next; if (fd >= 0) closesocket(fd); + ret = 0; goto restart; } fail1: diff --git a/ffmpeg/libavformat/tedcaptionsdec.c b/ffmpeg/libavformat/tedcaptionsdec.c index 048ba96..68063fa 100644 --- a/ffmpeg/libavformat/tedcaptionsdec.c +++ b/ffmpeg/libavformat/tedcaptionsdec.c @@ -153,7 +153,8 @@ static int parse_label(AVIOContext *pb, int *cur_byte, AVBPrint *bp) static int parse_boolean(AVIOContext *pb, int *cur_byte, int *result) { - const char *text[] = { "false", "true" }, *p; + static const char * const text[] = { "false", "true" }; + const char *p; int i; skip_spaces(pb, cur_byte); @@ -340,7 +341,7 @@ static av_cold int tedcaptions_read_probe(AVProbeData *p) count++; } return count == FF_ARRAY_ELEMS(tags) ? AVPROBE_SCORE_MAX : - count ? AVPROBE_SCORE_MAX / 2 : 0; + count ? AVPROBE_SCORE_EXTENSION : 0; } static int tedcaptions_read_seek(AVFormatContext *avf, int stream_index, diff --git a/ffmpeg/libavformat/tee.c b/ffmpeg/libavformat/tee.c index 10787ca..12ea0ea 100644 --- a/ffmpeg/libavformat/tee.c +++ b/ffmpeg/libavformat/tee.c @@ -1,5 +1,5 @@ /* - * Tee pesudo-muxer + * Tee pseudo-muxer * Copyright (c) 2012 Nicolas George * * This file is part of FFmpeg. @@ -27,16 +27,26 @@ #define MAX_SLAVES 16 +typedef struct { + AVFormatContext *avf; + AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream + + /** map from input to output streams indexes, + * disabled output streams are set to -1 */ + int *stream_map; +} TeeSlave; + typedef struct TeeContext { const AVClass *class; unsigned nb_slaves; - AVFormatContext *slaves[MAX_SLAVES]; + TeeSlave slaves[MAX_SLAVES]; } TeeContext; static const char *const slave_delim = "|"; static const char *const slave_opt_open = "["; static const char *const slave_opt_close = "]"; static const char *const slave_opt_delim = ":]"; /* must have the close too */ +static const char *const slave_bsfs_spec_sep = "/"; static const AVClass tee_muxer_class = { .class_name = "Tee muxer", @@ -82,34 +92,104 @@ fail: return ret; } -static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf) +/** + * Parse list of bitstream filters and add them to the list of filters + * pointed to by bsfs. + * + * The list must be specified in the form: + * BSFS ::= BSF[,BSFS] + */ +static int parse_bsfs(void *log_ctx, const char *bsfs_spec, + AVBitStreamFilterContext **bsfs) +{ + char *bsf_name, *buf, *dup, *saveptr; + int ret = 0; + + if (!(dup = buf = av_strdup(bsfs_spec))) + return AVERROR(ENOMEM); + + while (bsf_name = av_strtok(buf, ",", &saveptr)) { + AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name); + + if (!bsf) { + av_log(log_ctx, AV_LOG_ERROR, + "Cannot initialize bitstream filter with name '%s', " + "unknown filter or internal error happened\n", + bsf_name); + ret = AVERROR_UNKNOWN; + goto end; + } + + /* append bsf context to the list of bsf contexts */ + *bsfs = bsf; + bsfs = &bsf->next; + + buf = NULL; + } + +end: + av_free(dup); + return ret; +} + +static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) { int i, ret; AVDictionary *options = NULL; AVDictionaryEntry *entry; char *filename; - char *format = NULL; + char *format = NULL, *select = NULL; AVFormatContext *avf2 = NULL; AVStream *st, *st2; + int stream_count; if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0) return ret; - if ((entry = av_dict_get(options, "f", NULL, 0))) { - format = entry->value; - entry->value = NULL; /* prevent it from being freed */ - av_dict_set(&options, "f", NULL, 0); - } + +#define STEAL_OPTION(option, field) do { \ + if ((entry = av_dict_get(options, option, NULL, 0))) { \ + field = entry->value; \ + entry->value = NULL; /* prevent it from being freed */ \ + av_dict_set(&options, option, NULL, 0); \ + } \ + } while (0) + + STEAL_OPTION("f", format); + STEAL_OPTION("select", select); ret = avformat_alloc_output_context2(&avf2, NULL, format, filename); if (ret < 0) - goto fail; - av_free(format); + goto end; + av_dict_copy(&avf2->metadata, avf->metadata, 0); + tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map)); + if (!tee_slave->stream_map) { + ret = AVERROR(ENOMEM); + goto end; + } + + stream_count = 0; for (i = 0; i < avf->nb_streams; i++) { st = avf->streams[i]; + if (select) { + ret = avformat_match_stream_specifier(avf, avf->streams[i], select); + if (ret < 0) { + av_log(avf, AV_LOG_ERROR, + "Invalid stream specifier '%s' for output '%s'\n", + select, slave); + goto end; + } + + if (ret == 0) { /* no match */ + tee_slave->stream_map[i] = -1; + continue; + } + } + tee_slave->stream_map[i] = stream_count++; + if (!(st2 = avformat_new_stream(avf2, NULL))) { ret = AVERROR(ENOMEM); - goto fail; + goto end; } st2->id = st->id; st2->r_frame_rate = st->r_frame_rate; @@ -122,34 +202,85 @@ static int open_slave(AVFormatContext *avf, char *slave, AVFormatContext **ravf) st2->avg_frame_rate = st->avg_frame_rate; av_dict_copy(&st2->metadata, st->metadata, 0); if ((ret = avcodec_copy_context(st2->codec, st->codec)) < 0) - goto fail; + goto end; } if (!(avf2->oformat->flags & AVFMT_NOFILE)) { if ((ret = avio_open(&avf2->pb, filename, AVIO_FLAG_WRITE)) < 0) { av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n", slave, av_err2str(ret)); - goto fail; + goto end; } } if ((ret = avformat_write_header(avf2, &options)) < 0) { av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n", slave, av_err2str(ret)); - goto fail; + goto end; + } + + tee_slave->avf = avf2; + tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(TeeSlave)); + if (!tee_slave->bsfs) { + ret = AVERROR(ENOMEM); + goto end; + } + + entry = NULL; + while (entry = av_dict_get(options, "bsfs", NULL, AV_DICT_IGNORE_SUFFIX)) { + const char *spec = entry->key + strlen("bsfs"); + if (*spec) { + if (strspn(spec, slave_bsfs_spec_sep) != 1) { + av_log(avf, AV_LOG_ERROR, + "Specifier separator in '%s' is '%c', but only characters '%s' " + "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep); + return AVERROR(EINVAL); + } + spec++; /* consume separator */ + } + + for (i = 0; i < avf2->nb_streams; i++) { + ret = avformat_match_stream_specifier(avf2, avf2->streams[i], spec); + if (ret < 0) { + av_log(avf, AV_LOG_ERROR, + "Invalid stream specifier '%s' in bsfs option '%s' for slave " + "output '%s'\n", spec, entry->key, filename); + goto end; + } + + if (ret > 0) { + av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave " + "output '%s'\n", spec, entry->value, i, filename); + if (tee_slave->bsfs[i]) { + av_log(avf, AV_LOG_WARNING, + "Duplicate bsfs specification associated to stream %d of slave " + "output '%s', filters will be ignored\n", i, filename); + continue; + } + ret = parse_bsfs(avf, entry->value, &tee_slave->bsfs[i]); + if (ret < 0) { + av_log(avf, AV_LOG_ERROR, + "Error parsing bitstream filter sequence '%s' associated to " + "stream %d of slave output '%s'\n", entry->value, i, filename); + goto end; + } + } + } + + av_dict_set(&options, entry->key, NULL, 0); } + if (options) { entry = NULL; while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX))) av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key); ret = AVERROR_OPTION_NOT_FOUND; - goto fail; + goto end; } - *ravf = avf2; - return 0; - -fail: +end: + av_free(format); + av_free(select); av_dict_free(&options); return ret; } @@ -158,14 +289,50 @@ static void close_slaves(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; AVFormatContext *avf2; - unsigned i; + unsigned i, j; for (i = 0; i < tee->nb_slaves; i++) { - avf2 = tee->slaves[i]; + avf2 = tee->slaves[i].avf; + + for (j = 0; j < avf2->nb_streams; j++) { + AVBitStreamFilterContext *bsf_next, *bsf = tee->slaves[i].bsfs[j]; + while (bsf) { + bsf_next = bsf->next; + av_bitstream_filter_close(bsf); + bsf = bsf_next; + } + } + av_freep(&tee->slaves[i].stream_map); + av_freep(&tee->slaves[i].bsfs); + avio_close(avf2->pb); avf2->pb = NULL; avformat_free_context(avf2); - tee->slaves[i] = NULL; + tee->slaves[i].avf = NULL; + } +} + +static void log_slave(TeeSlave *slave, void *log_ctx, int log_level) +{ + int i; + av_log(log_ctx, log_level, "filename:'%s' format:%s\n", + slave->avf->filename, slave->avf->oformat->name); + for (i = 0; i < slave->avf->nb_streams; i++) { + AVStream *st = slave->avf->streams[i]; + AVBitStreamFilterContext *bsf = slave->bsfs[i]; + + av_log(log_ctx, log_level, " stream:%d codec:%s type:%s", + i, avcodec_get_name(st->codec->codec_id), + av_get_media_type_string(st->codec->codec_type)); + if (bsf) { + av_log(log_ctx, log_level, " bsfs:"); + while (bsf) { + av_log(log_ctx, log_level, "%s%s", + bsf->filter->name, bsf->next ? "," : ""); + bsf = bsf->next; + } + } + av_log(log_ctx, log_level, "\n"); } } @@ -195,10 +362,20 @@ static int tee_write_header(AVFormatContext *avf) for (i = 0; i < nb_slaves; i++) { if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) goto fail; + log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE); av_freep(&slaves[i]); } tee->nb_slaves = nb_slaves; + + for (i = 0; i < avf->nb_streams; i++) { + int j, mapped = 0; + for (j = 0; j < tee->nb_slaves; j++) + mapped += tee->slaves[j].stream_map[i] >= 0; + if (!mapped) + av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped " + "to any slave.\n", i); + } return 0; fail: @@ -208,6 +385,46 @@ fail: return ret; } +static int filter_packet(void *log_ctx, AVPacket *pkt, + AVFormatContext *fmt_ctx, AVBitStreamFilterContext *bsf_ctx) +{ + AVCodecContext *enc_ctx = fmt_ctx->streams[pkt->stream_index]->codec; + int ret = 0; + + while (bsf_ctx) { + AVPacket new_pkt = *pkt; + ret = av_bitstream_filter_filter(bsf_ctx, enc_ctx, NULL, + &new_pkt.data, &new_pkt.size, + pkt->data, pkt->size, + pkt->flags & AV_PKT_FLAG_KEY); + if (ret == 0 && new_pkt.data != pkt->data && new_pkt.destruct) { + if ((ret = av_copy_packet(&new_pkt, pkt)) < 0) + break; + ret = 1; + } + + if (ret > 0) { + av_free_packet(pkt); + new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size, + av_buffer_default_free, NULL, 0); + if (!new_pkt.buf) + break; + } + *pkt = new_pkt; + + bsf_ctx = bsf_ctx->next; + } + + if (ret < 0) { + av_log(log_ctx, AV_LOG_ERROR, + "Failed to filter bitstream with filter %s for stream %d in file '%s' with codec %s\n", + bsf_ctx->filter->name, pkt->stream_index, fmt_ctx->filename, + avcodec_get_name(enc_ctx->codec_id)); + } + + return ret; +} + static int tee_write_trailer(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; @@ -216,7 +433,7 @@ static int tee_write_trailer(AVFormatContext *avf) unsigned i; for (i = 0; i < tee->nb_slaves; i++) { - avf2 = tee->slaves[i]; + avf2 = tee->slaves[i].avf; if ((ret = av_write_trailer(avf2)) < 0) if (!ret_all) ret_all = ret; @@ -238,27 +455,30 @@ static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt) AVPacket pkt2; int ret_all = 0, ret; unsigned i, s; + int s2; AVRational tb, tb2; for (i = 0; i < tee->nb_slaves; i++) { - avf2 = tee->slaves[i]; + avf2 = tee->slaves[i].avf; s = pkt->stream_index; - if (s >= avf2->nb_streams) { - if (!ret_all) - ret_all = AVERROR(EINVAL); + s2 = tee->slaves[i].stream_map[s]; + if (s2 < 0) continue; - } + if ((ret = av_copy_packet(&pkt2, pkt)) < 0 || (ret = av_dup_packet(&pkt2))< 0) if (!ret_all) { ret = ret_all; continue; } - tb = avf ->streams[s]->time_base; - tb2 = avf2->streams[s]->time_base; + tb = avf ->streams[s ]->time_base; + tb2 = avf2->streams[s2]->time_base; pkt2.pts = av_rescale_q(pkt->pts, tb, tb2); pkt2.dts = av_rescale_q(pkt->dts, tb, tb2); pkt2.duration = av_rescale_q(pkt->duration, tb, tb2); + pkt2.stream_index = s2; + + filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsfs[s2]); if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0) if (!ret_all) ret_all = ret; diff --git a/ffmpeg/libavformat/thp.c b/ffmpeg/libavformat/thp.c index 3717b8f..bc4f0da 100644 --- a/ffmpeg/libavformat/thp.c +++ b/ffmpeg/libavformat/thp.c @@ -26,15 +26,15 @@ typedef struct ThpDemuxContext { int version; - int first_frame; - int first_framesz; - int last_frame; + unsigned first_frame; + unsigned first_framesz; + unsigned last_frame; int compoff; - int framecnt; + unsigned framecnt; AVRational fps; - int frame; - int next_frame; - int next_framesz; + unsigned frame; + int64_t next_frame; + unsigned next_framesz; int video_stream_index; int audio_stream_index; int compcount; @@ -47,11 +47,16 @@ typedef struct ThpDemuxContext { static int thp_probe(AVProbeData *p) { + double d; /* check file header */ - if (AV_RL32(p->buf) == MKTAG('T', 'H', 'P', '\0')) - return AVPROBE_SCORE_MAX; - else + if (AV_RL32(p->buf) != MKTAG('T', 'H', 'P', '\0')) return 0; + + d = av_int2float(AV_RB32(p->buf + 16)); + if (d < 0.1 || d > 1000 || isnan(d)) + return AVPROBE_SCORE_MAX/4; + + return AVPROBE_SCORE_MAX; } static int thp_read_header(AVFormatContext *s) @@ -109,7 +114,6 @@ static int thp_read_header(AVFormatContext *s) st->codec->codec_tag = 0; /* no fourcc */ st->codec->width = avio_rb32(pb); st->codec->height = avio_rb32(pb); - st->codec->sample_rate = av_q2d(thp->fps); st->nb_frames = st->duration = thp->framecnt; thp->vst = st; @@ -158,7 +162,7 @@ static int thp_read_packet(AVFormatContext *s, avio_seek(pb, thp->next_frame, SEEK_SET); /* Locate the next frame and read out its size. */ - thp->next_frame += thp->next_framesz; + thp->next_frame += FFMAX(thp->next_framesz, 1); thp->next_framesz = avio_rb32(pb); avio_rb32(pb); /* Previous total size. */ diff --git a/ffmpeg/libavformat/tls.c b/ffmpeg/libavformat/tls.c index 2c85d1d..5da82db 100644 --- a/ffmpeg/libavformat/tls.c +++ b/ffmpeg/libavformat/tls.c @@ -2,29 +2,31 @@ * TLS/SSL Protocol * Copyright (c) 2011 Martin Storsjo * - * 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 */ #include "avformat.h" #include "url.h" #include "libavutil/avstring.h" +#include "libavutil/opt.h" #include "libavutil/parseutils.h" #if CONFIG_GNUTLS #include <gnutls/gnutls.h> +#include <gnutls/x509.h> #define TLS_read(c, buf, size) gnutls_record_recv(c->session, buf, size) #define TLS_write(c, buf, size) gnutls_record_send(c->session, buf, size) #define TLS_shutdown(c) gnutls_bye(c->session, GNUTLS_SHUT_RDWR) @@ -66,14 +68,46 @@ typedef struct { SSL *ssl; #endif int fd; + char *ca_file; + int verify; + char *cert_file; + char *key_file; + int listen; } TLSContext; +#define OFFSET(x) offsetof(TLSContext, x) +#define D AV_OPT_FLAG_DECODING_PARAM +#define E AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + {"ca_file", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E }, + {"cafile", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E }, + {"tls_verify", "Verify the peer certificate", OFFSET(verify), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + {"cert_file", "Certificate file", OFFSET(cert_file), AV_OPT_TYPE_STRING, .flags = D|E }, + {"key_file", "Private key file", OFFSET(key_file), AV_OPT_TYPE_STRING, .flags = D|E }, + {"listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + { NULL } +}; + +static const AVClass tls_class = { + .class_name = "tls", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + static int do_tls_poll(URLContext *h, int ret) { TLSContext *c = h->priv_data; struct pollfd p = { c->fd, 0, 0 }; #if CONFIG_GNUTLS - if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED) { + switch (ret) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + break; + case GNUTLS_E_WARNING_ALERT_RECEIVED: + av_log(h, AV_LOG_WARNING, "%s\n", gnutls_strerror(ret)); + break; + default: av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret)); return AVERROR(EIO); } @@ -107,52 +141,26 @@ static int do_tls_poll(URLContext *h, int ret) static void set_options(URLContext *h, const char *uri) { TLSContext *c = h->priv_data; - char buf[1024], key[1024]; - int has_cert, has_key, verify = 0; -#if CONFIG_GNUTLS - int ret; -#endif + char buf[1024]; const char *p = strchr(uri, '?'); if (!p) return; - if (av_find_info_tag(buf, sizeof(buf), "cafile", p)) { -#if CONFIG_GNUTLS - ret = gnutls_certificate_set_x509_trust_file(c->cred, buf, GNUTLS_X509_FMT_PEM); - if (ret < 0) - av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret)); -#elif CONFIG_OPENSSL - if (!SSL_CTX_load_verify_locations(c->ctx, buf, NULL)) - av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL)); -#endif - } + if (!c->ca_file && av_find_info_tag(buf, sizeof(buf), "cafile", p)) + c->ca_file = av_strdup(buf); - if (av_find_info_tag(buf, sizeof(buf), "verify", p)) { + if (!c->verify && av_find_info_tag(buf, sizeof(buf), "verify", p)) { char *endptr = NULL; - verify = strtol(buf, &endptr, 10); + c->verify = strtol(buf, &endptr, 10); if (buf == endptr) - verify = 1; + c->verify = 1; } - has_cert = av_find_info_tag(buf, sizeof(buf), "cert", p); - has_key = av_find_info_tag(key, sizeof(key), "key", p); -#if CONFIG_GNUTLS - if (has_cert && has_key) { - ret = gnutls_certificate_set_x509_key_file(c->cred, buf, key, GNUTLS_X509_FMT_PEM); - if (ret < 0) - av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret)); - } else if (has_cert ^ has_key) { - av_log(h, AV_LOG_ERROR, "cert and key required\n"); - } - gnutls_certificate_set_verify_flags(c->cred, verify); -#elif CONFIG_OPENSSL - if (has_cert && !SSL_CTX_use_certificate_chain_file(c->ctx, buf)) - av_log(h, AV_LOG_ERROR, "SSL_CTX_use_certificate_chain_file %s\n", ERR_error_string(ERR_get_error(), NULL)); - if (has_key && !SSL_CTX_use_PrivateKey_file(c->ctx, key, SSL_FILETYPE_PEM)) - av_log(h, AV_LOG_ERROR, "SSL_CTX_use_PrivateKey_file %s\n", ERR_error_string(ERR_get_error(), NULL)); - if (verify) - SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); -#endif + if (!c->cert_file && av_find_info_tag(buf, sizeof(buf), "cert", p)) + c->cert_file = av_strdup(buf); + + if (!c->key_file && av_find_info_tag(buf, sizeof(buf), "key", p)) + c->key_file = av_strdup(buf); } static int tls_open(URLContext *h, const char *uri, int flags) @@ -160,20 +168,22 @@ static int tls_open(URLContext *h, const char *uri, int flags) TLSContext *c = h->priv_data; int ret; int port; - char buf[200], host[200], path[1024]; + char buf[200], host[200], opts[50] = ""; int numerichost = 0; struct addrinfo hints = { 0 }, *ai = NULL; const char *proxy_path; int use_proxy; - int server = 0; const char *p = strchr(uri, '?'); - if (p && av_find_info_tag(buf, sizeof(buf), "listen", p)) - server = 1; ff_tls_init(); - av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), uri); - ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", path); + if(p && av_find_info_tag(buf, sizeof(buf), "listen", p)) + c->listen = 1; + if (c->listen) + snprintf(opts, sizeof(opts), "?listen=1"); + + av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, uri); + ff_url_join(buf, sizeof(buf), "tcp", NULL, host, port, "%s", opts); hints.ai_flags = AI_NUMERICHOST; if (!getaddrinfo(host, NULL, &hints, &ai)) { @@ -203,11 +213,35 @@ static int tls_open(URLContext *h, const char *uri, int flags) c->fd = ffurl_get_file_handle(c->tcp); #if CONFIG_GNUTLS - gnutls_init(&c->session, server ? GNUTLS_SERVER : GNUTLS_CLIENT); - if (!numerichost) + gnutls_init(&c->session, c->listen ? GNUTLS_SERVER : GNUTLS_CLIENT); + if (!c->listen && !numerichost) gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host)); gnutls_certificate_allocate_credentials(&c->cred); set_options(h, uri); + if (c->ca_file) { + ret = gnutls_certificate_set_x509_trust_file(c->cred, c->ca_file, GNUTLS_X509_FMT_PEM); + if (ret < 0) + av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret)); + } +#if GNUTLS_VERSION_MAJOR >= 3 + else + gnutls_certificate_set_x509_system_trust(c->cred); +#endif + gnutls_certificate_set_verify_flags(c->cred, c->verify ? + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT : 0); + if (c->cert_file && c->key_file) { + ret = gnutls_certificate_set_x509_key_file(c->cred, + c->cert_file, c->key_file, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + av_log(h, AV_LOG_ERROR, + "Unable to set cert/key files %s and %s: %s\n", + c->cert_file, c->key_file, gnutls_strerror(ret)); + ret = AVERROR(EIO); + goto fail; + } + } else if (c->cert_file || c->key_file) + av_log(h, AV_LOG_ERROR, "cert and key required\n"); gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred); gnutls_transport_set_ptr(c->session, (gnutls_transport_ptr_t) (intptr_t) c->fd); @@ -219,14 +253,66 @@ static int tls_open(URLContext *h, const char *uri, int flags) if ((ret = do_tls_poll(h, ret)) < 0) goto fail; } + if (c->verify) { + unsigned int status, cert_list_size; + gnutls_x509_crt_t cert; + const gnutls_datum_t *cert_list; + if ((ret = gnutls_certificate_verify_peers2(c->session, &status)) < 0) { + av_log(h, AV_LOG_ERROR, "Unable to verify peer certificate: %s\n", + gnutls_strerror(ret)); + ret = AVERROR(EIO); + goto fail; + } + if (status & GNUTLS_CERT_INVALID) { + av_log(h, AV_LOG_ERROR, "Peer certificate failed verification\n"); + ret = AVERROR(EIO); + goto fail; + } + if (gnutls_certificate_type_get(c->session) != GNUTLS_CRT_X509) { + av_log(h, AV_LOG_ERROR, "Unsupported certificate type\n"); + ret = AVERROR(EIO); + goto fail; + } + gnutls_x509_crt_init(&cert); + cert_list = gnutls_certificate_get_peers(c->session, &cert_list_size); + gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER); + ret = gnutls_x509_crt_check_hostname(cert, host); + gnutls_x509_crt_deinit(cert); + if (!ret) { + av_log(h, AV_LOG_ERROR, + "The certificate's owner does not match hostname %s\n", host); + ret = AVERROR(EIO); + goto fail; + } + } #elif CONFIG_OPENSSL - c->ctx = SSL_CTX_new(server ? TLSv1_server_method() : TLSv1_client_method()); + c->ctx = SSL_CTX_new(c->listen ? TLSv1_server_method() : TLSv1_client_method()); if (!c->ctx) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); ret = AVERROR(EIO); goto fail; } set_options(h, uri); + if (c->ca_file) { + if (!SSL_CTX_load_verify_locations(c->ctx, c->ca_file, NULL)) + av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL)); + } + if (c->cert_file && !SSL_CTX_use_certificate_chain_file(c->ctx, c->cert_file)) { + av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n", + c->cert_file, ERR_error_string(ERR_get_error(), NULL)); + ret = AVERROR(EIO); + goto fail; + } + if (c->key_file && !SSL_CTX_use_PrivateKey_file(c->ctx, c->key_file, SSL_FILETYPE_PEM)) { + av_log(h, AV_LOG_ERROR, "Unable to load key file %s: %s\n", + c->key_file, ERR_error_string(ERR_get_error(), NULL)); + ret = AVERROR(EIO); + goto fail; + } + // Note, this doesn't check that the peer certificate actually matches + // the requested hostname. + if (c->verify) + SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); c->ssl = SSL_new(c->ctx); if (!c->ssl) { av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); @@ -234,10 +320,10 @@ static int tls_open(URLContext *h, const char *uri, int flags) goto fail; } SSL_set_fd(c->ssl, c->fd); - if (!server && !numerichost) + if (!c->listen && !numerichost) SSL_set_tlsext_host_name(c->ssl, host); while (1) { - ret = server ? SSL_accept(c->ssl) : SSL_connect(c->ssl); + ret = c->listen ? SSL_accept(c->ssl) : SSL_connect(c->ssl); if (ret > 0) break; if (ret == 0) { @@ -306,4 +392,5 @@ URLProtocol ff_tls_protocol = { .url_close = tls_close, .priv_data_size = sizeof(TLSContext), .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &tls_class, }; diff --git a/ffmpeg/libavformat/tta.c b/ffmpeg/libavformat/tta.c index 445389e..7174fd5 100644 --- a/ffmpeg/libavformat/tta.c +++ b/ffmpeg/libavformat/tta.c @@ -20,9 +20,12 @@ */ #include "libavcodec/get_bits.h" +#include "apetag.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "id3v1.h" +#include "libavutil/crc.h" #include "libavutil/dict.h" typedef struct { @@ -31,12 +34,20 @@ typedef struct { int last_frame_size; } TTAContext; -static int tta_probe(AVProbeData *p) +static unsigned long tta_check_crc(unsigned long checksum, const uint8_t *buf, + unsigned int len) { - const uint8_t *d = p->buf; + return av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), checksum, buf, len); +} - if (d[0] == 'T' && d[1] == 'T' && d[2] == 'A' && d[3] == '1') - return 80; +static int tta_probe(AVProbeData *p) +{ + if (AV_RL32(&p->buf[0]) == MKTAG('T', 'T', 'A', '1') && + (AV_RL16(&p->buf[4]) == 1 || AV_RL16(&p->buf[4]) == 2) && + AV_RL16(&p->buf[6]) > 0 && + AV_RL16(&p->buf[8]) > 0 && + AV_RL32(&p->buf[10]) > 0) + return AVPROBE_SCORE_EXTENSION + 30; return 0; } @@ -46,14 +57,14 @@ static int tta_read_header(AVFormatContext *s) AVStream *st; int i, channels, bps, samplerate; uint64_t framepos, start_offset; - uint32_t datalen; + uint32_t nb_samples, crc; - if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) - ff_id3v1_read(s); + ff_id3v1_read(s); start_offset = avio_tell(s->pb); + ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX); if (avio_rl32(s->pb) != AV_RL32("TTA1")) - return -1; // not tta file + return AVERROR_INVALIDDATA; avio_skip(s->pb, 2); // FIXME: flags channels = avio_rl16(s->pb); @@ -61,27 +72,31 @@ static int tta_read_header(AVFormatContext *s) samplerate = avio_rl32(s->pb); if(samplerate <= 0 || samplerate > 1000000){ av_log(s, AV_LOG_ERROR, "nonsense samplerate\n"); - return -1; + return AVERROR_INVALIDDATA; } - datalen = avio_rl32(s->pb); - if (!datalen) { - av_log(s, AV_LOG_ERROR, "invalid datalen\n"); + nb_samples = avio_rl32(s->pb); + if (!nb_samples) { + av_log(s, AV_LOG_ERROR, "invalid number of samples\n"); return AVERROR_INVALIDDATA; } - avio_skip(s->pb, 4); // header crc + crc = ffio_get_checksum(s->pb) ^ UINT32_MAX; + if (crc != avio_rl32(s->pb)) { + av_log(s, AV_LOG_ERROR, "Header CRC error\n"); + return AVERROR_INVALIDDATA; + } c->frame_size = samplerate * 256 / 245; - c->last_frame_size = datalen % c->frame_size; + c->last_frame_size = nb_samples % c->frame_size; if (!c->last_frame_size) c->last_frame_size = c->frame_size; - c->totalframes = datalen / c->frame_size + (c->last_frame_size < c->frame_size); + c->totalframes = nb_samples / c->frame_size + (c->last_frame_size < c->frame_size); c->currentframe = 0; if(c->totalframes >= UINT_MAX/sizeof(uint32_t) || c->totalframes <= 0){ av_log(s, AV_LOG_ERROR, "totalframes %d invalid\n", c->totalframes); - return -1; + return AVERROR_INVALIDDATA; } st = avformat_new_stream(s, NULL); @@ -90,17 +105,28 @@ static int tta_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, samplerate); st->start_time = 0; - st->duration = datalen; + st->duration = nb_samples; framepos = avio_tell(s->pb) + 4*c->totalframes + 4; + if (ff_alloc_extradata(st->codec, avio_tell(s->pb) - start_offset)) + return AVERROR(ENOMEM); + + avio_seek(s->pb, start_offset, SEEK_SET); + avio_read(s->pb, st->codec->extradata, st->codec->extradata_size); + + ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX); for (i = 0; i < c->totalframes; i++) { uint32_t size = avio_rl32(s->pb); av_add_index_entry(st, framepos, i * c->frame_size, size, 0, AVINDEX_KEYFRAME); framepos += size; } - avio_skip(s->pb, 4); // seektable crc + crc = ffio_get_checksum(s->pb) ^ UINT32_MAX; + if (crc != avio_rl32(s->pb)) { + av_log(s, AV_LOG_ERROR, "Seek table CRC error\n"); + return AVERROR_INVALIDDATA; + } st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = AV_CODEC_ID_TTA; @@ -108,19 +134,11 @@ static int tta_read_header(AVFormatContext *s) st->codec->sample_rate = samplerate; st->codec->bits_per_coded_sample = bps; - st->codec->extradata_size = avio_tell(s->pb) - start_offset; - if(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ - //this check is redundant as avio_read should fail - av_log(s, AV_LOG_ERROR, "extradata_size too large\n"); - return -1; - } - st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { - st->codec->extradata_size = 0; - return AVERROR(ENOMEM); + if (s->pb->seekable) { + int64_t pos = avio_tell(s->pb); + ff_ape_parse_tag(s); + avio_seek(s->pb, pos, SEEK_SET); } - avio_seek(s->pb, start_offset, SEEK_SET); - avio_read(s->pb, st->codec->extradata, st->codec->extradata_size); return 0; } diff --git a/ffmpeg/libavformat/tty.c b/ffmpeg/libavformat/tty.c index 9b3fa0a..3afb9b2 100644 --- a/ffmpeg/libavformat/tty.c +++ b/ffmpeg/libavformat/tty.c @@ -38,8 +38,8 @@ typedef struct { AVClass *class; int chars_per_frame; uint64_t fsize; /**< file size less metadata buffer */ - char *video_size;/**< A string describing video size, set by a private option. */ - char *framerate; /**< Set by a private option. */ + int width, height; /**< Set by a private option. */ + AVRational framerate; /**< Set by a private option. */ } TtyDemuxContext; /** @@ -75,9 +75,8 @@ static int efi_read(AVFormatContext *avctx, uint64_t start_pos) static int read_header(AVFormatContext *avctx) { TtyDemuxContext *s = avctx->priv_data; - int width = 0, height = 0, ret = 0; + int ret = 0; AVStream *st = avformat_new_stream(avctx, NULL); - AVRational framerate; if (!st) { ret = AVERROR(ENOMEM); @@ -87,18 +86,10 @@ static int read_header(AVFormatContext *avctx) st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_ANSI; - if (s->video_size && (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) { - av_log (avctx, AV_LOG_ERROR, "Couldn't parse video size.\n"); - goto fail; - } - if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s->framerate); - goto fail; - } - st->codec->width = width; - st->codec->height = height; - avpriv_set_pts_info(st, 60, framerate.den, framerate.num); - st->avg_frame_rate = framerate; + st->codec->width = s->width; + st->codec->height = s->height; + avpriv_set_pts_info(st, 60, s->framerate.den, s->framerate.num); + st->avg_frame_rate = s->framerate; /* simulate tty display speed */ s->chars_per_frame = FFMAX(av_q2d(st->time_base)*s->chars_per_frame, 1); @@ -146,8 +137,8 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt) #define DEC AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "chars_per_frame", "", offsetof(TtyDemuxContext, chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM}, - { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, - { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC }, + { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, + { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC }, { NULL }, }; diff --git a/ffmpeg/libavformat/udp.c b/ffmpeg/libavformat/udp.c index e8a01db..047ff7c 100644 --- a/ffmpeg/libavformat/udp.c +++ b/ffmpeg/libavformat/udp.c @@ -84,23 +84,24 @@ typedef struct { char *local_addr; int packet_size; int timeout; + struct sockaddr_storage local_addr_storage; } UDPContext; #define OFFSET(x) offsetof(UDPContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { -{"buffer_size", "Socket buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, -{"localport", "Set local port to bind to", OFFSET(local_port), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, -{"localaddr", "Choose local IP address", OFFSET(local_addr), AV_OPT_TYPE_STRING, {.str = ""}, 0, 0, D|E }, -{"pkt_size", "Set size of UDP packets", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = 1472}, 0, INT_MAX, D|E }, -{"reuse", "Explicitly allow or disallow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, -{"ttl", "Set the time to live value (for multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, {.i64 = 16}, 0, INT_MAX, E }, -{"connect", "Should connect() be called on socket", OFFSET(is_connected), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, +{"buffer_size", "set packet buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, +{"localport", "set local port to bind to", OFFSET(local_port), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E }, +{"localaddr", "choose local IP address", OFFSET(local_addr), AV_OPT_TYPE_STRING, {.str = ""}, 0, 0, D|E }, +{"pkt_size", "set size of UDP packets", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = 1472}, 0, INT_MAX, D|E }, +{"reuse", "explicitly allow or disallow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, +{"ttl", "set the time to live value (for multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, {.i64 = 16}, 0, INT_MAX, E }, +{"connect", "set if connect() should be called on socket", OFFSET(is_connected), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D|E }, /* TODO 'sources', 'block' option */ -{"fifo_size", "Set the UDP receiving circular buffer size, expressed as a number of packets with size of 188 bytes", OFFSET(circular_buffer_size), AV_OPT_TYPE_INT, {.i64 = 7*4096}, 0, INT_MAX, D }, -{"overrun_nonfatal", "Survive in case of UDP receiving circular buffer overrun", OFFSET(overrun_nonfatal), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, -{"timeout", "In read mode: if no data arrived in more than this time interval, raise error", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, +{"fifo_size", "set the UDP receiving circular buffer size, expressed as a number of packets with size of 188 bytes", OFFSET(circular_buffer_size), AV_OPT_TYPE_INT, {.i64 = 7*4096}, 0, INT_MAX, D }, +{"overrun_nonfatal", "survive in case of UDP receiving circular buffer overrun", OFFSET(overrun_nonfatal), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D }, +{"timeout", "set raise error timeout (only in read mode)", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D }, {NULL} }; @@ -140,14 +141,17 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL, return 0; } -static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) +static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,struct sockaddr *local_addr) { #ifdef IP_ADD_MEMBERSHIP if (addr->sa_family == AF_INET) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - mreq.imr_interface.s_addr= INADDR_ANY; + if (local_addr) + mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr; + else + mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)"); return -1; @@ -169,14 +173,17 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) return 0; } -static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) +static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,struct sockaddr *local_addr) { #ifdef IP_DROP_MEMBERSHIP if (addr->sa_family == AF_INET) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - mreq.imr_interface.s_addr= INADDR_ANY; + if (local_addr) + mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr; + else + mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP)"); return -1; @@ -237,7 +244,7 @@ static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr, int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0, SOCK_DGRAM, AF_UNSPEC, - AI_NUMERICHOST); + 0); if (!sourceaddr) return AVERROR(ENOENT); @@ -267,7 +274,7 @@ static int udp_set_multicast_sources(int sockfd, struct sockaddr *addr, struct ip_mreq_source mreqs; struct addrinfo *sourceaddr = udp_resolve_host(sources[i], 0, SOCK_DGRAM, AF_UNSPEC, - AI_NUMERICHOST); + 0); if (!sourceaddr) return AVERROR(ENOENT); if (sourceaddr->ai_addr->sa_family != AF_INET) { @@ -326,7 +333,7 @@ static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, if (res0 == 0) goto fail; for (res = res0; res; res=res->ai_next) { - udp_fd = socket(res->ai_family, SOCK_DGRAM, 0); + udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0); if (udp_fd != -1) break; log_net_error(NULL, AV_LOG_ERROR, "socket"); } @@ -494,6 +501,27 @@ end: } #endif +static int parse_source_list(char *buf, char **sources, int *num_sources, + int max_sources) +{ + char *source_start; + + source_start = buf; + while (1) { + char *next = strchr(source_start, ','); + if (next) + *next = '\0'; + sources[*num_sources] = av_strdup(source_start); + if (!sources[*num_sources]) + return AVERROR(ENOMEM); + source_start = next + 1; + (*num_sources)++; + if (*num_sources >= max_sources || !next) + break; + } + return 0; +} + /* put it in UDP context */ /* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) @@ -507,8 +535,8 @@ static int udp_open(URLContext *h, const char *uri, int flags) struct sockaddr_storage my_addr; socklen_t len; int reuse_specified = 0; - int i, include = 0, num_sources = 0; - char *sources[32]; + int i, num_include_sources = 0, num_exclude_sources = 0; + char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; @@ -562,31 +590,26 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } - if (av_find_info_tag(buf, sizeof(buf), "sources", p)) - include = 1; - if (include || av_find_info_tag(buf, sizeof(buf), "block", p)) { - char *source_start; - - source_start = buf; - while (1) { - char *next = strchr(source_start, ','); - if (next) - *next = '\0'; - sources[num_sources] = av_strdup(source_start); - if (!sources[num_sources]) - goto fail; - source_start = next + 1; - num_sources++; - if (num_sources >= FF_ARRAY_ELEMS(sources) || !next) - break; - } + if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { + if (parse_source_list(buf, include_sources, &num_include_sources, + FF_ARRAY_ELEMS(include_sources))) + goto fail; + } + if (av_find_info_tag(buf, sizeof(buf), "block", p)) { + if (parse_source_list(buf, exclude_sources, &num_exclude_sources, + FF_ARRAY_ELEMS(exclude_sources))) + goto fail; } if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p)) s->timeout = strtol(buf, NULL, 10); } /* handling needed to support options picking from both AVOption and URL */ s->circular_buffer_size *= 188; - h->max_packet_size = s->packet_size; + if (flags & AVIO_FLAG_WRITE) { + h->max_packet_size = s->packet_size; + } else { + h->max_packet_size = UDP_MAX_PKT_SIZE; + } h->rw_timeout = s->timeout; /* fill the dest addr */ @@ -608,6 +631,8 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (udp_fd < 0) goto fail; + s->local_addr_storage=my_addr; //store for future multicast join + /* Follow the requested reuse option, unless it's multicast in which * case enable reuse unless explicitly disabled. */ @@ -644,20 +669,20 @@ static int udp_open(URLContext *h, const char *uri, int flags) } if (h->flags & AVIO_FLAG_READ) { /* input */ - if (num_sources == 0 || !include) { - if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) - goto fail; - - if (num_sources) { - if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 0) < 0) - goto fail; - } - } else if (include && num_sources) { - if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, sources, num_sources, 1) < 0) + if (num_include_sources && num_exclude_sources) { + av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); + goto fail; + } + if (num_include_sources) { + if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0) goto fail; } else { - av_log(NULL, AV_LOG_ERROR, "invalid udp settings: inclusive multicast but no sources given\n"); - goto fail; + if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0) + goto fail; + } + if (num_exclude_sources) { + if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, exclude_sources, num_exclude_sources, 0) < 0) + goto fail; } } } @@ -686,8 +711,10 @@ static int udp_open(URLContext *h, const char *uri, int flags) } } - for (i = 0; i < num_sources; i++) - av_freep(&sources[i]); + for (i = 0; i < num_include_sources; i++) + av_freep(&include_sources[i]); + for (i = 0; i < num_exclude_sources; i++) + av_freep(&exclude_sources[i]); s->udp_fd = udp_fd; @@ -727,8 +754,10 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (udp_fd >= 0) closesocket(udp_fd); av_fifo_free(s->fifo); - for (i = 0; i < num_sources; i++) - av_freep(&sources[i]); + for (i = 0; i < num_include_sources; i++) + av_freep(&include_sources[i]); + for (i = 0; i < num_exclude_sources; i++) + av_freep(&exclude_sources[i]); return AVERROR(EIO); } @@ -818,7 +847,7 @@ static int udp_close(URLContext *h) int ret; if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) - udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); + udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage); closesocket(s->udp_fd); #if HAVE_PTHREAD_CANCEL if (s->thread_started) { diff --git a/ffmpeg/libavformat/url-test.c b/ffmpeg/libavformat/url-test.c index ee5f06e..a1da82e 100644 --- a/ffmpeg/libavformat/url-test.c +++ b/ffmpeg/libavformat/url-test.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "internal.h" +#include "url.h" static void test(const char *base, const char *rel) { diff --git a/ffmpeg/libavformat/url.h b/ffmpeg/libavformat/url.h index 5f75dc9..712ea0f 100644 --- a/ffmpeg/libavformat/url.h +++ b/ffmpeg/libavformat/url.h @@ -101,7 +101,7 @@ typedef struct URLProtocol { * is to be opened * @param int_cb interrupt callback to use for the URLContext, may be * NULL - * @return 0 in case of success, a negative value corresponding to an + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int ffurl_alloc(URLContext **puc, const char *filename, int flags, @@ -130,7 +130,7 @@ int ffurl_connect(URLContext *uc, AVDictionary **options); * @param options A dictionary filled with protocol-private options. On return * this parameter will be destroyed and replaced with a dict containing options * that were not found. May be NULL. - * @return 0 in case of success, a negative value corresponding to an + * @return >= 0 in case of success, a negative value corresponding to an * AVERROR code in case of failure */ int ffurl_open(URLContext **puc, const char *filename, int flags, @@ -226,10 +226,8 @@ int ffurl_shutdown(URLContext *h, int flags); /** * Register the URLProtocol protocol. - * - * @param size the size of the URLProtocol struct referenced */ -int ffurl_register_protocol(URLProtocol *protocol, int size); +int ffurl_register_protocol(URLProtocol *protocol); /** * Check if the user has requested to interrup a blocking function @@ -248,4 +246,41 @@ URLProtocol *ffurl_protocol_next(URLProtocol *prev); int ff_udp_set_remote_url(URLContext *h, const char *uri); int ff_udp_get_local_port(URLContext *h); +/** + * Assemble a URL string from components. This is the reverse operation + * of av_url_split. + * + * Note, this requires networking to be initialized, so the caller must + * ensure ff_network_init has been called. + * + * @see av_url_split + * + * @param str the buffer to fill with the url + * @param size the size of the str buffer + * @param proto the protocol identifier, if null, the separator + * after the identifier is left out, too + * @param authorization an optional authorization string, may be null. + * An empty string is treated the same as a null string. + * @param hostname the host name string + * @param port the port number, left out from the string if negative + * @param fmt a generic format string for everything to add after the + * host/port, may be null + * @return the number of characters written to the destination buffer + */ +int ff_url_join(char *str, int size, const char *proto, + const char *authorization, const char *hostname, + int port, const char *fmt, ...) av_printf_format(7, 8); + +/** + * Convert a relative url into an absolute url, given a base url. + * + * @param buf the buffer where output absolute url is written + * @param size the size of buf + * @param base the base url, may be equal to buf. + * @param rel the new url, which is interpreted relative to base + */ +void ff_make_absolute_url(char *buf, int size, const char *base, + const char *rel); + + #endif /* AVFORMAT_URL_H */ diff --git a/ffmpeg/libavformat/utils.c b/ffmpeg/libavformat/utils.c index f9acc0e..40d886f 100644 --- a/ffmpeg/libavformat/utils.c +++ b/ffmpeg/libavformat/utils.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* #define DEBUG */ +#include <stdint.h> #include "avformat.h" #include "avio_internal.h" @@ -27,9 +27,9 @@ #include "libavcodec/internal.h" #include "libavcodec/raw.h" #include "libavcodec/bytestream.h" -#include "libavutil/avassert.h" #include "libavutil/opt.h" #include "libavutil/dict.h" +#include "libavutil/internal.h" #include "libavutil/pixdesc.h" #include "metadata.h" #include "id3v2.h" @@ -99,156 +99,34 @@ static int64_t wrap_timestamp(AVStream *st, int64_t timestamp) return timestamp; } -#define MAKE_ACCESSORS(str, name, type, field) \ - type av_##name##_get_##field(const str *s) { return s->field; } \ - void av_##name##_set_##field(str *s, type v) { s->field = v; } - MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec) +MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec) -/** head of registered input format linked list */ -static AVInputFormat *first_iformat = NULL; -/** head of registered output format linked list */ -static AVOutputFormat *first_oformat = NULL; - -AVInputFormat *av_iformat_next(AVInputFormat *f) -{ - if(f) return f->next; - else return first_iformat; -} - -AVOutputFormat *av_oformat_next(AVOutputFormat *f) -{ - if(f) return f->next; - else return first_oformat; -} - -void av_register_input_format(AVInputFormat *format) -{ - AVInputFormat **p; - p = &first_iformat; - while (*p != NULL) p = &(*p)->next; - *p = format; - format->next = NULL; -} - -void av_register_output_format(AVOutputFormat *format) -{ - AVOutputFormat **p; - p = &first_oformat; - while (*p != NULL) p = &(*p)->next; - *p = format; - format->next = NULL; -} - -int av_match_ext(const char *filename, const char *extensions) +static AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id) { - const char *ext, *p; - char ext1[32], *q; - - if(!filename) - return 0; + if (st->codec->codec) + return st->codec->codec; - ext = strrchr(filename, '.'); - if (ext) { - ext++; - p = extensions; - for(;;) { - q = ext1; - while (*p != '\0' && *p != ',' && q-ext1<sizeof(ext1)-1) - *q++ = *p++; - *q = '\0'; - if (!av_strcasecmp(ext1, ext)) - return 1; - if (*p == '\0') - break; - p++; - } - } - return 0; -} - -static int match_format(const char *name, const char *names) -{ - const char *p; - int len, namelen; - - if (!name || !names) - return 0; - - namelen = strlen(name); - while ((p = strchr(names, ','))) { - len = FFMAX(p - names, namelen); - if (!av_strncasecmp(name, names, len)) - return 1; - names = p+1; - } - return !av_strcasecmp(name, names); -} - -AVOutputFormat *av_guess_format(const char *short_name, const char *filename, - const char *mime_type) -{ - AVOutputFormat *fmt = NULL, *fmt_found; - int score_max, score; - - /* specific test for image sequences */ -#if CONFIG_IMAGE2_MUXER - if (!short_name && filename && - av_filename_number_test(filename) && - ff_guess_image2_codec(filename) != AV_CODEC_ID_NONE) { - return av_guess_format("image2", NULL, NULL); - } -#endif - /* Find the proper file type. */ - fmt_found = NULL; - score_max = 0; - while ((fmt = av_oformat_next(fmt))) { - score = 0; - if (fmt->name && short_name && match_format(short_name, fmt->name)) - score += 100; - if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type)) - score += 10; - if (filename && fmt->extensions && - av_match_ext(filename, fmt->extensions)) { - score += 5; - } - if (score > score_max) { - score_max = score; - fmt_found = fmt; - } + switch(st->codec->codec_type){ + case AVMEDIA_TYPE_VIDEO: + if(s->video_codec) return s->video_codec; + break; + case AVMEDIA_TYPE_AUDIO: + if(s->audio_codec) return s->audio_codec; + break; + case AVMEDIA_TYPE_SUBTITLE: + if(s->subtitle_codec) return s->subtitle_codec; + break; } - return fmt_found; -} - -enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, - const char *filename, const char *mime_type, enum AVMediaType type){ - if(type == AVMEDIA_TYPE_VIDEO){ - enum AVCodecID codec_id= AV_CODEC_ID_NONE; -#if CONFIG_IMAGE2_MUXER - if(!strcmp(fmt->name, "image2") || !strcmp(fmt->name, "image2pipe")){ - codec_id= ff_guess_image2_codec(filename); - } -#endif - if(codec_id == AV_CODEC_ID_NONE) - codec_id= fmt->video_codec; - return codec_id; - }else if(type == AVMEDIA_TYPE_AUDIO) - return fmt->audio_codec; - else if (type == AVMEDIA_TYPE_SUBTITLE) - return fmt->subtitle_codec; - else - return AV_CODEC_ID_NONE; + return avcodec_find_decoder(codec_id); } -AVInputFormat *av_find_input_format(const char *short_name) +int av_format_get_probe_score(const AVFormatContext *s) { - AVInputFormat *fmt = NULL; - while ((fmt = av_iformat_next(fmt))) { - if (match_format(short_name, fmt->name)) - return fmt; - } - return NULL; + return s->probe_score; } /* an arbitrarily chosen "sane" max packet size -- 50M */ @@ -280,7 +158,7 @@ int ffio_limit(AVIOContext *s, int size) */ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size) { - int orig_pos = pkt->pos; // av_grow_packet might reset pos + int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos int orig_size = pkt->size; int ret; @@ -372,10 +250,10 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score if (fmt1->read_probe) { score = fmt1->read_probe(&lpd); if(fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) - score = FFMAX(score, nodat ? AVPROBE_SCORE_MAX/4-1 : 1); + score = FFMAX(score, nodat ? AVPROBE_SCORE_EXTENSION / 2 - 1 : 1); } else if (fmt1->extensions) { if (av_match_ext(lpd.filename, fmt1->extensions)) { - score = 50; + score = AVPROBE_SCORE_EXTENSION; } } if (score > score_max) { @@ -384,6 +262,8 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score }else if (score == score_max) fmt = NULL; } + if(nodat) + score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max); *score_ret= score_max; return fmt; @@ -458,11 +338,7 @@ int av_demuxer_open(AVFormatContext *ic){ } -/** size of probe buffer, for guessing file type from file contents */ -#define PROBE_BUF_MIN 2048 -#define PROBE_BUF_MAX (1<<20) - -int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { @@ -470,6 +346,7 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, unsigned char *buf = NULL; uint8_t *mime_type; int ret = 0, probe_size, buf_offset = 0; + int score = 0; if (!max_probe_size) { max_probe_size = PROBE_BUF_MAX; @@ -494,20 +371,15 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, for(probe_size= PROBE_BUF_MIN; probe_size<=max_probe_size && !*fmt; probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) { - int score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; - void *buftmp; if (probe_size < offset) { continue; } + score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0; /* read probe data */ - buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); - if(!buftmp){ - av_free(buf); - return AVERROR(ENOMEM); - } - buf=buftmp; + if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0) + return ret; if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset)) < 0) { /* fail if error was not end of file, otherwise, lower score */ if (ret != AVERROR_EOF) { @@ -529,6 +401,11 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, av_log(logctx, AV_LOG_WARNING, "Format %s detected only with low score of %d, misdetection possible!\n", (*fmt)->name, score); }else av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score); +#if 0 + FILE *f = fopen("probestat.tmp", "ab"); + fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename); + fclose(f); +#endif } } @@ -540,9 +417,18 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, /* rewind. reuse probe buffer to avoid seeking */ ret = ffio_rewind_with_probe_data(pb, &buf, pd.buf_size); - return ret; + return ret < 0 ? ret : score; } +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size) +{ + int ret = av_probe_input_buffer2(pb, fmt, filename, logctx, offset, max_probe_size); + return ret < 0 ? ret : 0; +} + + /* open input file and probe the format if necessary */ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options) { @@ -553,7 +439,7 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o if (s->pb) { s->flags |= AVFMT_FLAG_CUSTOM_IO; if (!s->iformat) - return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize); + return av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->probesize); else if (s->iformat->flags & AVFMT_NOFILE) av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and " "will be ignored with AVFMT_NOFILE format.\n"); @@ -562,14 +448,14 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) || (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score)))) - return 0; + return score; if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags, &s->interrupt_callback, options)) < 0) return ret; if (s->iformat) return 0; - return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize); + return av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->probesize); } static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, @@ -629,6 +515,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma if ((ret = init_input(s, filename, &tmp)) < 0) goto fail; + s->probe_score = ret; avio_skip(s->pb, s->skip_initial_bytes); /* check filename in case an image number is expected */ @@ -665,7 +552,8 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma goto fail; if (id3v2_extra_meta) { - if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac")) { + if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") || + !strcmp(s->iformat->name, "tta")) { if((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) goto fail; } else @@ -715,7 +603,7 @@ static void force_codec_ids(AVFormatContext *s, AVStream *st) } } -static void probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) +static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) { if(st->request_probe>0){ AVProbeData *pd = &st->probe_data; @@ -725,8 +613,12 @@ static void probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt) if (pkt) { uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); - if(!new_buf) + if(!new_buf) { + av_log(s, AV_LOG_WARNING, + "Failed to reallocate probe buffer for stream %d\n", + st->index); goto no_packet; + } pd->buf = new_buf; memcpy(pd->buf+pd->buf_size, pkt->data, pkt->size); pd->buf_size += pkt->size; @@ -758,11 +650,76 @@ no_packet: force_codec_ids(s, st); } } + return 0; +} + +static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index, AVPacket *pkt) +{ + int64_t ref = pkt->dts; + int i, pts_wrap_behavior; + int64_t pts_wrap_reference; + AVProgram *first_program; + + if (ref == AV_NOPTS_VALUE) + ref = pkt->pts; + if (st->pts_wrap_reference != AV_NOPTS_VALUE || st->pts_wrap_bits >= 63 || ref == AV_NOPTS_VALUE || !s->correct_ts_overflow) + return 0; + ref &= (1LL<<st->pts_wrap_bits)-1; + + // reference time stamp should be 60 s before first time stamp + pts_wrap_reference = ref - av_rescale(60, st->time_base.den, st->time_base.num); + // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset + pts_wrap_behavior = (ref < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) || + (ref < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ? + AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET; + + first_program = av_find_program_from_stream(s, NULL, stream_index); + + if (!first_program) { + int default_stream_index = av_find_default_stream_index(s); + if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) { + for (i=0; i<s->nb_streams; i++) { + s->streams[i]->pts_wrap_reference = pts_wrap_reference; + s->streams[i]->pts_wrap_behavior = pts_wrap_behavior; + } + } + else { + st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference; + st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior; + } + } + else { + AVProgram *program = first_program; + while (program) { + if (program->pts_wrap_reference != AV_NOPTS_VALUE) { + pts_wrap_reference = program->pts_wrap_reference; + pts_wrap_behavior = program->pts_wrap_behavior; + break; + } + program = av_find_program_from_stream(s, program, stream_index); + } + + // update every program with differing pts_wrap_reference + program = first_program; + while(program) { + if (program->pts_wrap_reference != pts_wrap_reference) { + for (i=0; i<program->nb_stream_indexes; i++) { + s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference; + s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior; + } + + program->pts_wrap_reference = pts_wrap_reference; + program->pts_wrap_behavior = pts_wrap_behavior; + } + program = av_find_program_from_stream(s, program, stream_index); + } + } + return 1; } int ff_read_packet(AVFormatContext *s, AVPacket *pkt) { - int ret, i; + int ret, i, err; AVStream *st; for(;;){ @@ -771,8 +728,10 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) if (pktl) { *pkt = pktl->pkt; st = s->streams[pkt->stream_index]; - if (s->raw_packet_buffer_remaining_size <= 0) - probe_codec(s, st, NULL); + if (s->raw_packet_buffer_remaining_size <= 0) { + if ((err = probe_codec(s, st, NULL)) < 0) + return err; + } if(st->request_probe <= 0){ s->raw_packet_buffer = pktl->next; s->raw_packet_buffer_remaining_size += pkt->size; @@ -791,7 +750,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->probe_packets) { - probe_codec(s, st, NULL); + if ((err = probe_codec(s, st, NULL)) < 0) + return err; } av_assert0(st->request_probe <= 0); } @@ -807,15 +767,23 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) continue; } - if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) - av_packet_merge_side_data(pkt); - if(pkt->stream_index >= (unsigned)s->nb_streams){ av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index); continue; } st= s->streams[pkt->stream_index]; + + if (update_wrap_reference(s, st, pkt->stream_index, pkt) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) { + // correct first time stamps to negative values + if (!is_relative(st->first_dts)) + st->first_dts = wrap_timestamp(st, st->first_dts); + if (!is_relative(st->start_time)) + st->start_time = wrap_timestamp(st, st->start_time); + if (!is_relative(st->cur_dts)) + st->cur_dts = wrap_timestamp(st, st->cur_dts); + } + pkt->dts = wrap_timestamp(st, pkt->dts); pkt->pts = wrap_timestamp(st, pkt->pts); @@ -831,7 +799,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); s->raw_packet_buffer_remaining_size -= pkt->size; - probe_codec(s, st, pkt); + if ((err = probe_codec(s, st, pkt)) < 0) + return err; } } @@ -870,7 +839,7 @@ int ff_get_audio_frame_size(AVCodecContext *enc, int size, int mux) if ((frame_size = av_get_audio_frame_duration(enc, size)) > 0) return frame_size; - /* fallback to using frame_size if muxing */ + /* Fall back on using frame_size if muxing. */ if (enc->frame_size > 1) return enc->frame_size; @@ -950,7 +919,7 @@ static int is_intra_only(AVCodecContext *enc){ static int has_decode_delay_been_guessed(AVStream *st) { if(st->codec->codec_id != AV_CODEC_ID_H264) return 1; - if(!st->info) // if we have left find_stream_info then nb_decoded_frames wont increase anymore for stream copy + if(!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy return 1; #if CONFIG_H264_DECODER if(st->codec->has_b_frames && @@ -974,65 +943,6 @@ static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList return NULL; } -static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index) -{ - if (s->correct_ts_overflow && st->pts_wrap_bits < 63 && - st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) { - int i; - - // reference time stamp should be 60 s before first time stamp - int64_t pts_wrap_reference = st->first_dts - av_rescale(60, st->time_base.den, st->time_base.num); - // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset - int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) || - (st->first_dts < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ? - AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET; - - AVProgram *first_program = av_find_program_from_stream(s, NULL, stream_index); - - if (!first_program) { - int default_stream_index = av_find_default_stream_index(s); - if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) { - for (i=0; i<s->nb_streams; i++) { - s->streams[i]->pts_wrap_reference = pts_wrap_reference; - s->streams[i]->pts_wrap_behavior = pts_wrap_behavior; - } - } - else { - st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference; - st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior; - } - } - else { - AVProgram *program = first_program; - while (program) { - if (program->pts_wrap_reference != AV_NOPTS_VALUE) { - pts_wrap_reference = program->pts_wrap_reference; - pts_wrap_behavior = program->pts_wrap_behavior; - break; - } - program = av_find_program_from_stream(s, program, stream_index); - } - - // update every program with differing pts_wrap_reference - program = first_program; - while(program) { - if (program->pts_wrap_reference != pts_wrap_reference) { - for (i=0; i<program->nb_stream_indexes; i++) { - s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference; - s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior; - } - - program->pts_wrap_reference = pts_wrap_reference; - program->pts_wrap_behavior = pts_wrap_behavior; - } - program = av_find_program_from_stream(s, program, stream_index); - } - } - return 1; - } - return 0; -} - static void update_initial_timestamps(AVFormatContext *s, int stream_index, int64_t dts, int64_t pts, AVPacket *pkt) { @@ -1077,15 +987,6 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, } } - if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) { - // correct first time stamps to negative values - st->first_dts = wrap_timestamp(st, st->first_dts); - st->cur_dts = wrap_timestamp(st, st->cur_dts); - pkt->dts = wrap_timestamp(st, pkt->dts); - pkt->pts = wrap_timestamp(st, pkt->pts); - pts = wrap_timestamp(st, pts); - } - if (st->start_time == AV_NOPTS_VALUE) st->start_time = pts; } @@ -1106,7 +1007,8 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st, } } if(pktl && pktl->pkt.dts != st->first_dts) { - av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s in the queue\n", av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts)); + av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s (pts %s, duration %d) in the queue\n", + av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts), av_ts2str(pktl->pkt.pts), pktl->pkt.duration); return; } if(!pktl) { @@ -1148,7 +1050,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE) pkt->dts= AV_NOPTS_VALUE; - if (st->codec->codec_id != AV_CODEC_ID_H264 && pc && pc->pict_type == AV_PICTURE_TYPE_B) + if (pc && pc->pict_type == AV_PICTURE_TYPE_B + && !st->codec->has_b_frames) //FIXME Set low_delay = 0 when has_b_frames = 1 st->codec->has_b_frames = 1; @@ -1162,7 +1065,9 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, pc && pc->pict_type != AV_PICTURE_TYPE_B) presentation_delayed = 1; - if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && st->pts_wrap_bits<63 && pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > pkt->pts){ + if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && + st->pts_wrap_bits < 63 && + pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) { if(is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > st->cur_dts) { pkt->dts -= 1LL<<st->pts_wrap_bits; } else @@ -1174,7 +1079,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, // Note, if this is misbehaving for a H.264 file then possibly presentation_delayed is not set correctly. if(delay==1 && pkt->dts == pkt->pts && pkt->dts != AV_NOPTS_VALUE && presentation_delayed){ av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts); - if(strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2")) // otherwise we discard correct timestamps for vc1-wmapro.ism + if ( strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") + && strcmp(s->iformat->name, "flv")) // otherwise we discard correct timestamps for vc1-wmapro.ism pkt->dts= AV_NOPTS_VALUE; } @@ -1198,25 +1104,6 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, pkt->dts += offset; } - if (pc && pc->dts_sync_point >= 0) { - // we have synchronization info from the parser - int64_t den = st->codec->time_base.den * (int64_t) st->time_base.num; - if (den > 0) { - int64_t num = st->codec->time_base.num * (int64_t) st->time_base.den; - if (pkt->dts != AV_NOPTS_VALUE) { - // got DTS from the stream, update reference timestamp - st->reference_dts = pkt->dts - pc->dts_ref_dts_delta * num / den; - pkt->pts = pkt->dts + pc->pts_dts_delta * num / den; - } else if (st->reference_dts != AV_NOPTS_VALUE) { - // compute DTS based on reference timestamp - pkt->dts = st->reference_dts + pc->dts_ref_dts_delta * num / den; - pkt->pts = pkt->dts + pc->pts_dts_delta * num / den; - } - if (pc->dts_sync_point > 0) - st->reference_dts = pkt->dts; // new reference - } - } - /* This may be redundant, but it should not hurt. */ if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts) presentation_delayed = 1; @@ -1338,6 +1225,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) if (!out_pkt.size) continue; + if (pkt->side_data) { + out_pkt.side_data = pkt->side_data; + out_pkt.side_data_elems = pkt->side_data_elems; + pkt->side_data = NULL; + pkt->side_data_elems = 0; + } + /* set the duration */ out_pkt.duration = 0; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { @@ -1377,8 +1271,10 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) out_pkt.buf = pkt->buf; pkt->buf = NULL; #if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS out_pkt.destruct = pkt->destruct; pkt->destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS #endif } if ((ret = av_dup_packet(&out_pkt)) < 0) @@ -1502,6 +1398,9 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) st->skip_to_keyframe = 0; if (st->skip_to_keyframe) { av_free_packet(&cur_pkt); + if (got_packet) { + *pkt = cur_pkt; + } got_packet = 0; } } @@ -1509,6 +1408,21 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (!got_packet && s->parse_queue) ret = read_from_packet_buffer(&s->parse_queue, &s->parse_queue_end, pkt); + if (ret >= 0) { + AVStream *st = s->streams[pkt->stream_index]; + if (st->skip_samples) { + uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (p) { + AV_WL32(p, st->skip_samples); + av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples); + } + st->skip_samples = 0; + } + } + + if(ret >= 0 && !(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) + av_packet_merge_side_data(pkt); + if(s->debug & FF_FDEBUG_TS) av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", pkt->stream_index, @@ -1598,13 +1512,6 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) return_packet: st = s->streams[pkt->stream_index]; - if (st->skip_samples) { - uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); - AV_WL32(p, st->skip_samples); - av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples); - st->skip_samples = 0; - } - if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) { ff_reduce_index(s, st->index); av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME); @@ -1672,7 +1579,6 @@ void ff_read_frame_flush(AVFormatContext *s) st->last_IP_pts = AV_NOPTS_VALUE; if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = RELATIVE_TS_BASE; else st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ - st->reference_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; @@ -1721,6 +1627,9 @@ int ff_add_index_entry(AVIndexEntry **index_entries, if(timestamp == AV_NOPTS_VALUE) return AVERROR(EINVAL); + if (size < 0 || size > 0x3FFFFFFF) + return AVERROR(EINVAL); + if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known timestamp -= RELATIVE_TS_BASE; @@ -1738,7 +1647,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries, if(index<0){ index= (*nb_index_entries)++; ie= &entries[index]; - assert(index==0 || ie[-1].timestamp < timestamp); + av_assert0(index==0 || ie[-1].timestamp < timestamp); }else{ ie= &entries[index]; if(ie->timestamp != timestamp){ @@ -1850,14 +1759,14 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts av_dlog(s, "using cached pos_min=0x%"PRIx64" dts_min=%s\n", pos_min, av_ts2str(ts_min)); }else{ - assert(index==0); + av_assert1(index==0); } index= av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD); - assert(index < st->nb_index_entries); + av_assert0(index < st->nb_index_entries); if(index >= 0){ e= &st->index_entries[index]; - assert(e->timestamp >= target_ts); + av_assert1(e->timestamp >= target_ts); pos_max= e->pos; ts_max= e->timestamp; pos_limit= pos_max - e->min_distance; @@ -1880,14 +1789,51 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts return 0; } +int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos, + int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )) +{ + int64_t step= 1024; + int64_t limit, ts_max; + int64_t filesize = avio_size(s->pb); + int64_t pos_max = filesize - 1; + do{ + limit = pos_max; + pos_max = FFMAX(0, (pos_max) - step); + ts_max = ff_read_timestamp(s, stream_index, &pos_max, limit, read_timestamp); + step += step; + }while(ts_max == AV_NOPTS_VALUE && 2*limit > step); + if (ts_max == AV_NOPTS_VALUE) + return -1; + + for(;;){ + int64_t tmp_pos = pos_max + 1; + int64_t tmp_ts = ff_read_timestamp(s, stream_index, &tmp_pos, INT64_MAX, read_timestamp); + if(tmp_ts == AV_NOPTS_VALUE) + break; + av_assert0(tmp_pos > pos_max); + ts_max = tmp_ts; + pos_max = tmp_pos; + if(tmp_pos >= filesize) + break; + } + + if (ts) + *ts = ts_max; + if (pos) + *pos = pos_max; + + return 0; +} + int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, int64_t pos_min, int64_t pos_max, int64_t pos_limit, int64_t ts_min, int64_t ts_max, int flags, int64_t *ts_ret, int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t )) { int64_t pos, ts; - int64_t start_pos, filesize; + int64_t start_pos; int no_change; + int ret; av_dlog(s, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts)); @@ -1904,27 +1850,8 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, } if(ts_max == AV_NOPTS_VALUE){ - int step= 1024; - filesize = avio_size(s->pb); - pos_max = filesize - 1; - do{ - pos_max = FFMAX(0, pos_max - step); - ts_max = ff_read_timestamp(s, stream_index, &pos_max, pos_max + step, read_timestamp); - step += step; - }while(ts_max == AV_NOPTS_VALUE && pos_max > 0); - if (ts_max == AV_NOPTS_VALUE) - return -1; - - for(;;){ - int64_t tmp_pos= pos_max + 1; - int64_t tmp_ts= ff_read_timestamp(s, stream_index, &tmp_pos, INT64_MAX, read_timestamp); - if(tmp_ts == AV_NOPTS_VALUE) - break; - ts_max= tmp_ts; - pos_max= tmp_pos; - if(tmp_pos >= filesize) - break; - } + if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0) + return ret; pos_limit= pos_max; } @@ -2014,6 +1941,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, in avio_seek(s->pb, pos, SEEK_SET); + s->io_repositioned = 1; + return 0; } @@ -2037,7 +1966,7 @@ static int seek_frame_generic(AVFormatContext *s, int nonkey=0; if(st->nb_index_entries){ - assert(st->index_entries); + av_assert0(st->index_entries); ie= &st->index_entries[st->nb_index_entries-1]; if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; @@ -2127,7 +2056,19 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index, int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { - int ret = seek_frame_internal(s, stream_index, timestamp, flags); + int ret; + + if (s->iformat->read_seek2 && !s->iformat->read_seek) { + int64_t min_ts = INT64_MIN, max_ts = INT64_MAX; + if ((flags & AVSEEK_FLAG_BACKWARD)) + max_ts = timestamp; + else + min_ts = timestamp; + return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts, + flags & ~AVSEEK_FLAG_BACKWARD); + } + + ret = seek_frame_internal(s, stream_index, timestamp, flags); if (ret >= 0) ret = avformat_queue_attached_pictures(s); @@ -2144,6 +2085,7 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int if(s->seek2any>0) flags |= AVSEEK_FLAG_ANY; + flags &= ~AVSEEK_FLAG_BACKWARD; if (s->iformat->read_seek2) { int ret; @@ -2171,8 +2113,8 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int //try to seek via read_timestamp() } - //Fallback to old API if new is not implemented but old is - //Note the old has somewhat different semantics + // Fall back on old API if new is not implemented but old is. + // Note the old API has somewhat different semantics. if (s->iformat->read_seek || 1) { int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0); int ret = av_seek_frame(s, stream_index, ts, flags | dir); @@ -2304,16 +2246,21 @@ static void fill_all_stream_timings(AVFormatContext *ic) static void estimate_timings_from_bit_rate(AVFormatContext *ic) { int64_t filesize, duration; - int bit_rate, i; + int i, show_warning = 0; AVStream *st; /* if bit_rate is already set, we believe it */ if (ic->bit_rate <= 0) { - bit_rate = 0; + int bit_rate = 0; for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; - if (st->codec->bit_rate > 0) - bit_rate += st->codec->bit_rate; + if (st->codec->bit_rate > 0) { + if (INT_MAX - st->codec->bit_rate < bit_rate) { + bit_rate = 0; + break; + } + bit_rate += st->codec->bit_rate; + } } ic->bit_rate = bit_rate; } @@ -2325,12 +2272,17 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic) if (filesize > 0) { for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; - duration= av_rescale(8*filesize, st->time_base.den, ic->bit_rate*(int64_t)st->time_base.num); - if (st->duration == AV_NOPTS_VALUE) + if ( st->time_base.num <= INT64_MAX / ic->bit_rate + && st->duration == AV_NOPTS_VALUE) { + duration= av_rescale(8*filesize, st->time_base.den, ic->bit_rate*(int64_t)st->time_base.num); st->duration = duration; + show_warning = 1; + } } } } + if (show_warning) + av_log(ic, AV_LOG_WARNING, "Estimating duration from bitrate, this may be inaccurate\n"); } #define DURATION_MAX_READ_SIZE 250000LL @@ -2410,7 +2362,6 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) st= ic->streams[i]; st->cur_dts= st->first_dts; st->last_IP_pts = AV_NOPTS_VALUE; - st->reference_dts = AV_NOPTS_VALUE; } } @@ -2438,7 +2389,6 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) fill_all_stream_timings(ic); ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM; } else { - av_log(ic, AV_LOG_WARNING, "Estimating duration from bitrate, this may be inaccurate\n"); /* less precise: use bitrate info */ estimate_timings_from_bit_rate(ic); ic->duration_estimation_method = AVFMT_DURATION_FROM_BITRATE; @@ -2507,11 +2457,11 @@ static int has_codec_parameters(AVStream *st, const char **errmsg_ptr) } /* returns 1 or 0 if or if not decoded data was returned, or a negative error */ -static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **options) +static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt, AVDictionary **options) { const AVCodec *codec; int got_picture = 1, ret = 0; - AVFrame *frame = avcodec_alloc_frame(); + AVFrame *frame = av_frame_alloc(); AVSubtitle subtitle; AVPacket pkt = *avpkt; @@ -2521,8 +2471,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option if (!avcodec_is_open(st->codec) && !st->info->found_decoder) { AVDictionary *thread_opt = NULL; - codec = st->codec->codec ? st->codec->codec : - avcodec_find_decoder(st->codec->codec_id); + codec = find_decoder(s, st, st->codec->codec_id); if (!codec) { st->info->found_decoder = -1; @@ -2555,7 +2504,6 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option !has_decode_delay_been_guessed(st) || (!st->codec_info_nb_frames && st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) { got_picture = 0; - avcodec_get_frame_defaults(frame); switch(st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: ret = avcodec_decode_video2(st->codec, frame, @@ -2585,7 +2533,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option ret = -1; fail: - avcodec_free_frame(&frame); + av_frame_free(&frame); return ret; } @@ -2733,9 +2681,158 @@ int av_find_stream_info(AVFormatContext *ic) } #endif +int ff_alloc_extradata(AVCodecContext *avctx, int size) +{ + int ret; + + if (size < 0 || size >= INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) { + avctx->extradata_size = 0; + return AVERROR(EINVAL); + } + avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + if (avctx->extradata) { + memset(avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata_size = size; + ret = 0; + } else { + avctx->extradata_size = 0; + ret = AVERROR(ENOMEM); + } + return ret; +} + +int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size) +{ + int ret = ff_alloc_extradata(avctx, size); + if (ret < 0) + return ret; + ret = avio_read(pb, avctx->extradata, size); + if (ret != size) { + av_freep(&avctx->extradata); + avctx->extradata_size = 0; + av_log(avctx, AV_LOG_ERROR, "Failed to read extradata of size %d\n", size); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } + + return ret; +} + +int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts) +{ + int i, j; + int64_t last = st->info->last_dts; + + if( ts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && ts > last + && ts - (uint64_t)last < INT64_MAX){ + double dts= (is_relative(ts) ? ts - RELATIVE_TS_BASE : ts) * av_q2d(st->time_base); + int64_t duration= ts - last; + + if (!st->info->duration_error) + st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2); + if (!st->info->duration_error) + return AVERROR(ENOMEM); + +// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) +// av_log(NULL, AV_LOG_ERROR, "%f\n", dts); + for (i=0; i<MAX_STD_TIMEBASES; i++) { + if (st->info->duration_error[0][1][i] < 1e10) { + int framerate= get_std_framerate(i); + double sdts= dts*framerate/(1001*12); + for(j=0; j<2; j++){ + int64_t ticks= llrint(sdts+j*0.5); + double error= sdts - ticks + j*0.5; + st->info->duration_error[j][0][i] += error; + st->info->duration_error[j][1][i] += error*error; + } + } + } + st->info->duration_count++; + st->info->rfps_duration_sum += duration; + + if (st->info->duration_count % 10 == 0) { + int n = st->info->duration_count; + for (i=0; i<MAX_STD_TIMEBASES; i++) { + if (st->info->duration_error[0][1][i] < 1e10) { + double a0 = st->info->duration_error[0][0][i] / n; + double error0 = st->info->duration_error[0][1][i] / n - a0*a0; + double a1 = st->info->duration_error[1][0][i] / n; + double error1 = st->info->duration_error[1][1][i] / n - a1*a1; + if (error0 > 0.04 && error1 > 0.04) { + st->info->duration_error[0][1][i] = 2e10; + st->info->duration_error[1][1][i] = 2e10; + } + } + } + } + + // ignore the first 4 values, they might have some random jitter + if (st->info->duration_count > 3 && is_relative(ts) == is_relative(last)) + st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration); + } + if (ts != AV_NOPTS_VALUE) + st->info->last_dts = ts; + + return 0; +} + +void ff_rfps_calculate(AVFormatContext *ic) +{ + int i, j; + + for (i = 0; i<ic->nb_streams; i++) { + AVStream *st = ic->streams[i]; + + if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) + continue; + // the check for tb_unreliable() is not completely correct, since this is not about handling + // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g. + // ipmovie.c produces. + if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num) + av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX); + if (st->info->duration_count>1 && !st->r_frame_rate.num + && tb_unreliable(st->codec)) { + int num = 0; + double best_error= 0.01; + + for (j=0; j<MAX_STD_TIMEBASES; j++) { + int k; + + if(st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j)) + continue; + if(!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j)) + continue; + + if (av_q2d(st->time_base) * st->info->rfps_duration_sum / st->info->duration_count < (1001*12.0 * 0.8)/get_std_framerate(j)) + continue; + + for(k=0; k<2; k++){ + int n= st->info->duration_count; + double a= st->info->duration_error[k][0][j] / n; + double error= st->info->duration_error[k][1][j]/n - a*a; + + if(error < best_error && best_error> 0.000000001){ + best_error= error; + num = get_std_framerate(j); + } + if(error < 0.02) + av_log(NULL, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error); + } + } + // do not increase frame rate by more than 1 % in order to match a standard rate. + if (num && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate))) + av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX); + } + + av_freep(&st->info->duration_error); + st->info->last_dts = AV_NOPTS_VALUE; + st->info->duration_count = 0; + st->info->rfps_duration_sum = 0; + } +} + int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) { - int i, count, ret, j; + int i, count, ret = 0, j; int64_t read_size; AVStream *st; AVPacket pkt1, *pkt; @@ -2744,7 +2841,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int flush_codecs = ic->probesize > 0; if(ic->pb) - av_log(ic, AV_LOG_DEBUG, "File position before avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb)); + av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d\n", + avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count); for(i=0;i<ic->nb_streams;i++) { const AVCodec *codec; @@ -2773,8 +2871,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) avcodec_get_name(st->codec->codec_id)); } } - codec = st->codec->codec ? st->codec->codec : - avcodec_find_decoder(st->codec->codec_id); + codec = find_decoder(ic, st, st->codec->codec_id); /* force thread count to 1 since the h264 decoder will not extract SPS * and PPS to extradata during multi-threaded decoding */ @@ -2782,15 +2879,16 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) /* Ensure that subtitle_header is properly set. */ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE - && codec && !st->codec->codec) - avcodec_open2(st->codec, codec, options ? &options[i] - : &thread_opt); + && codec && !st->codec->codec) { + if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0) + av_log(ic, AV_LOG_WARNING, "Failed to open codec in av_find_stream_info\n"); + } //try to just open decoders, in case this is enough to get parameters if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) { if (codec && !st->codec->codec) - avcodec_open2(st->codec, codec, options ? &options[i] - : &thread_opt); + if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0) + av_log(ic, AV_LOG_WARNING, "Failed to open codec in av_find_stream_info\n"); } if (!options) av_dict_free(&thread_opt); @@ -2859,7 +2957,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) av_log(ic, AV_LOG_DEBUG, "Probe buffer size limit of %d bytes reached\n", ic->probesize); for (i = 0; i < ic->nb_streams; i++) if (!ic->streams[i]->r_frame_rate.num && - ic->streams[i]->info->duration_count <= 1) + ic->streams[i]->info->duration_count <= 1 && + strcmp(ic->iformat->name, "image2")) av_log(ic, AV_LOG_WARNING, "Stream #%d: not enough frames to estimate rate; " "consider increasing probesize\n", i); @@ -2877,18 +2976,23 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) break; } - if (ic->flags & AVFMT_FLAG_NOBUFFER) { - pkt = &pkt1; - } else { + if (ic->flags & AVFMT_FLAG_NOBUFFER) + free_packet_buffer(&ic->packet_buffer, &ic->packet_buffer_end); + { pkt = add_to_pktbuf(&ic->packet_buffer, &pkt1, &ic->packet_buffer_end); + if (!pkt) { + ret = AVERROR(ENOMEM); + goto find_stream_info_err; + } if ((ret = av_dup_packet(pkt)) < 0) goto find_stream_info_err; } - read_size += pkt->size; - st = ic->streams[pkt->stream_index]; + if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + read_size += pkt->size; + if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) { /* check for non-increasing dts */ if (st->info->fps_last_dts != AV_NOPTS_VALUE && @@ -2928,57 +3032,30 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) if (st->avg_frame_rate.num > 0) t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q)); + if ( t==0 + && st->codec_info_nb_frames>30 + && st->info->fps_first_dts != AV_NOPTS_VALUE + && st->info->fps_last_dts != AV_NOPTS_VALUE) + t = FFMAX(t, av_rescale_q(st->info->fps_last_dts - st->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q)); + if (t >= ic->max_analyze_duration) { - av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached at %"PRId64" microseconds\n", ic->max_analyze_duration, t); + av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %d reached at %"PRId64" microseconds\n", ic->max_analyze_duration, t); break; } if (pkt->duration) { st->info->codec_info_duration += pkt->duration; - st->info->codec_info_duration_fields += st->parser && st->codec->ticks_per_frame==2 ? st->parser->repeat_pict + 1 : 2; + st->info->codec_info_duration_fields += st->parser && st->need_parsing && st->codec->ticks_per_frame==2 ? st->parser->repeat_pict + 1 : 2; } } #if FF_API_R_FRAME_RATE - { - int64_t last = st->info->last_dts; - - if( pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last - && pkt->dts - (uint64_t)last < INT64_MAX){ - double dts= (is_relative(pkt->dts) ? pkt->dts - RELATIVE_TS_BASE : pkt->dts) * av_q2d(st->time_base); - int64_t duration= pkt->dts - last; - - if (!st->info->duration_error) - st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2); - -// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -// av_log(NULL, AV_LOG_ERROR, "%f\n", dts); - for (i=0; i<MAX_STD_TIMEBASES; i++) { - int framerate= get_std_framerate(i); - double sdts= dts*framerate/(1001*12); - for(j=0; j<2; j++){ - int64_t ticks= llrint(sdts+j*0.5); - double error= sdts - ticks + j*0.5; - st->info->duration_error[j][0][i] += error; - st->info->duration_error[j][1][i] += error*error; - } - } - st->info->duration_count++; - // ignore the first 4 values, they might have some random jitter - if (st->info->duration_count > 3 && is_relative(pkt->dts) == is_relative(last)) - st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration); - } - if (pkt->dts != AV_NOPTS_VALUE) - st->info->last_dts = pkt->dts; - } + ff_rfps_add_frame(ic, st, pkt->dts); #endif if(st->parser && st->parser->parser->split && !st->codec->extradata){ int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) { - st->codec->extradata_size= i; - st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, i)) return AVERROR(ENOMEM); memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size); - memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE); } } @@ -2991,7 +3068,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) least one frame of codec data, this makes sure the codec initializes the channel configuration and does not only trust the values from the container. */ - try_decode_frame(st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL); + try_decode_frame(ic, st, pkt, (options && i < orig_nb_streams ) ? &options[i] : NULL); st->codec_info_nb_frames++; count++; @@ -3002,16 +3079,14 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int err = 0; av_init_packet(&empty_pkt); - ret = -1; /* we could not have all the codec parameters before EOF */ for(i=0;i<ic->nb_streams;i++) { - const char *errmsg; st = ic->streams[i]; /* flush the decoders */ if (st->info->found_decoder == 1) { do { - err = try_decode_frame(st, &empty_pkt, + err = try_decode_frame(ic, st, &empty_pkt, (options && i < orig_nb_streams) ? &options[i] : NULL); } while (err > 0 && !has_codec_parameters(st, NULL)); @@ -3021,17 +3096,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) "decoding for stream %d failed\n", st->index); } } - - if (!has_codec_parameters(st, &errmsg)) { - char buf[256]; - avcodec_string(buf, sizeof(buf), st->codec, 0); - av_log(ic, AV_LOG_WARNING, - "Could not find codec parameters for stream %d (%s): %s\n" - "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n", - i, buf, errmsg); - } else { - ret = 0; - } } } @@ -3040,6 +3104,9 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) st = ic->streams[i]; avcodec_close(st->codec); } + + ff_rfps_calculate(ic); + for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -3054,6 +3121,10 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int best_fps = 0; double best_error = 0.01; + if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2|| + st->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den || + st->info->codec_info_duration < 0) + continue; av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den, st->info->codec_info_duration_fields*(int64_t)st->time_base.den, st->info->codec_info_duration*2*(int64_t)st->time_base.num, 60000); @@ -3074,40 +3145,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) best_fps, 12*1001, INT_MAX); } } - // the check for tb_unreliable() is not completely correct, since this is not about handling - // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g. - // ipmovie.c produces. - if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num) - av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX); - if (st->info->duration_count>1 && !st->r_frame_rate.num - && tb_unreliable(st->codec)) { - int num = 0; - double best_error= 0.01; - - for (j=0; j<MAX_STD_TIMEBASES; j++) { - int k; - - if(st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j)) - continue; - if(!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j)) - continue; - for(k=0; k<2; k++){ - int n= st->info->duration_count; - double a= st->info->duration_error[k][0][j] / n; - double error= st->info->duration_error[k][1][j]/n - a*a; - - if(error < best_error && best_error> 0.000000001){ - best_error= error; - num = get_std_framerate(j); - } - if(error < 0.02) - av_log(NULL, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error); - } - } - // do not increase frame rate by more than 1 % in order to match a standard rate. - if (num && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate))) - av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX); - } if (!st->r_frame_rate.num){ if( st->codec->time_base.den * (int64_t)st->time_base.num @@ -3141,19 +3178,37 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) if(ic->probesize) estimate_timings(ic, old_offset); + if (ret >= 0 && ic->nb_streams) + ret = -1; /* we could not have all the codec parameters before EOF */ + for(i=0;i<ic->nb_streams;i++) { + const char *errmsg; + st = ic->streams[i]; + if (!has_codec_parameters(st, &errmsg)) { + char buf[256]; + avcodec_string(buf, sizeof(buf), st->codec, 0); + av_log(ic, AV_LOG_WARNING, + "Could not find codec parameters for stream %d (%s): %s\n" + "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n", + i, buf, errmsg); + } else { + ret = 0; + } + } + compute_chapters_end(ic); find_stream_info_err: for (i=0; i < ic->nb_streams; i++) { st = ic->streams[i]; - if (ic->streams[i]->codec) + if (ic->streams[i]->codec && ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) ic->streams[i]->codec->thread_count = 0; if (st->info) av_freep(&st->info->duration_error); av_freep(&ic->streams[i]->info); } if(ic->pb) - av_log(ic, AV_LOG_DEBUG, "File position after avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb)); + av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n", + avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, count); return ret; } @@ -3204,7 +3259,7 @@ int av_find_best_stream(AVFormatContext *ic, if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED|AV_DISPOSITION_VISUAL_IMPAIRED)) continue; if (decoder_ret) { - decoder = avcodec_find_decoder(st->codec->codec_id); + decoder = find_decoder(ic, st, st->codec->codec_id); if (!decoder) { if (ret < 0) ret = AVERROR_DECODER_NOT_FOUND; @@ -3264,6 +3319,7 @@ void ff_free_stream(AVFormatContext *s, AVStream *st){ if (st->attached_pic.data) av_free_packet(&st->attached_pic); av_dict_free(&st->metadata); + av_freep(&st->probe_data.buf); av_freep(&st->index_entries); av_freep(&st->codec->extradata); av_freep(&st->codec->subtitle_header); @@ -3272,7 +3328,6 @@ void ff_free_stream(AVFormatContext *s, AVStream *st){ if (st->info) av_freep(&st->info->duration_error); av_freep(&st->info); - av_freep(&st->probe_data.buf); av_freep(&s->streams[ --s->nb_streams ]); } @@ -3316,8 +3371,14 @@ void av_close_input_file(AVFormatContext *s) void avformat_close_input(AVFormatContext **ps) { - AVFormatContext *s = *ps; - AVIOContext *pb = s->pb; + AVFormatContext *s; + AVIOContext *pb; + + if (!ps || !*ps) + return; + + s = *ps; + pb = s->pb; if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || (s->flags & AVFMT_FLAG_CUSTOM_IO)) @@ -3355,7 +3416,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) if (s->nb_streams >= INT_MAX/sizeof(*streams)) return NULL; - streams = av_realloc(s->streams, (s->nb_streams + 1) * sizeof(*streams)); + streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams)); if (!streams) return NULL; s->streams = streams; @@ -3392,7 +3453,6 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c) st->last_IP_pts = AV_NOPTS_VALUE; for(i=0; i<MAX_REORDER_DELAY+1; i++) st->pts_buffer[i]= AV_NOPTS_VALUE; - st->reference_dts = AV_NOPTS_VALUE; st->sample_aspect_ratio = (AVRational){0,1}; @@ -3477,7 +3537,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i if(program->stream_index[j] == idx) return; - tmp = av_realloc(program->stream_index, sizeof(unsigned int)*(program->nb_stream_indexes+1)); + tmp = av_realloc_array(program->stream_index, program->nb_stream_indexes+1, sizeof(unsigned int)); if(!tmp) return; program->stream_index = tmp; @@ -3788,27 +3848,11 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int av_hex_dump(f, pkt->data, pkt->size); } -#if FF_API_PKT_DUMP -void av_pkt_dump(FILE *f, AVPacket *pkt, int dump_payload) -{ - AVRational tb = { 1, AV_TIME_BASE }; - pkt_dump_internal(NULL, f, 0, pkt, dump_payload, tb); -} -#endif - void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st) { pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base); } -#if FF_API_PKT_DUMP -void av_pkt_dump_log(void *avcl, int level, AVPacket *pkt, int dump_payload) -{ - AVRational tb = { 1, AV_TIME_BASE }; - pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, tb); -} -#endif - void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload, AVStream *st) { @@ -3956,72 +4000,6 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, s->pts_wrap_bits = pts_wrap_bits; } -int ff_url_join(char *str, int size, const char *proto, - const char *authorization, const char *hostname, - int port, const char *fmt, ...) -{ -#if CONFIG_NETWORK - struct addrinfo hints = { 0 }, *ai; -#endif - - str[0] = '\0'; - if (proto) - av_strlcatf(str, size, "%s://", proto); - if (authorization && authorization[0]) - av_strlcatf(str, size, "%s@", authorization); -#if CONFIG_NETWORK && defined(AF_INET6) - /* Determine if hostname is a numerical IPv6 address, - * properly escape it within [] in that case. */ - hints.ai_flags = AI_NUMERICHOST; - if (!getaddrinfo(hostname, NULL, &hints, &ai)) { - if (ai->ai_family == AF_INET6) { - av_strlcat(str, "[", size); - av_strlcat(str, hostname, size); - av_strlcat(str, "]", size); - } else { - av_strlcat(str, hostname, size); - } - freeaddrinfo(ai); - } else -#endif - /* Not an IPv6 address, just output the plain string. */ - av_strlcat(str, hostname, size); - - if (port >= 0) - av_strlcatf(str, size, ":%d", port); - if (fmt) { - va_list vl; - int len = strlen(str); - - va_start(vl, fmt); - vsnprintf(str + len, size > len ? size - len : 0, fmt, vl); - va_end(vl); - } - return strlen(str); -} - -int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, - AVFormatContext *src) -{ - AVPacket local_pkt; - - local_pkt = *pkt; - local_pkt.stream_index = dst_stream; - if (pkt->pts != AV_NOPTS_VALUE) - local_pkt.pts = av_rescale_q(pkt->pts, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - if (pkt->dts != AV_NOPTS_VALUE) - local_pkt.dts = av_rescale_q(pkt->dts, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - if (pkt->duration) - local_pkt.duration = av_rescale_q(pkt->duration, - src->streams[pkt->stream_index]->time_base, - dst->streams[dst_stream]->time_base); - return av_write_frame(dst, &local_pkt); -} - void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf, void *context) { @@ -4086,75 +4064,6 @@ int ff_find_stream_index(AVFormatContext *s, int id) return -1; } -void ff_make_absolute_url(char *buf, int size, const char *base, - const char *rel) -{ - char *sep, *path_query; - /* Absolute path, relative to the current server */ - if (base && strstr(base, "://") && rel[0] == '/') { - if (base != buf) - av_strlcpy(buf, base, size); - sep = strstr(buf, "://"); - if (sep) { - /* Take scheme from base url */ - if (rel[1] == '/') { - sep[1] = '\0'; - } else { - /* Take scheme and host from base url */ - sep += 3; - sep = strchr(sep, '/'); - if (sep) - *sep = '\0'; - } - } - av_strlcat(buf, rel, size); - return; - } - /* If rel actually is an absolute url, just copy it */ - if (!base || strstr(rel, "://") || rel[0] == '/') { - av_strlcpy(buf, rel, size); - return; - } - if (base != buf) - av_strlcpy(buf, base, size); - - /* Strip off any query string from base */ - path_query = strchr(buf, '?'); - if (path_query != NULL) - *path_query = '\0'; - - /* Is relative path just a new query part? */ - if (rel[0] == '?') { - av_strlcat(buf, rel, size); - return; - } - - /* Remove the file name from the base url */ - sep = strrchr(buf, '/'); - if (sep) - sep[1] = '\0'; - else - buf[0] = '\0'; - while (av_strstart(rel, "../", NULL) && sep) { - /* Remove the path delimiter at the end */ - sep[0] = '\0'; - sep = strrchr(buf, '/'); - /* If the next directory name to pop off is "..", break here */ - if (!strcmp(sep ? &sep[1] : buf, "..")) { - /* Readd the slash we just removed */ - av_strlcat(buf, "/", size); - break; - } - /* Cut off the directory name */ - if (sep) - sep[1] = '\0'; - else - buf[0] = '\0'; - rel += 3; - } - av_strlcat(buf, rel, size); -} - int64_t ff_iso8601_to_unix_time(const char *datestr) { struct tm time1 = {0}, time2 = {0}; @@ -4244,15 +4153,6 @@ int ff_add_param_change(AVPacket *pkt, int32_t channels, return 0; } -const struct AVCodecTag *avformat_get_riff_video_tags(void) -{ - return ff_codec_bmp_tags; -} -const struct AVCodecTag *avformat_get_riff_audio_tags(void) -{ - return ff_codec_wav_tags; -} - AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame) { AVRational undef = {0, 1}; @@ -4276,6 +4176,22 @@ AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *strea return frame_sample_aspect_ratio; } +AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *frame) +{ + AVRational fr = st->r_frame_rate; + + if (st->codec->ticks_per_frame > 1) { + AVRational codec_fr = av_inv_q(st->codec->time_base); + AVRational avg_fr = st->avg_frame_rate; + codec_fr.den *= st->codec->ticks_per_frame; + if ( codec_fr.num > 0 && codec_fr.den > 0 && av_q2d(codec_fr) < av_q2d(fr)*0.7 + && fabs(1.0 - av_q2d(av_div_q(avg_fr, fr))) > 0.1) + fr = codec_fr; + } + + return fr; +} + int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) { @@ -4337,7 +4253,7 @@ int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, return AVERROR(EINVAL); } -void ff_generate_avci_extradata(AVStream *st) +int ff_generate_avci_extradata(AVStream *st) { static const uint8_t avci100_1080p_extradata[] = { // SPS @@ -4404,8 +4320,10 @@ void ff_generate_avci_extradata(AVStream *st) 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x31, 0x12, 0x11 }; + + const uint8_t *data = NULL; int size = 0; - const uint8_t *data = 0; + if (st->codec->width == 1920) { if (st->codec->field_order == AV_FIELD_PROGRESSIVE) { data = avci100_1080p_extradata; @@ -4421,67 +4339,14 @@ void ff_generate_avci_extradata(AVStream *st) data = avci100_720p_extradata; size = sizeof(avci100_720p_extradata); } + if (!size) - return; + return 0; + av_freep(&st->codec->extradata); - st->codec->extradata_size = 0; - st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) - return; + if (ff_alloc_extradata(st->codec, size)) + return AVERROR(ENOMEM); memcpy(st->codec->extradata, data, size); - st->codec->extradata_size = size; -} -static int match_host_pattern(const char *pattern, const char *hostname) -{ - int len_p, len_h; - if (!strcmp(pattern, "*")) - return 1; - // Skip a possible *. at the start of the pattern - if (pattern[0] == '*') - pattern++; - if (pattern[0] == '.') - pattern++; - len_p = strlen(pattern); - len_h = strlen(hostname); - if (len_p > len_h) - return 0; - // Simply check if the end of hostname is equal to 'pattern' - if (!strcmp(pattern, &hostname[len_h - len_p])) { - if (len_h == len_p) - return 1; // Exact match - if (hostname[len_h - len_p - 1] == '.') - return 1; // The matched substring is a domain and not just a substring of a domain - } return 0; } - -int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) -{ - char *buf, *start; - int ret = 0; - if (!no_proxy) - return 0; - if (!hostname) - return 0; - buf = av_strdup(no_proxy); - if (!buf) - return 0; - start = buf; - while (start) { - char *sep, *next = NULL; - start += strspn(start, " ,"); - sep = start + strcspn(start, " ,"); - if (*sep) { - next = sep + 1; - *sep = '\0'; - } - if (match_host_pattern(start, hostname)) { - ret = 1; - break; - } - start = next; - } - av_free(buf); - return ret; -} diff --git a/ffmpeg/libavformat/vc1test.c b/ffmpeg/libavformat/vc1test.c index e411a25..e5303fa 100644 --- a/ffmpeg/libavformat/vc1test.c +++ b/ffmpeg/libavformat/vc1test.c @@ -39,7 +39,7 @@ static int vc1t_probe(AVProbeData *p) if (p->buf[3] != 0xC5 || AV_RL32(&p->buf[4]) != 4 || AV_RL32(&p->buf[20]) != 0xC) return 0; - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; } static int vc1t_read_header(AVFormatContext *s) @@ -61,9 +61,8 @@ static int vc1t_read_header(AVFormatContext *s) st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_WMV3; - st->codec->extradata = av_malloc(VC1_EXTRADATA_SIZE); - st->codec->extradata_size = VC1_EXTRADATA_SIZE; - avio_read(pb, st->codec->extradata, VC1_EXTRADATA_SIZE); + if (ff_get_extradata(st->codec, pb, VC1_EXTRADATA_SIZE) < 0) + return AVERROR(ENOMEM); st->codec->height = avio_rl32(pb); st->codec->width = avio_rl32(pb); if(avio_rl32(pb) != 0xC) diff --git a/ffmpeg/libavformat/vc1testenc.c b/ffmpeg/libavformat/vc1testenc.c index 9debf19..751333a 100644 --- a/ffmpeg/libavformat/vc1testenc.c +++ b/ffmpeg/libavformat/vc1testenc.c @@ -63,7 +63,6 @@ static int vc1test_write_packet(AVFormatContext *s, AVPacket *pkt) avio_wl32(pb, pkt->size | ((pkt->flags & AV_PKT_FLAG_KEY) ? 0x80000000 : 0)); avio_wl32(pb, pkt->pts); avio_write(pb, pkt->data, pkt->size); - avio_flush(pb); ctx->frames++; return 0; diff --git a/ffmpeg/libavformat/version.h b/ffmpeg/libavformat/version.h index 6332878..ee8679d 100644 --- a/ffmpeg/libavformat/version.h +++ b/ffmpeg/libavformat/version.h @@ -27,10 +27,10 @@ * Libavformat version macros */ -#include "libavutil/avutil.h" +#include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 0 +#define LIBAVFORMAT_VERSION_MINOR 22 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -48,13 +48,10 @@ * dropped at a future version bump. The defines themselves are not part of * the public API and may change, break or disappear at any time. */ - -#ifndef FF_API_OLD_AVIO -#define FF_API_OLD_AVIO (LIBAVFORMAT_VERSION_MAJOR < 55) -#endif -#ifndef FF_API_PKT_DUMP -#define FF_API_PKT_DUMP (LIBAVFORMAT_VERSION_MAJOR < 54) +#ifndef FF_API_REFERENCE_DTS +#define FF_API_REFERENCE_DTS (LIBAVFORMAT_VERSION_MAJOR < 56) #endif + #ifndef FF_API_ALLOC_OUTPUT_CONTEXT #define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 56) #endif @@ -73,6 +70,9 @@ #ifndef FF_API_READ_PACKET #define FF_API_READ_PACKET (LIBAVFORMAT_VERSION_MAJOR < 56) #endif +#ifndef FF_API_ASS_SSA +#define FF_API_ASS_SSA (LIBAVFORMAT_VERSION_MAJOR < 56) +#endif #ifndef FF_API_R_FRAME_RATE #define FF_API_R_FRAME_RATE 1 #endif diff --git a/ffmpeg/libavformat/vocdec.c b/ffmpeg/libavformat/vocdec.c index 62215fc..0b6b5a5 100644 --- a/ffmpeg/libavformat/vocdec.c +++ b/ffmpeg/libavformat/vocdec.c @@ -75,7 +75,7 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) while (!voc->remaining_size) { type = avio_r8(pb); if (type == VOC_TYPE_EOF) - return AVERROR(EIO); + return AVERROR_EOF; voc->remaining_size = avio_rl24(pb); if (!voc->remaining_size) { if (!s->pb->seekable) @@ -91,11 +91,11 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) if (sample_rate) dec->sample_rate = sample_rate; avpriv_set_pts_info(st, 64, 1, dec->sample_rate); + dec->channels = channels; + dec->bits_per_coded_sample = av_get_bits_per_sample(dec->codec_id); } else avio_skip(pb, 1); - dec->channels = channels; tmp_codec = avio_r8(pb); - dec->bits_per_coded_sample = av_get_bits_per_sample(dec->codec_id); voc->remaining_size -= 2; max_size -= 2; channels = 1; @@ -117,10 +117,10 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) if (!dec->sample_rate) { dec->sample_rate = avio_rl32(pb); avpriv_set_pts_info(st, 64, 1, dec->sample_rate); + dec->bits_per_coded_sample = avio_r8(pb); + dec->channels = avio_r8(pb); } else - avio_skip(pb, 4); - dec->bits_per_coded_sample = avio_r8(pb); - dec->channels = avio_r8(pb); + avio_skip(pb, 6); tmp_codec = avio_rl16(pb); avio_skip(pb, 4); voc->remaining_size -= 12; diff --git a/ffmpeg/libavformat/vorbiscomment.c b/ffmpeg/libavformat/vorbiscomment.c index 9b38e6a..f17a0c1 100644 --- a/ffmpeg/libavformat/vorbiscomment.c +++ b/ffmpeg/libavformat/vorbiscomment.c @@ -34,6 +34,7 @@ const AVMetadataConv ff_vorbiscomment_metadata_conv[] = { { "ALBUMARTIST", "album_artist"}, { "TRACKNUMBER", "track" }, { "DISCNUMBER", "disc" }, + { "DESCRIPTION", "comment" }, { 0 } }; diff --git a/ffmpeg/libavformat/vqf.c b/ffmpeg/libavformat/vqf.c index f1e6aaf..526b596 100644 --- a/ffmpeg/libavformat/vqf.c +++ b/ffmpeg/libavformat/vqf.c @@ -43,7 +43,10 @@ static int vqf_probe(AVProbeData *probe_packet) if (!memcmp(probe_packet->buf + 4, "00052200", 8)) return AVPROBE_SCORE_MAX; - return AVPROBE_SCORE_MAX/2; + if (AV_RL32(probe_packet->buf + 12) > (1<<27)) + return AVPROBE_SCORE_EXTENSION/2; + + return AVPROBE_SCORE_EXTENSION; } static void add_metadata(AVFormatContext *s, uint32_t tag, @@ -132,6 +135,11 @@ static int vqf_read_header(AVFormatContext *s) rate_flag = AV_RB32(comm_chunk + 8); avio_skip(s->pb, len-12); + if (st->codec->channels <= 0) { + av_log(s, AV_LOG_ERROR, "Invalid number of channels\n"); + return AVERROR_INVALIDDATA; + } + st->codec->bit_rate = read_bitrate*1000; break; case MKTAG('D','S','I','Z'): // size of compressed data @@ -158,7 +166,7 @@ static int vqf_read_header(AVFormatContext *s) header_size -= len; - } while (header_size >= 0); + } while (header_size >= 0 && !url_feof(s->pb)); switch (rate_flag) { case -1: @@ -174,14 +182,21 @@ static int vqf_read_header(AVFormatContext *s) st->codec->sample_rate = 11025; break; default: - st->codec->sample_rate = rate_flag*1000; - if (st->codec->sample_rate <= 0) { - av_log(s, AV_LOG_ERROR, "sample rate %d is invalid\n", st->codec->sample_rate); - return -1; + if (rate_flag < 8 || rate_flag > 44) { + av_log(s, AV_LOG_ERROR, "Invalid rate flag %d\n", rate_flag); + return AVERROR_INVALIDDATA; } + st->codec->sample_rate = rate_flag*1000; break; } + if (read_bitrate / st->codec->channels < 8 || + read_bitrate / st->codec->channels > 48) { + av_log(s, AV_LOG_ERROR, "Invalid bitrate per channel %d\n", + read_bitrate / st->codec->channels); + return AVERROR_INVALIDDATA; + } + switch (((st->codec->sample_rate/1000) << 8) + read_bitrate/st->codec->channels) { case (11<<8) + 8 : @@ -208,9 +223,8 @@ static int vqf_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, size, st->codec->sample_rate); /* put first 12 bytes of COMM chunk in extradata */ - if (!(st->codec->extradata = av_malloc(12 + FF_INPUT_BUFFER_PADDING_SIZE))) + if (ff_alloc_extradata(st->codec, 12)) return AVERROR(ENOMEM); - st->codec->extradata_size = 12; memcpy(st->codec->extradata, comm_chunk, 12); ff_metadata_conv_ctx(s, NULL, vqf_metadata_conv); diff --git a/ffmpeg/libavformat/w64.c b/ffmpeg/libavformat/w64.c index 7bf5502..ef2d90a 100644 --- a/ffmpeg/libavformat/w64.c +++ b/ffmpeg/libavformat/w64.c @@ -20,20 +20,31 @@ #include "w64.h" -const uint8_t ff_w64_guid_riff[16] = { 'r', 'i', 'f', 'f', - 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 }; +const uint8_t ff_w64_guid_riff[16] = { + 'r', 'i', 'f', 'f', + 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00 +}; -const uint8_t ff_w64_guid_wave[16] = { 'w', 'a', 'v', 'e', - 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A }; +const uint8_t ff_w64_guid_wave[16] = { + 'w', 'a', 'v', 'e', + 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A +}; -const uint8_t ff_w64_guid_fmt [16] = { 'f', 'm', 't', ' ', - 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A }; +const uint8_t ff_w64_guid_fmt [16] = { + 'f', 'm', 't', ' ', + 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A +}; const uint8_t ff_w64_guid_fact[16] = { 'f', 'a', 'c', 't', - 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A }; + 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A +}; -const uint8_t ff_w64_guid_data[16] = { 'd', 'a', 't', 'a', - 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A }; +const uint8_t ff_w64_guid_data[16] = { + 'd', 'a', 't', 'a', + 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A +}; -const uint8_t ff_w64_guid_summarylist[16] = { 0xBC, 0x94, 0x5F, 0x92, - 0x5A, 0x52, 0xD2, 0x11, 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A }; +const uint8_t ff_w64_guid_summarylist[16] = { + 0xBC, 0x94, 0x5F, 0x92, + 0x5A, 0x52, 0xD2, 0x11, 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A +}; diff --git a/ffmpeg/libavformat/wavdec.c b/ffmpeg/libavformat/wavdec.c index 782fa64..daea64e 100644 --- a/ffmpeg/libavformat/wavdec.c +++ b/ffmpeg/libavformat/wavdec.c @@ -23,19 +23,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <stdint.h> + #include "libavutil/avassert.h" #include "libavutil/dict.h" +#include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "avformat.h" -#include "internal.h" +#include "avio.h" #include "avio_internal.h" +#include "internal.h" +#include "metadata.h" #include "pcm.h" #include "riff.h" #include "w64.h" -#include "avio.h" -#include "metadata.h" #include "spdif.h" typedef struct WAVDemuxContext { @@ -51,9 +54,11 @@ typedef struct WAVDemuxContext { int audio_eof; int ignore_length; int spdif; + int smv_cur_pt; + int smv_given_first; + int unaligned; // e.g. if an odd number of bytes ID3 tag was prepended } WAVDemuxContext; - #if CONFIG_WAV_DEMUXER static int64_t next_tag(AVIOContext *pb, uint32_t *tag) @@ -62,19 +67,27 @@ static int64_t next_tag(AVIOContext *pb, uint32_t *tag) return avio_rl32(pb); } +/* RIFF chunks are always at even offsets relative to where they start. */ +static int64_t wav_seek_tag(WAVDemuxContext * wav, AVIOContext *s, int64_t offset, int whence) +{ + offset += offset < INT64_MAX && offset + wav->unaligned & 1; + + return avio_seek(s, offset, whence); +} + /* return the size of the found tag */ -static int64_t find_tag(AVIOContext *pb, uint32_t tag1) +static int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1) { unsigned int tag; int64_t size; for (;;) { if (url_feof(pb)) - return -1; + return AVERROR_EOF; size = next_tag(pb, &tag); if (tag == tag1) break; - avio_skip(pb, size); + wav_seek_tag(wav, pb, size, SEEK_CUR); } return size; } @@ -86,11 +99,9 @@ static int wav_probe(AVProbeData *p) return 0; if (!memcmp(p->buf + 8, "WAVE", 4)) { if (!memcmp(p->buf, "RIFF", 4)) - /* - Since ACT demuxer has standard WAV header at top of it's own, - returning score is decreased to avoid probe conflict - between ACT and WAV. - */ + /* Since the ACT demuxer has a standard WAV header at the top of + * its own, the returned score is decreased to avoid a probe + * conflict between ACT and WAV. */ return AVPROBE_SCORE_MAX - 1; else if (!memcmp(p->buf, "RF64", 4) && !memcmp(p->buf + 12, "ds64", 4)) @@ -102,7 +113,7 @@ static int wav_probe(AVProbeData *p) static void handle_stream_probing(AVStream *st) { if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) { - st->request_probe = AVPROBE_SCORE_MAX/2; + st->request_probe = AVPROBE_SCORE_EXTENSION; st->probe_packets = FFMIN(st->probe_packets, 4); } } @@ -173,16 +184,22 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) if (umid_mask) { /* the string formatting below is per SMPTE 330M-2004 Annex C */ - if (umid_parts[4] == 0 && umid_parts[5] == 0 && umid_parts[6] == 0 && umid_parts[7] == 0) { + if (umid_parts[4] == 0 && umid_parts[5] == 0 && + umid_parts[6] == 0 && umid_parts[7] == 0) { /* basic UMID */ - snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, - umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3]); + snprintf(temp, sizeof(temp), + "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, + umid_parts[0], umid_parts[1], + umid_parts[2], umid_parts[3]); } else { /* extended UMID */ - snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 - "%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, - umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3], - umid_parts[4], umid_parts[5], umid_parts[6], umid_parts[7]); + snprintf(temp, sizeof(temp), + "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 + "%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, + umid_parts[0], umid_parts[1], + umid_parts[2], umid_parts[3], + umid_parts[4], umid_parts[5], + umid_parts[6], umid_parts[7]); } if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0) @@ -197,7 +214,7 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) /* CodingHistory present */ size -= 602; - if (!(coding_history = av_malloc(size+1))) + if (!(coding_history = av_malloc(size + 1))) return AVERROR(ENOMEM); if ((ret = avio_read(s->pb, coding_history, size)) < 0) @@ -213,26 +230,28 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) } static const AVMetadataConv wav_metadata_conv[] = { - {"description", "comment" }, - {"originator", "encoded_by" }, - {"origination_date", "date" }, - {"origination_time", "creation_time"}, - {0}, + { "description", "comment" }, + { "originator", "encoded_by" }, + { "origination_date", "date" }, + { "origination_time", "creation_time" }, + { 0 }, }; /* wav input */ static int wav_read_header(AVFormatContext *s) { int64_t size, av_uninit(data_size); - int64_t sample_count=0; + int64_t sample_count = 0; int rf64; uint32_t tag; - AVIOContext *pb = s->pb; - AVStream *st = NULL; + AVIOContext *pb = s->pb; + AVStream *st = NULL; WAVDemuxContext *wav = s->priv_data; int ret, got_fmt = 0; int64_t next_tag_ofs, data_ofs = -1; + wav->unaligned = avio_tell(s->pb) & 1; + wav->smv_data_ofs = -1; /* check RIFF header */ @@ -240,21 +259,23 @@ static int wav_read_header(AVFormatContext *s) rf64 = tag == MKTAG('R', 'F', '6', '4'); if (!rf64 && tag != MKTAG('R', 'I', 'F', 'F')) - return -1; + return AVERROR_INVALIDDATA; avio_rl32(pb); /* file size */ tag = avio_rl32(pb); if (tag != MKTAG('W', 'A', 'V', 'E')) - return -1; + return AVERROR_INVALIDDATA; if (rf64) { if (avio_rl32(pb) != MKTAG('d', 's', '6', '4')) - return -1; + return AVERROR_INVALIDDATA; size = avio_rl32(pb); if (size < 24) - return -1; + return AVERROR_INVALIDDATA; avio_rl64(pb); /* RIFF size */ - data_size = avio_rl64(pb); + + data_size = avio_rl64(pb); sample_count = avio_rl64(pb); + if (data_size < 0 || sample_count < 0) { av_log(s, AV_LOG_ERROR, "negative data_size and/or sample_count in " "ds64: data_size = %"PRId64", sample_count = %"PRId64"\n", @@ -267,7 +288,7 @@ static int wav_read_header(AVFormatContext *s) for (;;) { AVStream *vst; - size = next_tag(pb, &tag); + size = next_tag(pb, &tag); next_tag_ofs = avio_tell(pb) + size; if (url_feof(pb)) @@ -285,14 +306,15 @@ static int wav_read_header(AVFormatContext *s) break; case MKTAG('d', 'a', 't', 'a'): if (!got_fmt) { - av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'data' tag\n"); + av_log(s, AV_LOG_ERROR, + "found no 'fmt ' tag before the 'data' tag\n"); return AVERROR_INVALIDDATA; } if (rf64) { next_tag_ofs = wav->data_end = avio_tell(pb) + data_size; } else { - data_size = size; + data_size = size; next_tag_ofs = wav->data_end = size ? next_tag_ofs : INT64_MAX; } @@ -304,11 +326,11 @@ static int wav_read_header(AVFormatContext *s) if (!pb->seekable || (!rf64 && !size)) goto break_loop; break; - case MKTAG('f','a','c','t'): + case MKTAG('f', 'a', 'c', 't'): if (!sample_count) sample_count = avio_rl32(pb); break; - case MKTAG('b','e','x','t'): + case MKTAG('b', 'e', 'x', 't'): if ((ret = wav_parse_bext_tag(s, size)) < 0) return ret; break; @@ -323,15 +345,20 @@ static int wav_read_header(AVFormatContext *s) goto break_loop; } av_log(s, AV_LOG_DEBUG, "Found SMV data\n"); + wav->smv_given_first = 0; vst = avformat_new_stream(s, NULL); if (!vst) return AVERROR(ENOMEM); avio_r8(pb); vst->id = 1; vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; - vst->codec->codec_id = AV_CODEC_ID_MJPEG; + vst->codec->codec_id = AV_CODEC_ID_SMVJPEG; vst->codec->width = avio_rl24(pb); vst->codec->height = avio_rl24(pb); + if (ff_alloc_extradata(vst->codec, 4)) { + av_log(s, AV_LOG_ERROR, "Could not allocate extradata.\n"); + return AVERROR(ENOMEM); + } size = avio_rl24(pb); wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3; avio_rl24(pb); @@ -341,6 +368,12 @@ static int wav_read_header(AVFormatContext *s) avio_rl24(pb); avio_rl24(pb); wav->smv_frames_per_jpeg = avio_rl24(pb); + if (wav->smv_frames_per_jpeg > 65536) { + av_log(s, AV_LOG_ERROR, "too many frames per jpeg\n"); + return AVERROR_INVALIDDATA; + } + AV_WL32(vst->codec->extradata, wav->smv_frames_per_jpeg); + wav->smv_cur_pt = 0; goto break_loop; case MKTAG('L', 'I', 'S', 'T'): if (size < 4) { @@ -356,10 +389,11 @@ static int wav_read_header(AVFormatContext *s) /* seek to next tag unless we know that we'll run into EOF */ if ((avio_size(pb) > 0 && next_tag_ofs >= avio_size(pb)) || - avio_seek(pb, next_tag_ofs, SEEK_SET) < 0) { + wav_seek_tag(wav, pb, next_tag_ofs, SEEK_SET) < 0) { break; } } + break_loop: if (data_ofs < 0) { av_log(s, AV_LOG_ERROR, "no 'data' tag found\n"); @@ -368,8 +402,15 @@ break_loop: avio_seek(pb, data_ofs, SEEK_SET); - if (!sample_count && st->codec->channels && av_get_bits_per_sample(st->codec->codec_id) && wav->data_end <= avio_size(pb)) - sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); + if (!sample_count || av_get_exact_bits_per_sample(st->codec->codec_id) > 0) + if ( st->codec->channels + && data_size + && av_get_bits_per_sample(st->codec->codec_id) + && wav->data_end <= avio_size(pb)) + sample_count = (data_size << 3) + / + (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); + if (sample_count) st->duration = sample_count; @@ -379,7 +420,8 @@ break_loop: return 0; } -/** Find chunk with w64 GUID by skipping over other chunks +/** + * Find chunk with w64 GUID by skipping over other chunks. * @return the size of the found chunk */ static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16]) @@ -391,18 +433,17 @@ static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16]) avio_read(pb, guid, 16); size = avio_rl64(pb); if (size <= 24) - return -1; + return AVERROR_INVALIDDATA; if (!memcmp(guid, guid1, 16)) return size; avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24); } - return -1; + return AVERROR_EOF; } #define MAX_SIZE 4096 -static int wav_read_packet(AVFormatContext *s, - AVPacket *pkt) +static int wav_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, size; int64_t left; @@ -414,7 +455,7 @@ static int wav_read_packet(AVFormatContext *s, enum AVCodecID codec; ret = ff_spdif_probe(s->pb->buffer, s->pb->buf_end - s->pb->buffer, &codec); - if (ret > AVPROBE_SCORE_MAX / 2) { + if (ret > AVPROBE_SCORE_EXTENSION) { s->streams[0]->codec->codec_id = codec; wav->spdif = 1; } else { @@ -427,12 +468,15 @@ static int wav_read_packet(AVFormatContext *s, if (wav->smv_data_ofs > 0) { int64_t audio_dts, video_dts; smv_retry: - audio_dts = s->streams[0]->cur_dts; - video_dts = s->streams[1]->cur_dts; + audio_dts = (int32_t)s->streams[0]->cur_dts; + video_dts = (int32_t)s->streams[1]->cur_dts; + if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) { - audio_dts = av_rescale_q(audio_dts, s->streams[0]->time_base, AV_TIME_BASE_Q); - video_dts = av_rescale_q(video_dts, s->streams[1]->time_base, AV_TIME_BASE_Q); - wav->smv_last_stream = video_dts >= audio_dts; + /*We always return a video frame first to get the pixel format first*/ + wav->smv_last_stream = wav->smv_given_first ? + av_compare_ts(video_dts, s->streams[1]->time_base, + audio_dts, s->streams[0]->time_base) > 0 : 0; + wav->smv_given_first = 1; } wav->smv_last_stream = !wav->smv_last_stream; wav->smv_last_stream |= wav->audio_eof; @@ -450,8 +494,13 @@ smv_retry: if (ret < 0) goto smv_out; pkt->pos -= 3; - pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg; - wav->smv_block++; + pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg + wav->smv_cur_pt; + wav->smv_cur_pt++; + if (wav->smv_frames_per_jpeg > 0) + wav->smv_cur_pt %= wav->smv_frames_per_jpeg; + if (!wav->smv_cur_pt) + wav->smv_block++; + pkt->stream_index = 1; smv_out: avio_seek(s->pb, old_pos, SEEK_SET); @@ -467,19 +516,19 @@ smv_out: left = wav->data_end - avio_tell(s->pb); if (wav->ignore_length) - left= INT_MAX; - if (left <= 0){ + left = INT_MAX; + if (left <= 0) { if (CONFIG_W64_DEMUXER && wav->w64) left = find_guid(s->pb, ff_w64_guid_data) - 24; else - left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a')); + left = find_tag(wav, s->pb, MKTAG('d', 'a', 't', 'a')); if (left < 0) { wav->audio_eof = 1; if (wav->smv_data_ofs > 0 && !wav->smv_eof) goto smv_retry; return AVERROR_EOF; } - wav->data_end= avio_tell(s->pb) + left; + wav->data_end = avio_tell(s->pb) + left; } size = MAX_SIZE; @@ -510,7 +559,10 @@ static int wav_read_seek(AVFormatContext *s, smv_timestamp = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[1]->time_base); else timestamp = av_rescale_q(smv_timestamp, s->streams[1]->time_base, s->streams[0]->time_base); - wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; + if (wav->smv_frames_per_jpeg > 0) { + wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg; + wav->smv_cur_pt = smv_timestamp % wav->smv_frames_per_jpeg; + } } st = s->streams[0]; @@ -549,12 +601,11 @@ AVInputFormat ff_wav_demuxer = { .read_packet = wav_read_packet, .read_seek = wav_read_seek, .flags = AVFMT_GENERIC_INDEX, - .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, + .codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 }, .priv_class = &wav_demuxer_class, }; #endif /* CONFIG_WAV_DEMUXER */ - #if CONFIG_W64_DEMUXER static int w64_probe(AVProbeData *p) { @@ -570,23 +621,24 @@ static int w64_probe(AVProbeData *p) static int w64_read_header(AVFormatContext *s) { int64_t size, data_ofs = 0; - AVIOContext *pb = s->pb; - WAVDemuxContext *wav = s->priv_data; + AVIOContext *pb = s->pb; + WAVDemuxContext *wav = s->priv_data; AVStream *st; uint8_t guid[16]; int ret; avio_read(pb, guid, 16); if (memcmp(guid, ff_w64_guid_riff, 16)) - return -1; + return AVERROR_INVALIDDATA; - if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8) /* riff + wave + fmt + sizes */ - return -1; + /* riff + wave + fmt + sizes */ + if (avio_rl64(pb) < 16 + 8 + 16 + 8 + 16 + 8) + return AVERROR_INVALIDDATA; avio_read(pb, guid, 16); if (memcmp(guid, ff_w64_guid_wave, 16)) { av_log(s, AV_LOG_ERROR, "could not find wave guid\n"); - return -1; + return AVERROR_INVALIDDATA; } wav->w64 = 1; @@ -629,7 +681,7 @@ static int w64_read_header(AVFormatContext *s) uint32_t count, chunk_size, i; start = avio_tell(pb); - end = start + size; + end = start + FFALIGN(size, INT64_C(8)) - 24; count = avio_rl32(pb); for (i = 0; i < count; i++) { @@ -655,7 +707,7 @@ static int w64_read_header(AVFormatContext *s) avio_skip(pb, end - avio_tell(pb)); } else { av_log(s, AV_LOG_DEBUG, "unknown guid: "FF_PRI_GUID"\n", FF_ARG_GUID(guid)); - avio_skip(pb, size - 24); + avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24); } } @@ -682,6 +734,6 @@ AVInputFormat ff_w64_demuxer = { .read_packet = wav_read_packet, .read_seek = wav_read_seek, .flags = AVFMT_GENERIC_INDEX, - .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, + .codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 }, }; #endif /* CONFIG_W64_DEMUXER */ diff --git a/ffmpeg/libavformat/wavenc.c b/ffmpeg/libavformat/wavenc.c index fea38cf..0067dfe 100644 --- a/ffmpeg/libavformat/wavenc.c +++ b/ffmpeg/libavformat/wavenc.c @@ -116,6 +116,11 @@ static int wav_write_header(AVFormatContext *s) AVIOContext *pb = s->pb; int64_t fmt; + if (s->nb_streams != 1) { + av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n"); + return AVERROR(EINVAL); + } + if (wav->rf64 == RF64_ALWAYS) { ffio_wfourcc(pb, "RF64"); avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ diff --git a/ffmpeg/libavformat/webvttdec.c b/ffmpeg/libavformat/webvttdec.c index 694a020..0654485 100644 --- a/ffmpeg/libavformat/webvttdec.c +++ b/ffmpeg/libavformat/webvttdec.c @@ -29,9 +29,12 @@ #include "subtitles.h" #include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" typedef struct { + const AVClass *class; FFDemuxSubtitlesQueue q; + int kind; } WebVTTContext; static int webvtt_probe(AVProbeData *p) @@ -66,6 +69,7 @@ static int webvtt_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, 1000); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_WEBVTT; + st->disposition |= webvtt->kind; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&cue, 0, AV_BPRINT_SIZE_UNLIMITED); @@ -74,8 +78,8 @@ static int webvtt_read_header(AVFormatContext *s) int i; int64_t pos; AVPacket *sub; - const char *p, *identifier; - //const char *settings = NULL; + const char *p, *identifier, *settings; + int identifier_len, settings_len; int64_t ts_start, ts_end; ff_subtitles_read_chunk(s->pb, &cue); @@ -92,15 +96,23 @@ static int webvtt_read_header(AVFormatContext *s) continue; /* optional cue identifier (can be a number like in SRT or some kind of - * chaptering id), silently skip it */ - for (i = 0; p[i] && p[i] != '\n'; i++) { + * chaptering id) */ + for (i = 0; p[i] && p[i] != '\n' && p[i] != '\r'; i++) { if (!strncmp(p + i, "-->", 3)) { identifier = NULL; break; } } - if (identifier) - p += strcspn(p, "\n"); + if (!identifier) + identifier_len = 0; + else { + identifier_len = strcspn(p, "\r\n"); + p += identifier_len; + if (*p == '\r') + p++; + if (*p == '\n') + p++; + } /* cue timestamps */ if ((ts_start = read_ts(p)) == AV_NOPTS_VALUE) @@ -112,14 +124,15 @@ static int webvtt_read_header(AVFormatContext *s) if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE) break; - /* optional cue settings, TODO: store in side_data */ + /* optional cue settings */ p += strcspn(p, "\n\t "); while (*p == '\t' || *p == ' ') p++; - if (*p != '\n') { - //settings = p; - p += strcspn(p, "\n"); - } + settings = p; + settings_len = strcspn(p, "\r\n"); + p += settings_len; + if (*p == '\r') + p++; if (*p == '\n') p++; @@ -132,6 +145,20 @@ static int webvtt_read_header(AVFormatContext *s) sub->pos = pos; sub->pts = ts_start; sub->duration = ts_end - ts_start; + +#define SET_SIDE_DATA(name, type) do { \ + if (name##_len) { \ + uint8_t *buf = av_packet_new_side_data(sub, type, name##_len); \ + if (!buf) { \ + res = AVERROR(ENOMEM); \ + goto end; \ + } \ + memcpy(buf, name, name##_len); \ + } \ +} while (0) + + SET_SIDE_DATA(identifier, AV_PKT_DATA_WEBVTT_IDENTIFIER); + SET_SIDE_DATA(settings, AV_PKT_DATA_WEBVTT_SETTINGS); } ff_subtitles_queue_finalize(&webvtt->q); @@ -163,6 +190,25 @@ static int webvtt_read_close(AVFormatContext *s) return 0; } +#define OFFSET(x) offsetof(WebVTTContext, x) +#define KIND_FLAGS AV_OPT_FLAG_SUBTITLE_PARAM + +static const AVOption options[] = { + { "kind", "Set kind of WebVTT track", OFFSET(kind), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, KIND_FLAGS, "webvtt_kind" }, + { "subtitles", "WebVTT subtitles kind", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, + { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, + { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, + { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, + { NULL } +}; + +static const AVClass webvtt_demuxer_class = { + .class_name = "WebVTT demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVInputFormat ff_webvtt_demuxer = { .name = "webvtt", .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"), @@ -173,4 +219,5 @@ AVInputFormat ff_webvtt_demuxer = { .read_seek2 = webvtt_read_seek, .read_close = webvtt_read_close, .extensions = "vtt", + .priv_class = &webvtt_demuxer_class, }; diff --git a/ffmpeg/libavformat/westwood_aud.c b/ffmpeg/libavformat/westwood_aud.c index d666117..f2bd3a1 100644 --- a/ffmpeg/libavformat/westwood_aud.c +++ b/ffmpeg/libavformat/westwood_aud.c @@ -77,7 +77,7 @@ static int wsaud_probe(AVProbeData *p) return 0; /* return 1/2 certainty since this file check is a little sketchy */ - return AVPROBE_SCORE_MAX / 2; + return AVPROBE_SCORE_EXTENSION; } static int wsaud_read_header(AVFormatContext *s) diff --git a/ffmpeg/libavformat/westwood_vqa.c b/ffmpeg/libavformat/westwood_vqa.c index c996dad..2a988ad 100644 --- a/ffmpeg/libavformat/westwood_vqa.c +++ b/ffmpeg/libavformat/westwood_vqa.c @@ -81,10 +81,10 @@ static int wsvqa_read_header(AVFormatContext *s) WsVqaDemuxContext *wsvqa = s->priv_data; AVIOContext *pb = s->pb; AVStream *st; - unsigned char *header; - unsigned char scratch[VQA_PREAMBLE_SIZE]; - unsigned int chunk_tag; - unsigned int chunk_size; + uint8_t *header; + uint8_t scratch[VQA_PREAMBLE_SIZE]; + uint32_t chunk_tag; + uint32_t chunk_size; int fps; /* initialize the video decoder stream */ @@ -101,14 +101,9 @@ static int wsvqa_read_header(AVFormatContext *s) avio_seek(pb, 20, SEEK_SET); /* the VQA header needs to go to the decoder */ - st->codec->extradata_size = VQA_HEADER_SIZE; - st->codec->extradata = av_mallocz(VQA_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); - header = (unsigned char *)st->codec->extradata; - if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) != - VQA_HEADER_SIZE) { - av_free(st->codec->extradata); - return AVERROR(EIO); - } + if (ff_get_extradata(st->codec, pb, VQA_HEADER_SIZE) < 0) + return AVERROR(ENOMEM); + header = (uint8_t *)st->codec->extradata; st->codec->width = AV_RL16(&header[6]); st->codec->height = AV_RL16(&header[8]); fps = header[12]; @@ -167,9 +162,9 @@ static int wsvqa_read_packet(AVFormatContext *s, WsVqaDemuxContext *wsvqa = s->priv_data; AVIOContext *pb = s->pb; int ret = -1; - unsigned char preamble[VQA_PREAMBLE_SIZE]; - unsigned int chunk_type; - unsigned int chunk_size; + uint8_t preamble[VQA_PREAMBLE_SIZE]; + uint32_t chunk_type; + uint32_t chunk_size; int skip_byte; while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) { @@ -220,9 +215,7 @@ static int wsvqa_read_packet(AVFormatContext *s, break; case SND2_TAG: st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_WS; - st->codec->extradata_size = 2; - st->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) + if (ff_alloc_extradata(st->codec, 2)) return AVERROR(ENOMEM); AV_WL16(st->codec->extradata, wsvqa->version); break; diff --git a/ffmpeg/libavformat/wtv.c b/ffmpeg/libavformat/wtv.c deleted file mode 100644 index 5b1e61b..0000000 --- a/ffmpeg/libavformat/wtv.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Windows Television (WTV) - * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org> - * - * This file is part of FFmpeg. - * - * 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. - * - * 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 FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "wtv.h" - -/* WTV GUIDs*/ -const ff_asf_guid ff_dir_entry_guid = - {0x92,0xB7,0x74,0x91,0x59,0x70,0x70,0x44,0x88,0xDF,0x06,0x3B,0x82,0xCC,0x21,0x3D}; -const ff_asf_guid ff_wtv_guid = - {0xB7,0xD8,0x00,0x20,0x37,0x49,0xDA,0x11,0xA6,0x4E,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -const ff_asf_guid ff_timestamp_guid = - {0x5B,0x05,0xE6,0x1B,0x97,0xA9,0x49,0x43,0x88,0x17,0x1A,0x65,0x5A,0x29,0x8A,0x97}; -const ff_asf_guid ff_data_guid = - {0x95,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT = - {0xED,0xA4,0x13,0x23,0x2D,0xBF,0x4F,0x45,0xAD,0x8A,0xD9,0x5B,0xA7,0xF9,0x1F,0xEE}; -const ff_asf_guid ff_stream1_guid = - {0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -const ff_asf_guid ff_sync_guid = - {0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -const ff_asf_guid ff_index_guid = - {0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -const ff_asf_guid ff_mediatype_audio = - {'a','u','d','s',FF_MEDIASUBTYPE_BASE_GUID}; -const ff_asf_guid ff_mediatype_video = - {'v','i','d','s',FF_MEDIASUBTYPE_BASE_GUID}; -const ff_asf_guid ff_format_none = - {0xD6,0x17,0x64,0x0F,0x18,0xC3,0xD0,0x11,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96}; - -/* declare utf16le strings */ -#define _ , 0, -const uint8_t ff_timeline_le16[] = - {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0}; -const uint8_t ff_timeline_table_0_entries_Events_le16[] = - {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0}; -const uint8_t ff_table_0_entries_legacy_attrib_le16[] = - {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0}; -const uint8_t ff_table_0_entries_time_le16[] = - {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'t'_'i'_'m'_'e', 0}; -#undef _ - -const ff_asf_guid ff_DSATTRIB_TRANSPORT_PROPERTIES = - {0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A}; -const ff_asf_guid ff_metadata_guid = - {0x5A,0xFE,0xD7,0x6D,0xC8,0x1D,0x8F,0x4A,0x99,0x22,0xFA,0xB1,0x1C,0x38,0x14,0x53}; -const ff_asf_guid ff_stream2_guid = - {0xA2,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; - -/* Media subtypes */ -const ff_asf_guid ff_mediasubtype_cpfilters_processed = - {0x28,0xBD,0xAD,0x46,0xD0,0x6F,0x96,0x47,0x93,0xB2,0x15,0x5C,0x51,0xDC,0x04,0x8D}; - -/* Formats */ -const ff_asf_guid ff_format_cpfilters_processed = - {0x6F,0xB3,0x39,0x67,0x5F,0x1D,0xC2,0x4A,0x81,0x92,0x28,0xBB,0x0E,0x73,0xD1,0x6A}; -const ff_asf_guid ff_format_waveformatex = - {0x81,0x9F,0x58,0x05,0x56,0xC3,0xCE,0x11,0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A}; -const ff_asf_guid ff_format_mpeg2_video = - {0xE3,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}; - -const AVCodecGuid ff_video_guids[] = { - {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, - {AV_CODEC_ID_NONE} -}; diff --git a/ffmpeg/libavformat/wtv.h b/ffmpeg/libavformat/wtv.h index efe90d6..f26ad5e 100644 --- a/ffmpeg/libavformat/wtv.h +++ b/ffmpeg/libavformat/wtv.h @@ -55,4 +55,6 @@ extern const ff_asf_guid ff_mediasubtype_cpfilters_processed; extern const ff_asf_guid ff_format_cpfilters_processed; extern const ff_asf_guid ff_format_waveformatex; extern const ff_asf_guid ff_format_mpeg2_video; +extern const ff_asf_guid ff_format_videoinfo2; + #endif /* AVFORMAT_WTV_H */ diff --git a/ffmpeg/libavformat/wtvdec.c b/ffmpeg/libavformat/wtvdec.c index e423370..21236fa 100644 --- a/ffmpeg/libavformat/wtvdec.c +++ b/ffmpeg/libavformat/wtvdec.c @@ -47,17 +47,22 @@ */ typedef struct { - AVIOContext *pb_filesystem; /** file system (AVFormatContext->pb) */ + AVIOContext *pb_filesystem; /**< file system (AVFormatContext->pb) */ - int sector_bits; /** sector shift bits; used to convert sector number into pb_filesystem offset */ - uint32_t *sectors; /** file allocation table */ - int nb_sectors; /** number of sectors */ + int sector_bits; /**< sector shift bits; used to convert sector number into pb_filesystem offset */ + uint32_t *sectors; /**< file allocation table */ + int nb_sectors; /**< number of sectors */ int error; int64_t position; int64_t length; } WtvFile; +static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset) +{ + return avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET); +} + /** * @return bytes read, 0 on end of file, or <0 on error */ @@ -88,7 +93,7 @@ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) int i = wf->position >> wf->sector_bits; if (i >= wf->nb_sectors || (wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) && - avio_seek(pb, (int64_t)wf->sectors[i] << WTV_SECTOR_BITS, SEEK_SET) < 0)) { + seek_by_sector(pb, wf->sectors[i], 0) < 0)) { wf->error = 1; break; } @@ -113,8 +118,8 @@ static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence) offset = wf->length; wf->error = offset < 0 || offset >= wf->length || - avio_seek(pb, ((int64_t)wf->sectors[offset >> wf->sector_bits] << WTV_SECTOR_BITS) - + (offset & ((1 << wf->sector_bits) - 1)), SEEK_SET) < 0; + seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits], + offset & ((1 << wf->sector_bits) - 1)) < 0; wf->position = offset; return offset; } @@ -148,8 +153,9 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int AVIOContext *pb; WtvFile *wf; uint8_t *buffer; + int64_t size; - if (avio_seek(s->pb, (int64_t)first_sector << WTV_SECTOR_BITS, SEEK_SET) < 0) + if (seek_by_sector(s->pb, first_sector, 0) < 0) return NULL; wf = av_mallocz(sizeof(WtvFile)); @@ -176,14 +182,14 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4); int i; - wf->sectors = av_malloc(nb_sectors1 << WTV_SECTOR_BITS); + wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS); if (!wf->sectors) { av_free(wf); return NULL; } wf->nb_sectors = 0; for (i = 0; i < nb_sectors1; i++) { - if (avio_seek(s->pb, (int64_t)sectors1[i] << WTV_SECTOR_BITS, SEEK_SET) < 0) + if (seek_by_sector(s->pb, sectors1[i], 0) < 0) break; wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4); } @@ -200,7 +206,8 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int return NULL; } - if ((int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > avio_tell(s->pb)) + size = avio_size(s->pb); + if (size >= 0 && (int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > size) av_log(s, AV_LOG_WARNING, "truncated file\n"); /* check length */ @@ -213,7 +220,7 @@ static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int /* seek to initial sector */ wf->position = 0; - if (avio_seek(s->pb, (int64_t)wf->sectors[0] << WTV_SECTOR_BITS, SEEK_SET) < 0) { + if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) { av_free(wf->sectors); av_free(wf); return NULL; @@ -261,7 +268,12 @@ static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int b dir_length = AV_RL16(buf + 16); file_length = AV_RL64(buf + 24); name_size = 2 * AV_RL32(buf + 32); - if (buf + 48 + (int64_t)name_size > buf_end || name_size<0) { + if (name_size < 0) { + av_log(s, AV_LOG_ERROR, + "bad filename length, remaining directory entries ignored\n"); + break; + } + if (48 + (int64_t)name_size > buf_end - buf) { av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n"); break; } @@ -306,10 +318,10 @@ typedef struct { } WtvStream; typedef struct { - AVIOContext *pb; /** timeline file */ + AVIOContext *pb; /**< timeline file */ int64_t epoch; - int64_t pts; /** pts for next data chunk */ - int64_t last_valid_pts; /** latest valid pts, used for interative seeking */ + int64_t pts; /**< pts for next data chunk */ + int64_t last_valid_pts; /**< latest valid pts, used for interative seeking */ /* maintain private seek index, as the AVIndexEntry->pos is relative to the start of the 'timeline' file, not the file system (AVFormatContext->pb) */ @@ -360,10 +372,6 @@ static const ff_asf_guid mediasubtype_dtvccdata = static const ff_asf_guid mediasubtype_mpeg2_sections = {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61}; -/* Formats */ -static const ff_asf_guid format_videoinfo2 = - {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA}; - static int read_probe(AVProbeData *p) { return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX; @@ -436,6 +444,7 @@ static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length) av_dict_set(&st->metadata, "title", description, 0); st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = AV_CODEC_ID_MJPEG; + st->id = -1; ret = av_get_packet(pb, &st->attached_pic, filesize); if (ret < 0) goto done; @@ -495,7 +504,7 @@ static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int ty else snprintf(buf, buf_size, "%"PRIi64, num); } else if (type == 5 && length == 2) { - snprintf(buf, buf_size, "%"PRIi16, avio_rl16(pb)); + snprintf(buf, buf_size, "%u", avio_rl16(pb)); } else if (type == 6 && length == 16) { ff_asf_guid guid; avio_read(pb, guid, 16); @@ -678,7 +687,7 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO); if (!st) return NULL; - if (!ff_guidcmp(formattype, format_videoinfo2)) { + if (!ff_guidcmp(formattype, ff_format_videoinfo2)) { int consumed = parse_videoinfoheader2(s, st); avio_skip(pb, FFMAX(size - consumed, 0)); } else if (!ff_guidcmp(formattype, ff_format_mpeg2_video)) { @@ -935,7 +944,7 @@ static int read_header(AVFormatContext *s) avio_skip(s->pb, 4); root_sector = avio_rl32(s->pb); - avio_seek(s->pb, (int64_t)root_sector << WTV_SECTOR_BITS, SEEK_SET); + seek_by_sector(s->pb, root_sector, 0); root_size = avio_read(s->pb, root, root_size); if (root_size < 0) return AVERROR_INVALIDDATA; diff --git a/ffmpeg/libavformat/wtvenc.c b/ffmpeg/libavformat/wtvenc.c index 22917a4..5e3b9b9 100644 --- a/ffmpeg/libavformat/wtvenc.c +++ b/ffmpeg/libavformat/wtvenc.c @@ -28,6 +28,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/avassert.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "wtv.h" #include "asf.h" @@ -87,10 +88,10 @@ typedef struct { typedef struct { int64_t timeline_start_pos; WtvFile file[WTV_FILES]; - int64_t serial; /** chunk serial number */ - int64_t last_chunk_pos; /** last chunk position */ - int64_t last_timestamp_pos; /** last timestamp chunk position */ - int64_t first_index_pos; /** first index_chunk position */ + int64_t serial; /**< chunk serial number */ + int64_t last_chunk_pos; /**< last chunk position */ + int64_t last_timestamp_pos; /**< last timestamp chunk position */ + int64_t first_index_pos; /**< first index_chunk position */ WtvChunkEntry index[MAX_NB_INDEX]; int nb_index; @@ -127,12 +128,7 @@ typedef struct { WTVHeaderWriteFunc *write_header; } WTVRootEntryTable; -static int write_pad(AVIOContext *pb, int size) -{ - for (; size > 0; size--) - avio_w8(pb, 0); - return 0; -} +#define write_pad(pb, size) ffio_fill(pb, 0, size) static const ff_asf_guid *get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid) { @@ -227,10 +223,52 @@ static void finish_chunk(AVFormatContext *s) write_index(s); } +static void put_videoinfoheader2(AVIOContext *pb, AVStream *st) +{ + AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational){st->codec->width, st->codec->height}); + unsigned int num, den; + av_reduce(&num, &den, dar.num, dar.den, 0xFFFFFFFF); + + /* VIDEOINFOHEADER2 */ + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, st->codec->width); + avio_wl32(pb, st->codec->height); + + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + avio_wl32(pb, st->codec->bit_rate); + avio_wl32(pb, 0); + avio_wl64(pb, st->avg_frame_rate.num && st->avg_frame_rate.den ? INT64_C(10000000) / av_q2d(st->avg_frame_rate) : 0); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + avio_wl32(pb, num); + avio_wl32(pb, den); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0, 1); + + if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + /* MPEG2VIDEOINFO */ + avio_wl32(pb, 0); + avio_wl32(pb, st->codec->extradata_size); + avio_wl32(pb, -1); + avio_wl32(pb, -1); + avio_wl32(pb, 0); + avio_write(pb, st->codec->extradata, st->codec->extradata_size); + avio_wl64(pb, 0); + } +} + static int write_stream_codec_info(AVFormatContext *s, AVStream *st) { - WtvContext *wctx = s->priv_data; const ff_asf_guid *g, *media_type, *format_type; + const AVCodecTag *tags; AVIOContext *pb = s->pb; int64_t hdr_pos_start; int hdr_size = 0; @@ -238,21 +276,18 @@ static int write_stream_codec_info(AVFormatContext *s, AVStream *st) if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { g = get_codec_guid(st->codec->codec_id, ff_video_guids); media_type = &ff_mediatype_video; - format_type = &ff_format_mpeg2_video; + format_type = st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO ? &ff_format_mpeg2_video : &ff_format_videoinfo2; + tags = ff_codec_bmp_tags; } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { g = get_codec_guid(st->codec->codec_id, ff_codec_wav_guids); media_type = &ff_mediatype_audio; format_type = &ff_format_waveformatex; + tags = ff_codec_wav_tags; } else { av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type); return -1; } - if (g == NULL) { - av_log(s, AV_LOG_ERROR, "can't get video codec_id (0x%x) guid.\n", st->codec->codec_id); - return -1; - } - ff_put_guid(pb, media_type); // mediatype ff_put_guid(pb, &ff_mediasubtype_cpfilters_processed); // subtype write_pad(pb, 12); @@ -261,15 +296,10 @@ static int write_stream_codec_info(AVFormatContext *s, AVStream *st) hdr_pos_start = avio_tell(pb); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - if (wctx->first_video_flag) { - write_pad(pb, 216); //The size is sensitive. - wctx->first_video_flag = 0; - } else { - write_pad(pb, 72); // aspect ratio - ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0); - } + put_videoinfoheader2(pb, st); } else { - ff_put_wav_header(pb, st->codec); + if (ff_put_wav_header(pb, st->codec) < 0) + format_type = &ff_format_none; } hdr_size = avio_tell(pb) - hdr_pos_start; @@ -277,7 +307,17 @@ static int write_stream_codec_info(AVFormatContext *s, AVStream *st) avio_seek(pb, -(hdr_size + 4), SEEK_CUR); avio_wl32(pb, hdr_size + 32); avio_seek(pb, hdr_size, SEEK_CUR); - ff_put_guid(pb, g); // actual_subtype + if (g) { + ff_put_guid(pb, g); // actual_subtype + } else { + int tag = ff_codec_get_tag(tags, st->codec->codec_id); + if (!tag) { + av_log(s, AV_LOG_ERROR, "unsupported codec_id (0x%x)\n", st->codec->codec_id); + return -1; + } + avio_wl32(pb, tag); + avio_write(pb, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12); + } ff_put_guid(pb, format_type); // actual_formattype return 0; @@ -457,7 +497,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) write_pad(pb, WTV_PAD8(pkt->size) - pkt->size); wctx->serial++; - avio_flush(pb); return 0; } diff --git a/ffmpeg/libavformat/wv.c b/ffmpeg/libavformat/wv.c index 97a6c1f..0f4f807 100644 --- a/ffmpeg/libavformat/wv.c +++ b/ffmpeg/libavformat/wv.c @@ -1,6 +1,5 @@ /* - * WavPack demuxer - * Copyright (c) 2006,2011 Konstantin Shishkov + * WavPack shared functions * * This file is part of FFmpeg. * @@ -19,379 +18,35 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/channel_layout.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/dict.h" -#include "avformat.h" -#include "internal.h" -#include "apetag.h" -#include "id3v1.h" - -// specs say that maximum block size is 1Mb -#define WV_BLOCK_LIMIT 1047576 - -#define WV_EXTRA_SIZE 12 - -#define WV_START_BLOCK 0x0800 -#define WV_END_BLOCK 0x1000 -#define WV_SINGLE_BLOCK (WV_START_BLOCK | WV_END_BLOCK) - -enum WV_FLAGS { - WV_MONO = 0x0004, - WV_HYBRID = 0x0008, - WV_JOINT = 0x0010, - WV_CROSSD = 0x0020, - WV_HSHAPE = 0x0040, - WV_FLOAT = 0x0080, - WV_INT32 = 0x0100, - WV_HBR = 0x0200, - WV_HBAL = 0x0400, - WV_MCINIT = 0x0800, - WV_MCEND = 0x1000, -}; +#include <stdint.h> +#include <string.h> -static const int wv_rates[16] = { - 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, 192000, -1 -}; - -typedef struct { - uint32_t blksize, flags; - int rate, chan, bpp; - uint32_t chmask; - uint32_t samples, soff; - int multichannel; - int block_parsed; - uint8_t extra[WV_EXTRA_SIZE]; - int64_t pos; - - int64_t apetag_start; -} WVContext; +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" -static int wv_probe(AVProbeData *p) -{ - /* check file header */ - if (p->buf_size <= 32) - return 0; - if (p->buf[0] == 'w' && p->buf[1] == 'v' && - p->buf[2] == 'p' && p->buf[3] == 'k') - return AVPROBE_SCORE_MAX; - else - return 0; -} +#include "wv.h" -static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb, - int append) +int ff_wv_parse_header(WvHeader *wv, const uint8_t *data) { - WVContext *wc = ctx->priv_data; - uint32_t tag, ver; - int size; - int rate, bpp, chan; - uint32_t chmask; - - wc->pos = avio_tell(pb); - - /* don't return bogus packets with the ape tag data */ - if (wc->apetag_start && wc->pos >= wc->apetag_start) - return AVERROR_EOF; + memset(wv, 0, sizeof(*wv)); - if (!append) { - tag = avio_rl32(pb); - if (tag != MKTAG('w', 'v', 'p', 'k')) - return AVERROR_INVALIDDATA; - size = avio_rl32(pb); - if (size < 24 || size > WV_BLOCK_LIMIT) { - av_log(ctx, AV_LOG_ERROR, "Incorrect block size %i\n", size); - return AVERROR_INVALIDDATA; - } - wc->blksize = size; - ver = avio_rl16(pb); - if (ver < 0x402 || ver > 0x410) { - av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); - return AVERROR_PATCHWELCOME; - } - avio_r8(pb); // track no - avio_r8(pb); // track sub index - wc->samples = avio_rl32(pb); // total samples in file - wc->soff = avio_rl32(pb); // offset in samples of current block - avio_read(pb, wc->extra, WV_EXTRA_SIZE); - } else { - size = wc->blksize; - } - wc->flags = AV_RL32(wc->extra + 4); - /* Blocks with zero samples don't contain actual audio information - * and should be ignored */ - if (!AV_RN32(wc->extra)) - return 0; - // parse flags - bpp = ((wc->flags & 3) + 1) << 3; - chan = 1 + !(wc->flags & WV_MONO); - chmask = wc->flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; - rate = wv_rates[(wc->flags >> 23) & 0xF]; - wc->multichannel = !!((wc->flags & WV_SINGLE_BLOCK) != WV_SINGLE_BLOCK); - if (wc->multichannel) { - chan = wc->chan; - chmask = wc->chmask; - } - if ((rate == -1 || !chan) && !wc->block_parsed) { - int64_t block_end = avio_tell(pb) + wc->blksize - 24; - if (!pb->seekable) { - av_log(ctx, AV_LOG_ERROR, - "Cannot determine additional parameters\n"); - return AVERROR_INVALIDDATA; - } - while (avio_tell(pb) < block_end) { - int id, size; - id = avio_r8(pb); - size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb); - size <<= 1; - if (id & 0x40) - size--; - switch (id & 0x3F) { - case 0xD: - if (size <= 1) { - av_log(ctx, AV_LOG_ERROR, - "Insufficient channel information\n"); - return AVERROR_INVALIDDATA; - } - chan = avio_r8(pb); - switch (size - 2) { - case 0: - chmask = avio_r8(pb); - break; - case 1: - chmask = avio_rl16(pb); - break; - case 2: - chmask = avio_rl24(pb); - break; - case 3: - chmask = avio_rl32(pb); - break; - case 5: - avio_skip(pb, 1); - chan |= (avio_r8(pb) & 0xF) << 8; - chmask = avio_rl24(pb); - break; - default: - av_log(ctx, AV_LOG_ERROR, - "Invalid channel info size %d\n", size); - return AVERROR_INVALIDDATA; - } - break; - case 0x27: - rate = avio_rl24(pb); - break; - default: - avio_skip(pb, size); - } - if (id & 0x40) - avio_skip(pb, 1); - } - if (rate == -1) { - av_log(ctx, AV_LOG_ERROR, - "Cannot determine custom sampling rate\n"); - return AVERROR_INVALIDDATA; - } - avio_seek(pb, block_end - wc->blksize + 24, SEEK_SET); - } - if (!wc->bpp) - wc->bpp = bpp; - if (!wc->chan) - wc->chan = chan; - if (!wc->chmask) - wc->chmask = chmask; - if (!wc->rate) - wc->rate = rate; - - if (wc->flags && bpp != wc->bpp) { - av_log(ctx, AV_LOG_ERROR, - "Bits per sample differ, this block: %i, header block: %i\n", - bpp, wc->bpp); - return AVERROR_INVALIDDATA; - } - if (wc->flags && !wc->multichannel && chan != wc->chan) { - av_log(ctx, AV_LOG_ERROR, - "Channels differ, this block: %i, header block: %i\n", - chan, wc->chan); + if (AV_RL32(data) != MKTAG('w', 'v', 'p', 'k')) return AVERROR_INVALIDDATA; - } - if (wc->flags && rate != -1 && rate != wc->rate) { - av_log(ctx, AV_LOG_ERROR, - "Sampling rate differ, this block: %i, header block: %i\n", - rate, wc->rate); - return AVERROR_INVALIDDATA; - } - wc->blksize = size - 24; - return 0; -} -static int wv_read_header(AVFormatContext *s) -{ - AVIOContext *pb = s->pb; - WVContext *wc = s->priv_data; - AVStream *st; - int ret; - - wc->block_parsed = 0; - for (;;) { - if ((ret = wv_read_block_header(s, pb, 0)) < 0) - return ret; - if (!AV_RN32(wc->extra)) - avio_skip(pb, wc->blksize - 24); - else - break; - } - - /* now we are ready: build format streams */ - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - st->codec->codec_type = AVMEDIA_TYPE_AUDIO; - st->codec->codec_id = AV_CODEC_ID_WAVPACK; - st->codec->channels = wc->chan; - st->codec->channel_layout = wc->chmask; - st->codec->sample_rate = wc->rate; - st->codec->bits_per_coded_sample = wc->bpp; - avpriv_set_pts_info(st, 64, 1, wc->rate); - st->start_time = 0; - if (wc->samples != 0xFFFFFFFFu) - st->duration = wc->samples; - - if (s->pb->seekable) { - int64_t cur = avio_tell(s->pb); - wc->apetag_start = ff_ape_parse_tag(s); - if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) - ff_id3v1_read(s); - avio_seek(s->pb, cur, SEEK_SET); - } - - return 0; -} - -static int wv_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - WVContext *wc = s->priv_data; - int ret; - int size, ver, off; - int64_t pos; - uint32_t block_samples; - - if (url_feof(s->pb)) - return AVERROR_EOF; - if (wc->block_parsed) { - if ((ret = wv_read_block_header(s, s->pb, 0)) < 0) - return ret; - } - - pos = wc->pos; - off = wc->multichannel ? 4 : 0; - if (av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE + off) < 0) - return AVERROR(ENOMEM); - if (wc->multichannel) - AV_WL32(pkt->data, wc->blksize + WV_EXTRA_SIZE + 12); - memcpy(pkt->data + off, wc->extra, WV_EXTRA_SIZE); - ret = avio_read(s->pb, pkt->data + WV_EXTRA_SIZE + off, wc->blksize); - if (ret != wc->blksize) { - av_free_packet(pkt); - return AVERROR(EIO); - } - while (!(wc->flags & WV_END_BLOCK)) { - if (avio_rl32(s->pb) != MKTAG('w', 'v', 'p', 'k')) { - av_free_packet(pkt); - return AVERROR_INVALIDDATA; - } - if ((ret = av_append_packet(s->pb, pkt, 4)) < 0) { - av_free_packet(pkt); - return ret; - } - size = AV_RL32(pkt->data + pkt->size - 4); - if (size < 24 || size > WV_BLOCK_LIMIT) { - av_free_packet(pkt); - av_log(s, AV_LOG_ERROR, "Incorrect block size %d\n", size); - return AVERROR_INVALIDDATA; - } - wc->blksize = size; - ver = avio_rl16(s->pb); - if (ver < 0x402 || ver > 0x410) { - av_free_packet(pkt); - av_log(s, AV_LOG_ERROR, "Unsupported version %03X\n", ver); - return AVERROR_PATCHWELCOME; - } - avio_r8(s->pb); // track no - avio_r8(s->pb); // track sub index - wc->samples = avio_rl32(s->pb); // total samples in file - wc->soff = avio_rl32(s->pb); // offset in samples of current block - if ((ret = av_append_packet(s->pb, pkt, WV_EXTRA_SIZE)) < 0) { - av_free_packet(pkt); - return ret; - } - memcpy(wc->extra, pkt->data + pkt->size - WV_EXTRA_SIZE, WV_EXTRA_SIZE); - - if ((ret = wv_read_block_header(s, s->pb, 1)) < 0) { - av_free_packet(pkt); - return ret; - } - ret = av_append_packet(s->pb, pkt, wc->blksize); - if (ret < 0) { - av_free_packet(pkt); - return ret; - } - } - pkt->stream_index = 0; - wc->block_parsed = 1; - pkt->pts = wc->soff; - block_samples = AV_RL32(wc->extra); - if (block_samples > INT32_MAX) - av_log(s, AV_LOG_WARNING, - "Too many samples in block: %"PRIu32"\n", block_samples); - else - pkt->duration = block_samples; - - av_add_index_entry(s->streams[0], pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME); - return 0; -} + wv->blocksize = AV_RL32(data + 4); + if (wv->blocksize < 24 || wv->blocksize > WV_BLOCK_LIMIT) + return AVERROR_INVALIDDATA; + wv->blocksize -= 24; -static int wv_read_seek(AVFormatContext *s, int stream_index, - int64_t timestamp, int flags) -{ - AVStream *st = s->streams[stream_index]; - WVContext *wc = s->priv_data; - AVPacket pkt1, *pkt = &pkt1; - int ret; - int index = av_index_search_timestamp(st, timestamp, flags); - int64_t pos, pts; + wv->version = AV_RL16(data + 8); + wv->total_samples = AV_RL32(data + 12); + wv->block_idx = AV_RL32(data + 16); + wv->samples = AV_RL32(data + 20); + wv->flags = AV_RL32(data + 24); + wv->crc = AV_RL32(data + 28); - /* if found, seek there */ - if (index >= 0 && - timestamp <= st->index_entries[st->nb_index_entries - 1].timestamp) { - wc->block_parsed = 1; - avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET); - return 0; - } - /* if timestamp is out of bounds, return error */ - if (timestamp < 0 || timestamp >= s->duration) - return AVERROR(EINVAL); + wv->initial = !!(wv->flags & WV_FLAG_INITIAL_BLOCK); + wv->final = !!(wv->flags & WV_FLAG_FINAL_BLOCK); - pos = avio_tell(s->pb); - do { - ret = av_read_frame(s, pkt); - if (ret < 0) { - avio_seek(s->pb, pos, SEEK_SET); - return ret; - } - pts = pkt->pts; - av_free_packet(pkt); - } while(pts < timestamp); return 0; } - -AVInputFormat ff_wv_demuxer = { - .name = "wv", - .long_name = NULL_IF_CONFIG_SMALL("WavPack"), - .priv_data_size = sizeof(WVContext), - .read_probe = wv_probe, - .read_header = wv_read_header, - .read_packet = wv_read_packet, - .read_seek = wv_read_seek, -}; diff --git a/ffmpeg/libavformat/wvenc.c b/ffmpeg/libavformat/wvenc.c index 03d471e..b0d74ca 100644 --- a/ffmpeg/libavformat/wvenc.c +++ b/ffmpeg/libavformat/wvenc.c @@ -1,5 +1,6 @@ /* * WavPack muxer + * Copyright (c) 2013 Konstantin Shishkov <kostya.shishkov@gmail.com> * Copyright (c) 2012 Paul B Mahol * * This file is part of FFmpeg. @@ -19,126 +20,72 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/intreadwrite.h" -#include "avformat.h" -#include "internal.h" -#include "avio_internal.h" -#include "apetag.h" +#include "libavutil/attributes.h" -#define WV_EXTRA_SIZE 12 -#define WV_END_BLOCK 0x1000 +#include "apetag.h" +#include "avformat.h" +#include "wv.h" -typedef struct{ - uint32_t duration; -} WVMuxContext; +typedef struct WvMuxContext { + int64_t samples; +} WvMuxContext; -static int write_header(AVFormatContext *s) +static av_cold int wv_write_header(AVFormatContext *ctx) { - AVCodecContext *codec = s->streams[0]->codec; - - if (s->nb_streams > 1) { - av_log(s, AV_LOG_ERROR, "only one stream is supported\n"); - return AVERROR(EINVAL); - } - if (codec->codec_id != AV_CODEC_ID_WAVPACK) { - av_log(s, AV_LOG_ERROR, "unsupported codec\n"); + if (ctx->nb_streams > 1 || + ctx->streams[0]->codec->codec_id != AV_CODEC_ID_WAVPACK) { + av_log(ctx, AV_LOG_ERROR, "This muxer only supports a single WavPack stream.\n"); return AVERROR(EINVAL); } - if (codec->extradata_size > 0) { - avpriv_report_missing_feature(s, "remuxing from matroska container"); - return AVERROR_PATCHWELCOME; - } - avpriv_set_pts_info(s->streams[0], 64, 1, codec->sample_rate); return 0; } -static int write_packet(AVFormatContext *s, AVPacket *pkt) +static int wv_write_packet(AVFormatContext *ctx, AVPacket *pkt) { - WVMuxContext *wc = s->priv_data; - AVCodecContext *codec = s->streams[0]->codec; - AVIOContext *pb = s->pb; - uint64_t size; - uint32_t flags; - uint32_t left = pkt->size; - uint8_t *ptr = pkt->data; - int off = codec->channels > 2 ? 4 : 0; + WvMuxContext *s = ctx->priv_data; + WvHeader header; + int ret; - /* FIXME: Simplify decoder/demuxer so bellow code can support midstream - * change of stream parameters */ - wc->duration += pkt->duration; - ffio_wfourcc(pb, "wvpk"); - if (off) { - size = AV_RL32(pkt->data); - if (size <= 12) - return AVERROR_INVALIDDATA; - size -= 12; - } else { - size = pkt->size; + if (pkt->size < WV_HEADER_SIZE || + (ret = ff_wv_parse_header(&header, pkt->data)) < 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid WavPack packet.\n"); + return AVERROR(EINVAL); } + s->samples += header.samples; - if (size + off > left) - return AVERROR_INVALIDDATA; - - avio_wl32(pb, size + 12); - avio_wl16(pb, 0x410); - avio_w8(pb, 0); - avio_w8(pb, 0); - avio_wl32(pb, -1); - avio_wl32(pb, pkt->pts); - ptr += off; left -= off; - flags = AV_RL32(ptr + 4); - avio_write(pb, ptr, size); - ptr += size; left -= size; - - while (!(flags & WV_END_BLOCK) && - (left >= 4 + WV_EXTRA_SIZE)) { - ffio_wfourcc(pb, "wvpk"); - size = AV_RL32(ptr); - ptr += 4; left -= 4; - if (size < 24 || size - 24 > left) - return AVERROR_INVALIDDATA; - avio_wl32(pb, size); - avio_wl16(pb, 0x410); - avio_w8(pb, 0); - avio_w8(pb, 0); - avio_wl32(pb, -1); - avio_wl32(pb, pkt->pts); - flags = AV_RL32(ptr + 4); - avio_write(pb, ptr, WV_EXTRA_SIZE); - ptr += WV_EXTRA_SIZE; left -= WV_EXTRA_SIZE; - avio_write(pb, ptr, size - 24); - ptr += size - 24; left -= size - 24; - } - avio_flush(pb); + avio_write(ctx->pb, pkt->data, pkt->size); return 0; } -static int write_trailer(AVFormatContext *s) +static av_cold int wv_write_trailer(AVFormatContext *ctx) { - WVMuxContext *wc = s->priv_data; - AVIOContext *pb = s->pb; - - ff_ape_write(s); - - if (pb->seekable) { - avio_seek(pb, 12, SEEK_SET); - avio_wl32(pb, wc->duration); - avio_flush(pb); + WvMuxContext *s = ctx->priv_data; + + /* update total number of samples in the first block */ + if (ctx->pb->seekable && s->samples && + s->samples < UINT32_MAX) { + int64_t pos = avio_tell(ctx->pb); + avio_seek(ctx->pb, 12, SEEK_SET); + avio_wl32(ctx->pb, s->samples); + avio_seek(ctx->pb, pos, SEEK_SET); } + ff_ape_write_tag(ctx); return 0; } AVOutputFormat ff_wv_muxer = { .name = "wv", - .long_name = NULL_IF_CONFIG_SMALL("WavPack"), - .priv_data_size = sizeof(WVMuxContext), + .long_name = NULL_IF_CONFIG_SMALL("raw WavPack"), + .mime_type = "audio/x-wavpack", .extensions = "wv", + .priv_data_size = sizeof(WvMuxContext), .audio_codec = AV_CODEC_ID_WAVPACK, .video_codec = AV_CODEC_ID_NONE, - .write_header = write_header, - .write_packet = write_packet, - .write_trailer = write_trailer, + .write_header = wv_write_header, + .write_packet = wv_write_packet, + .write_trailer = wv_write_trailer, + .flags = AVFMT_NOTIMESTAMPS, }; diff --git a/ffmpeg/libavformat/xa.c b/ffmpeg/libavformat/xa.c index e3d36e6..43661de 100644 --- a/ffmpeg/libavformat/xa.c +++ b/ffmpeg/libavformat/xa.c @@ -59,7 +59,7 @@ static int xa_probe(AVProbeData *p) if (!channels || channels > 8 || !srate || srate > 192000 || bits_per_sample < 4 || bits_per_sample > 32) return 0; - return AVPROBE_SCORE_MAX/2; + return AVPROBE_SCORE_EXTENSION; } static int xa_read_header(AVFormatContext *s) @@ -84,6 +84,9 @@ static int xa_read_header(AVFormatContext *s) avio_skip(pb, 2); /* Skip block align */ avio_skip(pb, 2); /* Skip bits-per-sample */ + if (!st->codec->channels || !st->codec->sample_rate) + return AVERROR_INVALIDDATA; + st->codec->bit_rate = av_clip(15LL * st->codec->channels * 8 * st->codec->sample_rate / 28, 0, INT_MAX); diff --git a/ffmpeg/libavformat/xmv.c b/ffmpeg/libavformat/xmv.c index e970477..20f9bea 100644 --- a/ffmpeg/libavformat/xmv.c +++ b/ffmpeg/libavformat/xmv.c @@ -49,6 +49,8 @@ XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \ XMV_AUDIO_ADPCM51_REARLEFTRIGHT) +#define XMV_BLOCK_ALIGN_SIZE 36 + /** A video packet with an XMV file. */ typedef struct XMVVideoPacket { int stream_index; ///< The decoder stream index for this video packet. @@ -124,6 +126,15 @@ static int xmv_probe(AVProbeData *p) return 0; } +static int xmv_read_close(AVFormatContext *s) +{ + XMVDemuxContext *xmv = s->priv_data; + + av_freep(&xmv->audio); + + return 0; +} + static int xmv_read_header(AVFormatContext *s) { XMVDemuxContext *xmv = s->priv_data; @@ -133,6 +144,7 @@ static int xmv_read_header(AVFormatContext *s) uint32_t file_version; uint32_t this_packet_size; uint16_t audio_track; + int ret; avio_skip(pb, 4); /* Next packet size */ @@ -171,8 +183,10 @@ static int xmv_read_header(AVFormatContext *s) avio_skip(pb, 2); /* Unknown (padding?) */ xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket)); - if (!xmv->audio) - return AVERROR(ENOMEM); + if (!xmv->audio) { + ret = AVERROR(ENOMEM); + goto fail; + } for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) { XMVAudioPacket *packet = &xmv->audio[audio_track]; @@ -184,15 +198,10 @@ static int xmv_read_header(AVFormatContext *s) packet->bits_per_sample = avio_rl16(pb); packet->flags = avio_rl16(pb); - if (!packet->channels) { - av_log(s, AV_LOG_ERROR, "0 channels\n"); - return AVERROR(EINVAL); - } - packet->bit_rate = packet->bits_per_sample * packet->sample_rate * packet->channels; - packet->block_align = 36 * packet->channels; + packet->block_align = XMV_BLOCK_ALIGN_SIZE * packet->channels; packet->block_samples = 64; packet->codec_id = ff_wav_codec_get_id(packet->compression, packet->bits_per_sample); @@ -208,9 +217,19 @@ static int xmv_read_header(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream " "(0x%04X)\n", packet->flags); + if (!packet->channels || !packet->sample_rate || + packet->channels >= UINT16_MAX / XMV_BLOCK_ALIGN_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid parameters for audio track %d.\n", + audio_track); + ret = AVERROR_INVALIDDATA; + goto fail; + } + ast = avformat_new_stream(s, NULL); - if (!ast) - return AVERROR(ENOMEM); + if (!ast) { + ret = AVERROR(ENOMEM); + goto fail; + } ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; ast->codec->codec_id = packet->codec_id; @@ -236,6 +255,10 @@ static int xmv_read_header(AVFormatContext *s) xmv->stream_count = xmv->audio_track_count + 1; return 0; + +fail: + xmv_read_close(s); + return ret; } static void xmv_read_extradata(uint8_t *extradata, AVIOContext *pb) @@ -360,9 +383,7 @@ static int xmv_process_packet_header(AVFormatContext *s) if (vst->codec->extradata_size < 4) { av_free(vst->codec->extradata); - vst->codec->extradata = - av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE); - vst->codec->extradata_size = 4; + ff_alloc_extradata(vst->codec, 4); } memcpy(vst->codec->extradata, xmv->video.extradata, 4); @@ -546,15 +567,6 @@ static int xmv_read_packet(AVFormatContext *s, return 0; } -static int xmv_read_close(AVFormatContext *s) -{ - XMVDemuxContext *xmv = s->priv_data; - - av_freep(&xmv->audio); - - return 0; -} - AVInputFormat ff_xmv_demuxer = { .name = "xmv", .long_name = NULL_IF_CONFIG_SMALL("Microsoft XMV"), diff --git a/ffmpeg/libavformat/xwma.c b/ffmpeg/libavformat/xwma.c index 0d40bd7..e629b3f 100644 --- a/ffmpeg/libavformat/xwma.c +++ b/ffmpeg/libavformat/xwma.c @@ -20,6 +20,7 @@ */ #include <inttypes.h> +#include <stdint.h> #include "avformat.h" #include "internal.h" @@ -199,8 +200,10 @@ static int xwma_read_header(AVFormatContext *s) /* Estimate the duration from the total number of output bytes. */ const uint64_t total_decoded_bytes = dpds_table[dpds_table_size - 1]; - if(!bytes_per_sample) { - av_log(s, AV_LOG_ERROR, "bytes_per_sample is 0\n"); + if (!bytes_per_sample) { + av_log(s, AV_LOG_ERROR, + "Invalid bits_per_coded_sample %d for %d channels\n", + st->codec->bits_per_coded_sample, st->codec->channels); return AVERROR_INVALIDDATA; } diff --git a/ffmpeg/libavformat/yop.c b/ffmpeg/libavformat/yop.c index d1c0129..07086d5 100644 --- a/ffmpeg/libavformat/yop.c +++ b/ffmpeg/libavformat/yop.c @@ -69,12 +69,7 @@ static int yop_read_header(AVFormatContext *s) return AVERROR(ENOMEM); // Extra data that will be passed to the decoder - video_stream->codec->extradata_size = 8; - - video_stream->codec->extradata = av_mallocz(video_stream->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - - if (!video_stream->codec->extradata) + if (ff_alloc_extradata(video_stream->codec, 8)) return AVERROR(ENOMEM); // Audio @@ -136,6 +131,12 @@ static int yop_read_packet(AVFormatContext *s, AVPacket *pkt) if (yop->video_packet.data) { *pkt = yop->video_packet; yop->video_packet.data = NULL; + yop->video_packet.buf = NULL; +#if FF_API_DESTRUCT_PACKET +FF_DISABLE_DEPRECATION_WARNINGS + yop->video_packet.destruct = NULL; +FF_ENABLE_DEPRECATION_WARNINGS +#endif yop->video_packet.size = 0; pkt->data[0] = yop->odd_frame; pkt->flags |= AV_PKT_FLAG_KEY; diff --git a/ffmpeg/libavformat/yuv4mpeg.c b/ffmpeg/libavformat/yuv4mpeg.c index f34a4af..1999c73 100644 --- a/ffmpeg/libavformat/yuv4mpeg.c +++ b/ffmpeg/libavformat/yuv4mpeg.c @@ -22,7 +22,6 @@ #include "libavutil/pixdesc.h" #include "avformat.h" #include "internal.h" -#include "libavutil/pixdesc.h" #define Y4M_MAGIC "YUV4MPEG2" #define Y4M_FRAME_MAGIC "FRAME" @@ -217,8 +216,8 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) // Adjust for smaller Cb and Cr planes av_pix_fmt_get_chroma_sub_sample(st->codec->pix_fmt, &h_chroma_shift, &v_chroma_shift); - width >>= h_chroma_shift; - height >>= v_chroma_shift; + width = FF_CEIL_RSHIFT(width, h_chroma_shift); + height = FF_CEIL_RSHIFT(height, v_chroma_shift); ptr1 = picture->data[1]; ptr2 = picture->data[2]; @@ -232,7 +231,6 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) } } - avio_flush(pb); return 0; } |
