diff options
Diffstat (limited to 'libavformat')
330 files changed, 11052 insertions, 4428 deletions
diff --git a/libavformat/4xm.c b/libavformat/4xm.c index fa6a26bcc2..342c22c169 100644 --- a/libavformat/4xm.c +++ b/libavformat/4xm.c @@ -2,20 +2,20 @@ * 4X Technologies .4xm File Demuxer (no muxer) * Copyright (c) 2003 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 */ @@ -173,8 +173,9 @@ static int fourxm_read_header(AVFormatContext *s) goto fail; } if (current_track + 1 > fourxm->track_count) { - fourxm->tracks = av_realloc(fourxm->tracks, - (current_track + 1) * sizeof(AudioTrack)); + fourxm->tracks = av_realloc_f(fourxm->tracks, + sizeof(AudioTrack), + current_track + 1); if (!fourxm->tracks) { ret = AVERROR(ENOMEM); goto fail; @@ -263,7 +264,7 @@ static int fourxm_read_packet(AVFormatContext *s, return ret; fourcc_tag = AV_RL32(&header[0]); size = AV_RL32(&header[4]); - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); switch (fourcc_tag) { diff --git a/libavformat/Makefile b/libavformat/Makefile index 45f757690d..623cd65234 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -1,3 +1,5 @@ +include $(SUBDIR)../config.mak + NAME = avformat FFLIBS = avcodec avutil @@ -21,12 +23,14 @@ OBJS-$(CONFIG_A64_MUXER) += a64.o OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.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_ADX_DEMUXER) += adxdec.o OBJS-$(CONFIG_ADX_MUXER) += rawenc.o OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o -OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o riff.o pcm.o -OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o riff.o +OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o riff.o pcm.o isom.o +OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o riff.o isom.o OBJS-$(CONFIG_AMR_DEMUXER) += amr.o OBJS-$(CONFIG_AMR_MUXER) += amr.o OBJS-$(CONFIG_ANM_DEMUXER) += anm.o @@ -48,10 +52,14 @@ OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o OBJS-$(CONFIG_BETHSOFTVID_DEMUXER) += bethsoftvid.o OBJS-$(CONFIG_BFI_DEMUXER) += bfi.o OBJS-$(CONFIG_BINK_DEMUXER) += bink.o +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_C93_DEMUXER) += c93.o vocdec.o voc.o OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ riff.o isom.o +OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o isom.o OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o @@ -96,13 +104,18 @@ OBJS-$(CONFIG_GXF_DEMUXER) += gxf.o OBJS-$(CONFIG_GXF_MUXER) += gxfenc.o audiointerleave.o OBJS-$(CONFIG_G722_DEMUXER) += rawdec.o OBJS-$(CONFIG_G722_MUXER) += rawenc.o +OBJS-$(CONFIG_G723_1_DEMUXER) += g723_1.o +OBJS-$(CONFIG_G723_1_MUXER) += rawenc.o +OBJS-$(CONFIG_G729_DEMUXER) += g729dec.o OBJS-$(CONFIG_H261_DEMUXER) += h261dec.o rawdec.o OBJS-$(CONFIG_H261_MUXER) += rawenc.o 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_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o +OBJS-$(CONFIG_IDF_DEMUXER) += bintext.o OBJS-$(CONFIG_IFF_DEMUXER) += iff.o OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2.o OBJS-$(CONFIG_IMAGE2_MUXER) += img2.o @@ -118,6 +131,7 @@ OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o OBJS-$(CONFIG_LATM_DEMUXER) += rawdec.o OBJS-$(CONFIG_LATM_MUXER) += latmenc.o OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o +OBJS-$(CONFIG_LOAS_DEMUXER) += loasdec.o OBJS-$(CONFIG_LXF_DEMUXER) += lxfdec.o OBJS-$(CONFIG_M4V_DEMUXER) += m4vdec.o rawdec.o OBJS-$(CONFIG_M4V_MUXER) += rawenc.o @@ -127,6 +141,8 @@ OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ riff.o isom.o avc.o \ flacenc_header.o avlanguage.o OBJS-$(CONFIG_MD5_MUXER) += md5enc.o +OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o +OBJS-$(CONFIG_MICRODVD_MUXER) += microdvdenc.o rawenc.o OBJS-$(CONFIG_MJPEG_DEMUXER) += rawdec.o OBJS-$(CONFIG_MJPEG_MUXER) += rawenc.o OBJS-$(CONFIG_MLP_DEMUXER) += rawdec.o @@ -268,6 +284,7 @@ OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o \ rtpenc_chain.o OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o OBJS-$(CONFIG_SAP_MUXER) += sapenc.o rtpenc_chain.o +OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o @@ -288,6 +305,7 @@ OBJS-$(CONFIG_SWF_DEMUXER) += swfdec.o OBJS-$(CONFIG_SWF_MUXER) += swfenc.o OBJS-$(CONFIG_THP_DEMUXER) += thp.o OBJS-$(CONFIG_TIERTEXSEQ_DEMUXER) += tiertexseq.o +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 @@ -310,10 +328,12 @@ OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \ flacenc_header.o avlanguage.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o -OBJS-$(CONFIG_WTV_DEMUXER) += wtv.o asfdec.o asf.o asfcrypt.o \ +OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv.o asfdec.o asf.o asfcrypt.o \ avlanguage.o mpegts.o isom.o riff.o +OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv.o asf.o asfenc.o riff.o OBJS-$(CONFIG_WV_DEMUXER) += wv.o apetag.o OBJS-$(CONFIG_XA_DEMUXER) += xa.o +OBJS-$(CONFIG_XBIN_DEMUXER) += bintext.o sauce.o OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o riff.o OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o riff.o OBJS-$(CONFIG_YOP_DEMUXER) += yop.o @@ -321,6 +341,7 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o # external libraries +OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o riff.o OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o riff.o @@ -328,6 +349,7 @@ OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o riff.o OBJS+= avio.o aviobuf.o OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += applehttpproto.o +OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o @@ -351,9 +373,5 @@ OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h - -EXAMPLES = metadata output TESTPROGS = seek TOOLS = aviocat ismindex pktdumper probetest - -$(SUBDIR)output-example$(EXESUF): ELIBS = -lswscale diff --git a/libavformat/a64.c b/libavformat/a64.c index 3cea50b6c5..4c8a942471 100644 --- a/libavformat/a64.c +++ b/libavformat/a64.c @@ -2,20 +2,20 @@ * a64 muxer * Copyright (c) 2009 Tobias Bindhammer * - * 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/libavformat/aacdec.c b/libavformat/aacdec.c index df94d15831..ff58c36675 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -3,20 +3,20 @@ * Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at> * Copyright (c) 2009 Robert Swain ( rob opendot cl ) * - * 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 */ @@ -48,6 +48,7 @@ static int adts_aac_probe(AVProbeData *p) fsize = (AV_RB32(buf2 + 3) >> 13) & 0x1FFF; if(fsize < 7) break; + fsize = FFMIN(fsize, end - buf2); buf2 += fsize; } max_frames = FFMAX(max_frames, frames); diff --git a/libavformat/ac3dec.c b/libavformat/ac3dec.c index ca6aee3685..f1421dc058 100644 --- a/libavformat/ac3dec.c +++ b/libavformat/ac3dec.c @@ -2,20 +2,20 @@ * RAW AC-3 and E-AC-3 demuxer * Copyright (c) 2007 Justin Ruggles <justin.ruggles@gmail.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 */ @@ -40,6 +40,8 @@ static int ac3_eac3_probe(AVProbeData *p, enum CodecID expected_codec_id) buf2 = buf; for(frames = 0; buf2 < end; frames++) { + if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) + buf2+=16; init_get_bits(&gbc, buf2, 54); if(avpriv_ac3_parse_header(&gbc, &hdr) < 0) break; @@ -58,7 +60,7 @@ static int ac3_eac3_probe(AVProbeData *p, enum CodecID expected_codec_id) // 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>500)return AVPROBE_SCORE_MAX/2; + else if(max_frames>200)return AVPROBE_SCORE_MAX/2; else if(max_frames>=4) return AVPROBE_SCORE_MAX/4; else if(max_frames>=1) return 1; else return 0; diff --git a/libavformat/act.c b/libavformat/act.c new file mode 100644 index 0000000000..e47afc1d27 --- /dev/null +++ b/libavformat/act.c @@ -0,0 +1,207 @@ +/* + * ACT file format demuxer + * Copyright (c) 2007-2008 Vladimir Voroshilov + * + * 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 "avformat.h" +#include "riff.h" +#include "internal.h" +#include "libavcodec/get_bits.h" + +#define CHUNK_SIZE 512 +#define RIFF_TAG MKTAG('R','I','F','F') +#define WAVE_TAG MKTAG('W','A','V','E') + +typedef struct{ + int bytes_left_in_chunk; + uint8_t audio_buffer[22];///< temporary buffer for ACT frame + char second_packet; ///< 1 - if temporary buffer contains valid (second) G.729 packet +} ACTContext; + +static int probe(AVProbeData *p) +{ + int i; + + if ((AV_RL32(&p->buf[0]) != RIFF_TAG) || + (AV_RL32(&p->buf[8]) != WAVE_TAG) || + (AV_RL32(&p->buf[16]) != 16)) + return 0; + + //We cant be sure that this is ACT and not regular WAV + if (p->buf_size<512) + return 0; + + for(i=44; i<256; i++) + if(p->buf[i]) + return 0; + + if(p->buf[256]!=0x84) + return 0; + + for(i=264; i<512; i++) + if(p->buf[i]) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int read_header(AVFormatContext *s) +{ + ACTContext* ctx = s->priv_data; + AVIOContext *pb = s->pb; + int size; + AVStream* st; + + int min,sec,msec; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + avio_skip(pb, 16); + size=avio_rl32(pb); + ff_get_wav_header(pb, st->codec, size); + + /* + 8000Hz (Fine-rec) file format has 10 bytes long + packets with 10ms of sound data in them + */ + if (st->codec->sample_rate != 8000) { + av_log(s, AV_LOG_ERROR, "Sample rate %d is not supported.\n", st->codec->sample_rate); + return AVERROR_INVALIDDATA; + } + + st->codec->frame_size=80; + st->codec->channels=1; + avpriv_set_pts_info(st, 64, 1, 100); + + st->codec->codec_id=CODEC_ID_G729; + + avio_seek(pb, 257, SEEK_SET); + msec=avio_rl16(pb); + sec=avio_r8(pb); + min=avio_rl32(pb); + + st->duration = av_rescale(1000*(min*60+sec)+msec, st->codec->sample_rate, 1000 * st->codec->frame_size); + + ctx->bytes_left_in_chunk=CHUNK_SIZE; + + avio_seek(pb, 512, SEEK_SET); + + return 0; +} + + +static int read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + ACTContext *ctx = s->priv_data; + AVIOContext *pb = s->pb; + int ret; + int frame_size=s->streams[0]->codec->sample_rate==8000?10:22; + + + if(s->streams[0]->codec->sample_rate==8000) + ret=av_new_packet(pkt, 10); + else + ret=av_new_packet(pkt, 11); + + if(ret) + return ret; + + if(s->streams[0]->codec->sample_rate==4400 && !ctx->second_packet) + { + ret = avio_read(pb, ctx->audio_buffer, frame_size); + + if(ret<0) + return ret; + if(ret!=frame_size) + return AVERROR(EIO); + + pkt->data[0]=ctx->audio_buffer[11]; + pkt->data[1]=ctx->audio_buffer[0]; + pkt->data[2]=ctx->audio_buffer[12]; + pkt->data[3]=ctx->audio_buffer[1]; + pkt->data[4]=ctx->audio_buffer[13]; + pkt->data[5]=ctx->audio_buffer[2]; + pkt->data[6]=ctx->audio_buffer[14]; + pkt->data[7]=ctx->audio_buffer[3]; + pkt->data[8]=ctx->audio_buffer[15]; + pkt->data[9]=ctx->audio_buffer[4]; + pkt->data[10]=ctx->audio_buffer[16]; + + ctx->second_packet=1; + } + else if(s->streams[0]->codec->sample_rate==4400 && ctx->second_packet) + { + pkt->data[0]=ctx->audio_buffer[5]; + pkt->data[1]=ctx->audio_buffer[17]; + pkt->data[2]=ctx->audio_buffer[6]; + pkt->data[3]=ctx->audio_buffer[18]; + pkt->data[4]=ctx->audio_buffer[7]; + pkt->data[5]=ctx->audio_buffer[19]; + pkt->data[6]=ctx->audio_buffer[8]; + pkt->data[7]=ctx->audio_buffer[20]; + pkt->data[8]=ctx->audio_buffer[9]; + pkt->data[9]=ctx->audio_buffer[21]; + pkt->data[10]=ctx->audio_buffer[10]; + + ctx->second_packet=0; + } + else // 8000 Hz + { + ret = avio_read(pb, ctx->audio_buffer, frame_size); + + if(ret<0) + return ret; + if(ret!=frame_size) + return AVERROR(EIO); + + pkt->data[0]=ctx->audio_buffer[5]; + pkt->data[1]=ctx->audio_buffer[0]; + pkt->data[2]=ctx->audio_buffer[6]; + pkt->data[3]=ctx->audio_buffer[1]; + pkt->data[4]=ctx->audio_buffer[7]; + pkt->data[5]=ctx->audio_buffer[2]; + pkt->data[6]=ctx->audio_buffer[8]; + pkt->data[7]=ctx->audio_buffer[3]; + pkt->data[8]=ctx->audio_buffer[9]; + pkt->data[9]=ctx->audio_buffer[4]; + } + + ctx->bytes_left_in_chunk -= frame_size; + + if(ctx->bytes_left_in_chunk < frame_size) + { + avio_skip(pb, ctx->bytes_left_in_chunk); + ctx->bytes_left_in_chunk=CHUNK_SIZE; + } + + pkt->duration=1; + + return ret; +} + +AVInputFormat ff_act_demuxer = { + .name = "act", + .long_name = "ACT Voice file format", + .priv_data_size = sizeof(ACTContext), + .read_probe = probe, + .read_header = read_header, + .read_packet = read_packet, +}; diff --git a/libavformat/adts.h b/libavformat/adts.h index 78b42c7101..1da57beff9 100644 --- a/libavformat/adts.h +++ b/libavformat/adts.h @@ -3,20 +3,20 @@ * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com> * Mans Rullgard <mans@mansr.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 */ diff --git a/libavformat/adtsenc.c b/libavformat/adtsenc.c index ef3d8e2c21..18a055a1e5 100644 --- a/libavformat/adtsenc.c +++ b/libavformat/adtsenc.c @@ -3,20 +3,20 @@ * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com> * Mans Rullgard <mans@mansr.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 */ diff --git a/libavformat/aea.c b/libavformat/aea.c index b62e56030a..4e255241d1 100644 --- a/libavformat/aea.c +++ b/libavformat/aea.c @@ -3,20 +3,20 @@ * * Copyright (c) 2009 Benjamin Larsson * - * 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/libavformat/aiff.h b/libavformat/aiff.h index 3190a22787..d909bdd83e 100644 --- a/libavformat/aiff.h +++ b/libavformat/aiff.h @@ -2,20 +2,20 @@ * AIFF/AIFF-C muxer/demuxer common header * Copyright (c) 2006 Patrick Guimond * - * 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/libavformat/aiffdec.c b/libavformat/aiffdec.c index 46396cda6f..0f683837a3 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -2,20 +2,20 @@ * AIFF/AIFF-C demuxer * Copyright (c) 2006 Patrick Guimond * - * 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 */ @@ -25,6 +25,7 @@ #include "internal.h" #include "pcm.h" #include "aiff.h" +#include "isom.h" #define AIFF 0 #define AIFF_C_VERSION1 0xA2805140 @@ -53,7 +54,7 @@ static int get_tag(AVIOContext *pb, uint32_t * tag) { int size; - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); *tag = avio_rl32(pb); @@ -69,19 +70,20 @@ static int get_tag(AVIOContext *pb, uint32_t * tag) static void get_meta(AVFormatContext *s, const char *key, int size) { uint8_t *str = av_malloc(size+1); - int res; - if (!str) { - avio_skip(s->pb, size); - return; - } - - res = avio_read(s->pb, str, size); - if (res < 0) - return; + if (str) { + int res = avio_read(s->pb, str, size); + if (res < 0){ + av_free(str); + return; + } + size += (size&1)-res; + str[res] = 0; + av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL); + }else + size+= size&1; - str[res] = 0; - av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL); + avio_skip(s->pb, size); } /* Returns the number of sound data frames or negative on error */ @@ -256,6 +258,11 @@ static int aiff_read_header(AVFormatContext *s) st->codec->extradata_size = size; avio_read(pb, st->codec->extradata, size); break; + case MKTAG('C','H','A','N'): + if (size < 12) + return AVERROR_INVALIDDATA; + ff_mov_read_chan(s, size, st->codec); + break; default: /* Jump */ if (size & 1) /* Always even aligned */ size++; diff --git a/libavformat/aiffenc.c b/libavformat/aiffenc.c index 2916d26fc6..e5c38b1547 100644 --- a/libavformat/aiffenc.c +++ b/libavformat/aiffenc.c @@ -2,20 +2,20 @@ * AIFF/AIFF-C muxer * Copyright (c) 2006 Patrick Guimond * - * 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 */ @@ -24,6 +24,7 @@ #include "internal.h" #include "aiff.h" #include "avio_internal.h" +#include "isom.h" typedef struct { int64_t form; @@ -63,6 +64,12 @@ static int aiff_write_header(AVFormatContext *s) avio_wb32(pb, 0xA2805140); } + if (enc->channels > 2 && enc->channel_layout) { + ffio_wfourcc(pb, "CHAN"); + avio_wb32(pb, 12); + ff_mov_write_chan(pb, enc->channel_layout); + } + /* Common chunk */ ffio_wfourcc(pb, "COMM"); avio_wb32(pb, aifc ? 24 : 18); /* size */ diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 66a8cfec48..134839ffa1 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -2,20 +2,20 @@ * Register all the formats and protocols * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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" @@ -51,6 +51,8 @@ void av_register_all(void) REGISTER_MUXER (A64, a64); REGISTER_DEMUXER (AAC, aac); REGISTER_MUXDEMUX (AC3, ac3); + REGISTER_DEMUXER (ACT, act); + REGISTER_DEMUXER (ADF, adf); REGISTER_MUXER (ADTS, adts); REGISTER_MUXDEMUX (ADX, adx); REGISTER_DEMUXER (AEA, aea); @@ -70,10 +72,12 @@ void av_register_all(void) REGISTER_DEMUXER (AVS, avs); REGISTER_DEMUXER (BETHSOFTVID, bethsoftvid); REGISTER_DEMUXER (BFI, bfi); + REGISTER_DEMUXER (BINTEXT, bintext); REGISTER_DEMUXER (BINK, bink); + REGISTER_MUXDEMUX (BIT, bit); REGISTER_DEMUXER (BMV, bmv); REGISTER_DEMUXER (C93, c93); - REGISTER_DEMUXER (CAF, caf); + REGISTER_MUXDEMUX (CAF, caf); REGISTER_MUXDEMUX (CAVSVIDEO, cavsvideo); REGISTER_DEMUXER (CDG, cdg); REGISTER_MUXER (CRC, crc); @@ -98,13 +102,17 @@ void av_register_all(void) REGISTER_MUXER (FRAMECRC, framecrc); REGISTER_MUXER (FRAMEMD5, framemd5); REGISTER_MUXDEMUX (G722, g722); + REGISTER_MUXDEMUX (G723_1, g723_1); + REGISTER_DEMUXER (G729, g729); REGISTER_MUXER (GIF, gif); REGISTER_DEMUXER (GSM, gsm); REGISTER_MUXDEMUX (GXF, gxf); REGISTER_MUXDEMUX (H261, h261); REGISTER_MUXDEMUX (H263, h263); REGISTER_MUXDEMUX (H264, h264); + REGISTER_DEMUXER (ICO, ico); REGISTER_DEMUXER (IDCIN, idcin); + REGISTER_DEMUXER (IDF, idf); REGISTER_DEMUXER (IFF, iff); REGISTER_MUXDEMUX (IMAGE2, image2); REGISTER_MUXDEMUX (IMAGE2PIPE, image2pipe); @@ -118,11 +126,13 @@ void av_register_all(void) REGISTER_DEMUXER (JV, jv); REGISTER_MUXDEMUX (LATM, latm); REGISTER_DEMUXER (LMLM4, lmlm4); + REGISTER_DEMUXER (LOAS, loas); REGISTER_DEMUXER (LXF, lxf); REGISTER_MUXDEMUX (M4V, m4v); REGISTER_MUXER (MD5, md5); REGISTER_MUXDEMUX (MATROSKA, matroska); REGISTER_MUXER (MATROSKA_AUDIO, matroska_audio); + REGISTER_MUXDEMUX (MICRODVD, microdvd); REGISTER_MUXDEMUX (MJPEG, mjpeg); REGISTER_MUXDEMUX (MLP, mlp); REGISTER_DEMUXER (MM, mm); @@ -192,6 +202,7 @@ void av_register_all(void) REGISTER_MUXDEMUX (RTP, rtp); REGISTER_MUXDEMUX (RTSP, rtsp); REGISTER_MUXDEMUX (SAP, sap); + REGISTER_DEMUXER (SBG, sbg); REGISTER_DEMUXER (SDP, sdp); #if CONFIG_RTPDEC av_register_rtp_dynamic_payload_handlers(); @@ -213,6 +224,7 @@ void av_register_all(void) REGISTER_MUXER (TGP, tgp); REGISTER_DEMUXER (THP, thp); REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq); + REGISTER_MUXER (MKVTIMESTAMP_V2, mkvtimestamp_v2); REGISTER_DEMUXER (TMV, tmv); REGISTER_MUXDEMUX (TRUEHD, truehd); REGISTER_DEMUXER (TTA, tta); @@ -229,19 +241,24 @@ void av_register_all(void) REGISTER_MUXER (WEBM, webm); REGISTER_DEMUXER (WSAUD, wsaud); REGISTER_DEMUXER (WSVQA, wsvqa); - REGISTER_DEMUXER (WTV, wtv); + REGISTER_MUXDEMUX (WTV, wtv); REGISTER_DEMUXER (WV, wv); REGISTER_DEMUXER (XA, xa); + REGISTER_DEMUXER (XBIN, xbin); REGISTER_DEMUXER (XMV, xmv); REGISTER_DEMUXER (XWMA, xwma); REGISTER_DEMUXER (YOP, yop); REGISTER_MUXDEMUX (YUV4MPEGPIPE, yuv4mpegpipe); /* external libraries */ +#if CONFIG_LIBMODPLUG + REGISTER_DEMUXER (LIBMODPLUG, libmodplug); +#endif REGISTER_MUXDEMUX (LIBNUT, libnut); /* protocols */ REGISTER_PROTOCOL (APPLEHTTP, applehttp); + REGISTER_PROTOCOL (CACHE, cache); REGISTER_PROTOCOL (CONCAT, concat); REGISTER_PROTOCOL (CRYPTO, crypto); REGISTER_PROTOCOL (FILE, file); diff --git a/libavformat/amr.c b/libavformat/amr.c index 708eace1f9..84dbd5a78b 100644 --- a/libavformat/amr.c +++ b/libavformat/amr.c @@ -2,20 +2,20 @@ * amr file format * Copyright (c) 2001 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 */ @@ -123,7 +123,7 @@ static int amr_read_packet(AVFormatContext *s, int read, size = 0, toc, mode; int64_t pos = avio_tell(s->pb); - if (s->pb->eof_reached) + if (url_feof(s->pb)) { return AVERROR(EIO); } diff --git a/libavformat/anm.c b/libavformat/anm.c index f236ce6eed..3c8d570c8e 100644 --- a/libavformat/anm.c +++ b/libavformat/anm.c @@ -2,20 +2,20 @@ * Deluxe Paint Animation demuxer * Copyright (c) 2009 Peter Ross * - * 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 */ @@ -134,18 +134,17 @@ static int read_header(AVFormatContext *s) /* color cycling and palette data */ st->codec->extradata_size = 16*8 + 4*256; st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!st->codec->extradata) + return AVERROR(ENOMEM); + ret = avio_read(pb, st->codec->extradata, st->codec->extradata_size); if (ret < 0) - goto fail; + return ret; /* read page table */ ret = avio_seek(pb, anm->page_table_offset, SEEK_SET); if (ret < 0) - goto fail; + return ret; for (i = 0; i < MAX_PAGES; i++) { Page *p = &anm->pt[i]; @@ -156,20 +155,15 @@ static int read_header(AVFormatContext *s) /* find page of first frame */ anm->page = find_record(anm, 0); - if (anm->page < 0) { - ret = anm->page; - goto fail; - } + if (anm->page < 0) + return anm->page; anm->record = -1; return 0; invalid: av_log_ask_for_sample(s, NULL); - ret = AVERROR_INVALIDDATA; - -fail: - return ret; + return AVERROR_INVALIDDATA; } static int read_packet(AVFormatContext *s, @@ -180,7 +174,7 @@ static int read_packet(AVFormatContext *s, Page *p; int tmp, record_size; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); if (anm->page < 0) diff --git a/libavformat/apc.c b/libavformat/apc.c index 30ddae3665..389eba7b0a 100644 --- a/libavformat/apc.c +++ b/libavformat/apc.c @@ -2,20 +2,20 @@ * CRYO APC audio format demuxer * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.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 */ diff --git a/libavformat/ape.c b/libavformat/ape.c index 080e0ba8f6..ffb8f5a384 100644 --- a/libavformat/ape.c +++ b/libavformat/ape.c @@ -3,20 +3,20 @@ * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> * based upon libdemac from Dave Chapman. * - * 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 */ @@ -356,7 +356,7 @@ static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) APEContext *ape = s->priv_data; uint32_t extra_size = 8; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); if (ape->currentframe > ape->totalframes) return AVERROR(EIO); diff --git a/libavformat/apetag.c b/libavformat/apetag.c index 257ed48970..8d53e4cdf7 100644 --- a/libavformat/apetag.c +++ b/libavformat/apetag.c @@ -3,20 +3,20 @@ * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> * based upon libdemac from Dave Chapman. * - * 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/libavformat/apetag.h b/libavformat/apetag.h index 9a39d02a2b..8aaef68c38 100644 --- a/libavformat/apetag.h +++ b/libavformat/apetag.h @@ -3,20 +3,20 @@ * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> * based upon libdemac from Dave Chapman. * - * 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/libavformat/applehttp.c b/libavformat/applehttp.c index 32a51fede1..7e6346a989 100644 --- a/libavformat/applehttp.c +++ b/libavformat/applehttp.c @@ -2,20 +2,20 @@ * Apple HTTP Live Streaming demuxer * Copyright (c) 2010 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 */ @@ -100,6 +100,8 @@ typedef struct AppleHTTPContext { int end_of_segment; int first_packet; int64_t first_timestamp; + int64_t seek_timestamp; + int seek_flags; AVIOInterruptCB *interrupt_callback; } AppleHTTPContext; @@ -226,7 +228,7 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, free_segment_list(var); var->finished = 0; } - while (!in->eof_reached) { + while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; @@ -545,6 +547,7 @@ static int applehttp_read_header(AVFormatContext *s) c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; + c->seek_timestamp = AV_NOPTS_VALUE; return 0; fail: @@ -559,7 +562,7 @@ static int recheck_discard_flags(AVFormatContext *s, int first) /* Check if any new streams are needed */ for (i = 0; i < c->n_variants; i++) - c->variants[i]->cur_needed = 0;; + c->variants[i]->cur_needed = 0; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; @@ -604,14 +607,44 @@ start: /* Make sure we've got one buffered packet from each open variant * stream */ if (var->needed && !var->pkt.data) { - ret = av_read_frame(var->ctx, &var->pkt); - if (ret < 0) { - if (!var->pb.eof_reached) - return ret; - reset_packet(&var->pkt); - } else { - if (c->first_timestamp == AV_NOPTS_VALUE) - c->first_timestamp = var->pkt.dts; + while (1) { + int64_t ts_diff; + ret = av_read_frame(var->ctx, &var->pkt); + if (ret < 0) { + if (!url_feof(&var->pb)) { + return ret; + } else { + if ((var->cur_seq_no - var->start_seq_no) == (var->n_segments)) { + return AVERROR_EOF; + } + } + reset_packet(&var->pkt); + } else { + if (c->first_timestamp == AV_NOPTS_VALUE) + c->first_timestamp = var->pkt.dts; + } + + if (c->seek_timestamp == AV_NOPTS_VALUE) + break; + + if (var->pkt.dts == AV_NOPTS_VALUE) { + c->seek_timestamp = AV_NOPTS_VALUE; + break; + } + + ts_diff = var->pkt.dts - c->seek_timestamp; + if (ts_diff >= 0) { + if (c->seek_flags & AVSEEK_FLAG_ANY) { + c->seek_timestamp = AV_NOPTS_VALUE; + break; + } + + /* Seek to keyframe */ + if (var->pkt.flags & AV_PKT_FLAG_KEY) { + c->seek_timestamp = AV_NOPTS_VALUE; + break; + } + } } } /* Check if this stream has the packet with the lowest dts */ @@ -652,19 +685,27 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index, if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished) return AVERROR(ENOSYS); + c->seek_timestamp = timestamp; + c->seek_flags = flags; timestamp = av_rescale_rnd(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 (s->duration < c->seek_timestamp) { + c->seek_timestamp = AV_NOPTS_VALUE; + return AVERROR(EIO); + } + ret = AVERROR(EIO); 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) { + 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) { ffurl_close(var->input); var->input = NULL; } @@ -682,6 +723,8 @@ static int applehttp_read_seek(AVFormatContext *s, int stream_index, } pos += var->segments[j]->duration; } + if (ret != 0) + c->seek_timestamp = AV_NOPTS_VALUE; } return ret; } diff --git a/libavformat/applehttpproto.c b/libavformat/applehttpproto.c index 46758ba30f..be04131642 100644 --- a/libavformat/applehttpproto.c +++ b/libavformat/applehttpproto.c @@ -2,20 +2,20 @@ * Apple HTTP Live Streaming Protocol Handler * Copyright (c) 2010 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 */ @@ -124,7 +124,7 @@ static int parse_playlist(URLContext *h, const char *url) free_segment_list(s); s->finished = 0; - while (!in->eof_reached) { + while (!url_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; diff --git a/libavformat/asf.c b/libavformat/asf.c index cc2833ddf6..8e360d3596 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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 */ @@ -152,7 +152,6 @@ const AVMetadataConv ff_asf_metadata_conv[] = { { "WM/Publisher" , "publisher" }, { "WM/Tool" , "encoder" }, { "WM/TrackNumber" , "track" }, - { "WM/Track" , "track" }, { "WM/MediaStationCallSign", "service_provider" }, { "WM/MediaStationName", "service_name" }, // { "Year" , "date" }, TODO: conversion year<->date diff --git a/libavformat/asf.h b/libavformat/asf.h index b72445def9..5562865f68 100644 --- a/libavformat/asf.h +++ b/libavformat/asf.h @@ -1,20 +1,20 @@ /* * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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 */ @@ -24,6 +24,7 @@ #include <stdint.h> #include "avformat.h" #include "metadata.h" +#include "riff.h" #define PACKET_SIZE 3200 @@ -48,8 +49,6 @@ typedef struct { uint32_t palette[256]; } ASFStream; -typedef uint8_t ff_asf_guid[16]; - typedef struct { ff_asf_guid guid; ///< generated by client computer uint64_t file_size; /**< in bytes @@ -175,11 +174,6 @@ extern const AVMetadataConv ff_asf_metadata_conv[]; extern AVInputFormat ff_asf_demuxer; -static av_always_inline int ff_guidcmp(const void *g1, const void *g2) -{ - return memcmp(g1, g2, sizeof(ff_asf_guid)); -} - -void ff_get_guid(AVIOContext *s, ff_asf_guid *g); +void ff_put_guid(AVIOContext *s, const ff_asf_guid *g); #endif /* AVFORMAT_ASF_H */ diff --git a/libavformat/asfcrypt.c b/libavformat/asfcrypt.c index aea3d4f345..750758d822 100644 --- a/libavformat/asfcrypt.c +++ b/libavformat/asfcrypt.c @@ -3,20 +3,20 @@ * Copyright (c) 2007 Reimar Doeffinger * This is a rewrite of code contained in freeme/freeme2 * - * 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/libavformat/asfcrypt.h b/libavformat/asfcrypt.h index 53388b426e..8b80d63c5d 100644 --- a/libavformat/asfcrypt.h +++ b/libavformat/asfcrypt.h @@ -2,20 +2,20 @@ * ASF decryption * Copyright (c) 2007 Reimar Doeffinger * - * 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/libavformat/asfdec.c b/libavformat/asfdec.c index c5391a9d62..2c2bd47802 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -2,20 +2,20 @@ * ASF compatible demuxer * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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 */ @@ -133,12 +133,6 @@ static void print_guid(const ff_asf_guid *g) #define print_guid(g) #endif -void ff_get_guid(AVIOContext *s, ff_asf_guid *g) -{ - assert(sizeof(*g) == 16); - avio_read(s, *g, sizeof(*g)); -} - static int asf_probe(AVProbeData *pd) { /* check file header */ @@ -172,6 +166,9 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len) if (type == 0) { // UTF16-LE avio_get_str16le(s->pb, len, value, 2*len + 1); + } else if (type == -1) { // ASCII + avio_read(s->pb, value, len); + value[len]=0; } else if (type > 1 && type <= 5) { // boolean or DWORD or QWORD or WORD uint64_t num = get_value(s->pb, type); snprintf(value, len, "%"PRIu64, num); @@ -236,7 +233,6 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) if (!asf_st) return AVERROR(ENOMEM); st->priv_data = asf_st; - st->start_time = 0; start_time = asf->hdr.preroll; asf_st->stream_language_index = 128; // invalid stream index means no language info @@ -295,7 +291,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) if (is_dvr_ms_audio) { // codec_id and codec_tag are unreliable in dvr_ms // files. Set them later by probing stream. - st->codec->codec_id = CODEC_ID_PROBE; + st->request_probe= 1; st->codec->codec_tag = 0; } if (st->codec->codec_id == CODEC_ID_AAC) { @@ -639,16 +635,28 @@ static int asf_read_header(AVFormatContext *s) continue; } else if (!ff_guidcmp(&g, &ff_asf_marker_header)) { asf_read_marker(s, gsize); - } else if (pb->eof_reached) { + } else if (url_feof(pb)) { return -1; } else { if (!s->keylen) { if (!ff_guidcmp(&g, &ff_asf_content_encryption)) { + unsigned int len; + AVPacket pkt; av_log(s, AV_LOG_WARNING, "DRM protected stream detected, decoding will likely fail!\n"); + len= avio_rl32(pb); + av_log(s, AV_LOG_DEBUG, "Secret data:\n"); + av_get_packet(pb, &pkt, len); av_hex_dump_log(s, AV_LOG_DEBUG, pkt.data, pkt.size); av_free_packet(&pkt); + len= avio_rl32(pb); + get_tag(s, "ASF_Protection_Type", -1, len); + len= avio_rl32(pb); + get_tag(s, "ASF_Key_ID", -1, len); + len= avio_rl32(pb); + get_tag(s, "ASF_License_URL", -1, len); } else if (!ff_guidcmp(&g, &ff_asf_ext_content_encryption)) { av_log(s, AV_LOG_WARNING, "Ext DRM protected stream detected, decoding will likely fail!\n"); + av_dict_set(&s->metadata, "encryption", "ASF Extended Content Encryption", 0); } else if (!ff_guidcmp(&g, &ff_asf_digital_signature)) { - av_log(s, AV_LOG_WARNING, "Digital signature detected, decoding will likely fail!\n"); + av_log(s, AV_LOG_INFO, "Digital signature detected!\n"); } } } @@ -660,7 +668,7 @@ static int asf_read_header(AVFormatContext *s) avio_rl64(pb); avio_r8(pb); avio_r8(pb); - if (pb->eof_reached) + if (url_feof(pb)) return -1; asf->data_offset = avio_tell(pb); asf->packet_size_left = 0; @@ -745,19 +753,19 @@ static int ff_asf_get_packet(AVFormatContext *s, AVIOContext *pb) */ if (pb->error == AVERROR(EAGAIN)) return AVERROR(EAGAIN); - if (!pb->eof_reached) + if (!url_feof(pb)) av_log(s, AV_LOG_ERROR, "ff asf bad header %x at:%"PRId64"\n", c, avio_tell(pb)); } if ((c & 0x8f) == 0x82) { if (d || e) { - if (!pb->eof_reached) + if (!url_feof(pb)) av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n"); return -1; } c= avio_r8(pb); d= avio_r8(pb); rsize+=3; - }else{ + }else if(!url_feof(pb)){ avio_seek(pb, -1, SEEK_CUR); //FIXME } @@ -805,7 +813,7 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb){ ASFContext *asf = s->priv_data; int rsize = 1; int num = avio_r8(pb); - int64_t ts0; + int64_t ts0, ts1 av_unused; asf->packet_segments--; asf->packet_key_frame = num >> 7; @@ -815,6 +823,10 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb){ DO_2BITS(asf->packet_property >> 2, asf->packet_frag_offset, 0); DO_2BITS(asf->packet_property, asf->packet_replic_size, 0); //printf("key:%d stream:%d seq:%d offset:%d replic_size:%d\n", asf->packet_key_frame, asf->stream_index, asf->packet_seq, //asf->packet_frag_offset, asf->packet_replic_size); + if (rsize+asf->packet_replic_size > asf->packet_size_left) { + av_log(s, AV_LOG_ERROR, "packet_replic_size %d is invalid\n", asf->packet_replic_size); + return -1; + } if (asf->packet_replic_size >= 8) { asf->packet_obj_size = avio_rl32(pb); if(asf->packet_obj_size >= (1<<24) || asf->packet_obj_size <= 0){ @@ -828,7 +840,7 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb){ // av_log(s, AV_LOG_DEBUG, "\n"); avio_skip(pb, 10); ts0= avio_rl64(pb); - avio_skip(pb, 8);; + ts1= avio_rl64(pb); avio_skip(pb, 12); avio_rl32(pb); avio_skip(pb, asf->packet_replic_size - 8 - 38 - 4); @@ -866,10 +878,6 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb){ } //printf("Fragsize %d\n", asf->packet_frag_size); } else { - if (rsize > asf->packet_size_left) { - av_log(s, AV_LOG_ERROR, "packet_replic_size is invalid\n"); - return -1; - } asf->packet_frag_size = asf->packet_size_left - rsize; //printf("Using rest %d %d %d\n", asf->packet_frag_size, asf->packet_size_left, rsize); } @@ -899,7 +907,7 @@ static int ff_asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pk ASFStream *asf_st = 0; for (;;) { int ret; - if(pb->eof_reached) + if(url_feof(pb)) return AVERROR_EOF; if (asf->packet_size_left < FRAME_HEADER_SIZE || asf->packet_segments < 1) { @@ -1163,12 +1171,13 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, if (s->packet_size > 0) pos= (pos+s->packet_size-1-s->data_offset)/s->packet_size*s->packet_size+ s->data_offset; *ppos= pos; - avio_seek(s->pb, pos, SEEK_SET); + if (avio_seek(s->pb, pos, SEEK_SET) < 0) + return AV_NOPTS_VALUE; //printf("asf_read_pts\n"); asf_reset_header(s); for(;;){ - if (asf_read_packet(s, pkt) < 0){ + if (av_read_frame(s, pkt) < 0){ av_log(s, AV_LOG_INFO, "asf_read_pts failed\n"); return AV_NOPTS_VALUE; } @@ -1203,17 +1212,21 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) ff_asf_guid g; ASFContext *asf = s->priv_data; int64_t current_pos= avio_tell(s->pb); - int i; - avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET); + if(avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET) < 0) { + asf->index_read= -1; + return; + } + ff_get_guid(s->pb, &g); /* the data object can be followed by other top-level objects, skip them until the simple index object is reached */ while (ff_guidcmp(&g, &index_guid)) { int64_t gsize= avio_rl64(s->pb); - if (gsize < 24 || s->pb->eof_reached) { + if (gsize < 24 || url_feof(s->pb)) { avio_seek(s->pb, current_pos, SEEK_SET); + asf->index_read= -1; return; } avio_skip(s->pb, gsize-24); @@ -1223,6 +1236,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) { int64_t itime, last_pos=-1; int pct, ict; + int i; int64_t av_unused gsize= avio_rl64(s->pb); ff_get_guid(s->pb, &g); itime=avio_rl64(s->pb); @@ -1251,8 +1265,6 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int { ASFContext *asf = s->priv_data; AVStream *st = s->streams[stream_index]; - int64_t pos; - int index; if (s->packet_size <= 0) return -1; @@ -1269,15 +1281,16 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int if (!asf->index_read) asf_build_simple_index(s, stream_index); - if((asf->index_read && st->index_entries)){ - index= av_index_search_timestamp(st, pts, flags); + if((asf->index_read > 0 && st->index_entries)){ + int index= av_index_search_timestamp(st, pts, flags); if(index >= 0) { /* find the position */ - pos = st->index_entries[index].pos; + uint64_t pos = st->index_entries[index].pos; /* do the seek */ av_log(s, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos); - avio_seek(s->pb, pos, SEEK_SET); + if(avio_seek(s->pb, pos, SEEK_SET) < 0) + return -1; asf_reset_header(s); return 0; } diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c index 1cfc857418..a287ac55ad 100644 --- a/libavformat/asfenc.c +++ b/libavformat/asfenc.c @@ -2,20 +2,20 @@ * ASF muxer * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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" @@ -200,8 +200,8 @@ typedef struct { /* packet filling */ unsigned char multi_payloads_present; int packet_size_left; - int packet_timestamp_start; - int packet_timestamp_end; + int64_t packet_timestamp_start; + int64_t packet_timestamp_end; unsigned int packet_nb_payloads; uint8_t packet_buf[PACKET_SIZE]; AVIOContext pb; @@ -216,15 +216,15 @@ typedef struct { } ASFContext; static const AVCodecTag codec_asf_bmp_tags[] = { - { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') }, + { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') }, { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, { CODEC_ID_NONE, 0 }, }; #define PREROLL_TIME 3100 -static void put_guid(AVIOContext *s, const ff_asf_guid *g) +void ff_put_guid(AVIOContext *s, const ff_asf_guid *g) { assert(sizeof(*g) == 16); avio_write(s, *g, sizeof(*g)); @@ -250,7 +250,7 @@ static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g) int64_t pos; pos = avio_tell(pb); - put_guid(pb, g); + ff_put_guid(pb, g); avio_wl64(pb, 24); return pos; } @@ -331,7 +331,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */ } - put_guid(pb, &ff_asf_header); + ff_put_guid(pb, &ff_asf_header); avio_wl64(pb, -1); /* header length, will be patched after */ avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */ avio_w8(pb, 1); /* ??? */ @@ -340,7 +340,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data /* file header */ header_offset = avio_tell(pb); hpos = put_header(pb, &ff_asf_file_header); - put_guid(pb, &ff_asf_my_guid); + ff_put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, file_size); file_time = 0; avio_wl64(pb, unix_to_file_time(file_time)); @@ -356,7 +356,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data /* unknown headers */ hpos = put_header(pb, &ff_asf_head1_guid); - put_guid(pb, &ff_asf_head2_guid); + ff_put_guid(pb, &ff_asf_head2_guid); avio_wl32(pb, 6); avio_wl16(pb, 0); end_header(pb, hpos); @@ -419,11 +419,11 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data hpos = put_header(pb, &ff_asf_stream_header); if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { - put_guid(pb, &ff_asf_audio_stream); - put_guid(pb, &ff_asf_audio_conceal_spread); + ff_put_guid(pb, &ff_asf_audio_stream); + ff_put_guid(pb, &ff_asf_audio_conceal_spread); } else { - put_guid(pb, &ff_asf_video_stream); - put_guid(pb, &ff_asf_video_conceal_none); + ff_put_guid(pb, &ff_asf_video_stream); + ff_put_guid(pb, &ff_asf_video_conceal_none); } avio_wl64(pb, 0); /* ??? */ es_pos = avio_tell(pb); @@ -470,7 +470,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data /* media comments */ hpos = put_header(pb, &ff_asf_codec_comment_header); - put_guid(pb, &ff_asf_codec_comment1_header); + ff_put_guid(pb, &ff_asf_codec_comment1_header); avio_wl32(pb, s->nb_streams); for(n=0;n<s->nb_streams;n++) { AVCodec *p; @@ -541,9 +541,9 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data /* movie chunk, followed by packets of packet_size */ asf->data_offset = cur_pos; - put_guid(pb, &ff_asf_data_header); + ff_put_guid(pb, &ff_asf_data_header); avio_wl64(pb, data_chunk_size); - put_guid(pb, &ff_asf_my_guid); + ff_put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, asf->nb_packets); /* nb packets */ avio_w8(pb, 1); /* ??? */ avio_w8(pb, 1); /* ??? */ @@ -681,7 +681,7 @@ static void flush_packet(AVFormatContext *s) static void put_payload_header( AVFormatContext *s, ASFStream *stream, - int presentation_time, + int64_t presentation_time, int m_obj_size, int m_obj_offset, int payload_len, @@ -708,7 +708,7 @@ static void put_payload_header( avio_w8(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH); avio_wl32(pb, m_obj_size); //Replicated Data - Media Object Size - avio_wl32(pb, presentation_time);//Replicated Data - Presentation Time + avio_wl32(pb, (uint32_t) presentation_time);//Replicated Data - Presentation Time if (asf->multi_payloads_present){ avio_wl16(pb, payload_len); //payload length @@ -719,7 +719,7 @@ static void put_frame( AVFormatContext *s, ASFStream *stream, AVStream *avst, - int timestamp, + int64_t timestamp, const uint8_t *buf, int m_obj_size, int flags @@ -833,9 +833,9 @@ static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, ui AVIOContext *pb = s->pb; int i; - put_guid(pb, &ff_asf_simple_index_header); + ff_put_guid(pb, &ff_asf_simple_index_header); avio_wl64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2)*count); - put_guid(pb, &ff_asf_my_guid); + ff_put_guid(pb, &ff_asf_my_guid); avio_wl64(pb, ASF_INDEXED_INTERVAL); avio_wl32(pb, max); avio_wl32(pb, count); @@ -884,11 +884,7 @@ AVOutputFormat ff_asf_muxer = { .mime_type = "video/x-ms-asf", .extensions = "asf,wmv,wma", .priv_data_size = sizeof(ASFContext), -#if CONFIG_LIBMP3LAME - .audio_codec = CODEC_ID_MP3, -#else - .audio_codec = CODEC_ID_MP2, -#endif + .audio_codec = CODEC_ID_WMAV2, .video_codec = CODEC_ID_MSMPEG4V3, .write_header = asf_write_header, .write_packet = asf_write_packet, @@ -905,11 +901,7 @@ AVOutputFormat ff_asf_stream_muxer = { .mime_type = "video/x-ms-asf", .extensions = "asf,wmv,wma", .priv_data_size = sizeof(ASFContext), -#if CONFIG_LIBMP3LAME - .audio_codec = CODEC_ID_MP3, -#else - .audio_codec = CODEC_ID_MP2, -#endif + .audio_codec = CODEC_ID_WMAV2, .video_codec = CODEC_ID_MSMPEG4V3, .write_header = asf_write_stream_header, .write_packet = asf_write_packet, diff --git a/libavformat/assdec.c b/libavformat/assdec.c index bb1f525616..f76424a36c 100644 --- a/libavformat/assdec.c +++ b/libavformat/assdec.c @@ -2,20 +2,20 @@ * SSA/ASS demuxer * Copyright (c) 2008 Michael Niedermayer * - * 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 */ @@ -93,7 +93,7 @@ static int read_header(AVFormatContext *s) header_remaining= INT_MAX; dst[0] = &st->codec->extradata; dst[1] = &ass->event_buffer; - while(!pb->eof_reached){ + while(!url_feof(pb)){ uint8_t line[MAX_LINESIZE]; len = ff_get_line(pb, line, sizeof(line)); diff --git a/libavformat/assenc.c b/libavformat/assenc.c index c53af16bbd..b367668d2d 100644 --- a/libavformat/assenc.c +++ b/libavformat/assenc.c @@ -2,20 +2,20 @@ * SSA/ASS muxer * Copyright (c) 2008 Michael Niedermayer * - * 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/libavformat/au.c b/libavformat/au.c index e56869b4b9..05ec1eea31 100644 --- a/libavformat/au.c +++ b/libavformat/au.c @@ -2,20 +2,20 @@ * AU muxer and demuxer * Copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -120,7 +120,7 @@ static int au_probe(AVProbeData *p) /* au input */ static int au_read_header(AVFormatContext *s) { - int size; + int size, bps, data_size = 0; unsigned int tag; AVIOContext *pb = s->pb; unsigned int id, channels, rate; @@ -132,7 +132,12 @@ static int au_read_header(AVFormatContext *s) if (tag != MKTAG('.', 's', 'n', 'd')) return -1; size = avio_rb32(pb); /* header size */ - avio_rb32(pb); /* data size */ + data_size = avio_rb32(pb); /* data size in bytes */ + + if (data_size < 0 && data_size != AU_UNKNOWN_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid negative data size '%d' found\n", data_size); + return AVERROR_INVALIDDATA; + } id = avio_rb32(pb); rate = avio_rb32(pb); @@ -140,7 +145,7 @@ static int au_read_header(AVFormatContext *s) codec = ff_codec_get_id(codec_au_tags, id); - if (!av_get_bits_per_sample(codec)) { + if (!(bps = av_get_bits_per_sample(codec))) { av_log_ask_for_sample(s, "could not determine bits per sample\n"); return AVERROR_INVALIDDATA; } @@ -159,6 +164,8 @@ static int au_read_header(AVFormatContext *s) st->codec->codec_id = codec; st->codec->channels = channels; st->codec->sample_rate = rate; + if (data_size != AU_UNKNOWN_SIZE) + st->duration = (((int64_t)data_size)<<3) / (st->codec->channels * bps); avpriv_set_pts_info(st, 64, 1, rate); return 0; } diff --git a/libavformat/audiointerleave.c b/libavformat/audiointerleave.c index e48f826e14..922f4a5880 100644 --- a/libavformat/audiointerleave.c +++ b/libavformat/audiointerleave.c @@ -3,20 +3,20 @@ * * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ @@ -113,10 +113,13 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt } av_fifo_generic_write(aic->fifo, pkt->data, pkt->size, NULL); } else { + int ret; // rewrite pts and dts to be decoded time line position pkt->pts = pkt->dts = aic->dts; aic->dts += pkt->duration; - ff_interleave_add_packet(s, pkt, compare_ts); + ret = ff_interleave_add_packet(s, pkt, compare_ts); + if (ret < 0) + return ret; } pkt = NULL; } @@ -125,8 +128,12 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt AVStream *st = s->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { AVPacket new_pkt; - while (ff_interleave_new_audio_packet(s, &new_pkt, i, flush)) - ff_interleave_add_packet(s, &new_pkt, compare_ts); + int ret; + while (ff_interleave_new_audio_packet(s, &new_pkt, i, flush)) { + ret = ff_interleave_add_packet(s, &new_pkt, compare_ts); + if (ret < 0) + return ret; + } } } diff --git a/libavformat/audiointerleave.h b/libavformat/audiointerleave.h index af29629b8a..b37c8aefbd 100644 --- a/libavformat/audiointerleave.h +++ b/libavformat/audiointerleave.h @@ -3,20 +3,20 @@ * * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ diff --git a/libavformat/avc.c b/libavformat/avc.c index b0c511e7b5..eff1ddb121 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -2,20 +2,20 @@ * AVC helper functions for muxers * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.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 */ diff --git a/libavformat/avc.h b/libavformat/avc.h index 56122125a9..46e5e37a54 100644 --- a/libavformat/avc.h +++ b/libavformat/avc.h @@ -2,20 +2,20 @@ * AVC helper functions for muxers * Copyright (c) 2008 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/avformat.h b/libavformat/avformat.h index a78c1e3b72..55616a8010 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1,20 +1,20 @@ /* * copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -157,7 +157,7 @@ struct AVFormatContext; * * Metadata is exported or set as pairs of key/value strings in the 'metadata' * fields of the AVFormatContext, AVStream, AVChapter and AVProgram structs - * using the @ref lavu_dict "AVDictionary" API. Like all strings in Libav, + * using the @ref lavu_dict "AVDictionary" API. Like all strings in FFmpeg, * metadata is assumed to be UTF-8 encoded Unicode. Note that metadata * exported by demuxers isn't checked to be valid UTF-8 in most cases. * @@ -294,6 +294,9 @@ typedef struct AVProbeData { #define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fallback to 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. */ +#define AVFMT_TS_NONSTRICT 0x8000000 /**< Format does not require strictly + increasing timestamps, but they must + still be monotonic */ /** * @addtogroup lavf_encoding @@ -332,9 +335,6 @@ typedef struct AVOutputFormat { * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH */ int flags; - /** - * Currently only used to set pixel format if not YUV420P. - */ int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, AVPacket *in, int flush); @@ -356,6 +356,9 @@ typedef struct AVOutputFormat { */ int (*query_codec)(enum CodecID id, int std_compliance); + void (*get_output_timestamp)(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + /* private fields */ struct AVOutputFormat *next; } AVOutputFormat; @@ -496,7 +499,12 @@ enum AVStreamParseType { typedef struct AVIndexEntry { int64_t pos; - int64_t timestamp; + int64_t timestamp; /**< + * Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are available + * when seeking to this entry. That means preferable PTS on keyframe based formats. + * But demuxers can choose to store a different timestamp, if it is more convenient for the implementation or nothing better + * is known + */ #define AVINDEX_KEYFRAME 0x0001 int flags:2; int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs. 32 bytes due to possible 8-byte alignment). @@ -558,10 +566,12 @@ typedef struct AVStream { enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed. /** - * Decoding: pts of the first frame of the stream, in stream time base. + * Decoding: pts of the first frame of the stream in presentation order, in stream time base. * Only set this if you are absolutely 100% sure that the value you set * it to really is the pts of the first frame. * This may be undefined (AV_NOPTS_VALUE). + * @note The ASF header does NOT contain a correct start_time the ASF + * demuxer must NOT set this. */ int64_t start_time; @@ -604,6 +614,16 @@ 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; + + /** * Stream information used internally by av_find_stream_info() */ #define MAX_STD_TIMEBASES (60*12+5) @@ -611,7 +631,7 @@ typedef struct AVStream { int64_t last_dts; int64_t duration_gcd; int duration_count; - double duration_error[MAX_STD_TIMEBASES]; + double duration_error[2][2][MAX_STD_TIMEBASES]; int64_t codec_info_duration; int nb_decoded_frames; } *info; @@ -656,6 +676,12 @@ typedef struct AVStream { unsigned int index_entries_allocated_size; int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ + + /** + * flag to indicate that probing is requested + * NOT PART OF PUBLIC API + */ + int request_probe; } AVStream; #define AV_PROGRAM_RUNNING 1 @@ -673,6 +699,10 @@ typedef struct AVProgram { unsigned int *stream_index; unsigned int nb_stream_indexes; AVDictionary *metadata; + + int program_num; + int pmt_pid; + int pcr_pid; } AVProgram; #define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present @@ -762,7 +792,7 @@ typedef struct AVFormatContext { /** * Decoding: total stream bitrate in bit/s, 0 if not * available. Never set it directly if the file_size and the - * duration are known as Libav can compute it automatically. + * duration are known as FFmpeg can compute it automatically. */ int bit_rate; @@ -778,6 +808,10 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_NOPARSE 0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled #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_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) +#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Dont merge side data but keep it seperate. /** * decoding: size of data to probe; encoding: unused. @@ -876,6 +910,36 @@ typedef struct AVFormatContext { */ AVIOInterruptCB interrupt_callback; + /** + * Transport stream id. + * This will be moved into demuxer private options. Thus no API/ABI compatibility + */ + int ts_id; + + /** + * Audio preload in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int audio_preload; + + /** + * Max chunk time in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int max_chunk_duration; + + /** + * Max chunk size in bytes + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int max_chunk_size; + /***************************************************************** * 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 @@ -1030,6 +1094,41 @@ 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() + */ +attribute_deprecated +AVFormatContext *avformat_alloc_output_context(const char *format, + AVOutputFormat *oformat, + const char *filename); +#endif + +/** + * Allocate an AVFormatContext for an output format. + * avformat_free_context() can be used to free the context and + * everything allocated by the framework within it. + * + * @param *ctx is set to the created format context, or to NULL in + * case of failure + * @param oformat format to use for allocating the context, if NULL + * format_name and filename are used instead + * @param format_name the name of output format to use for allocating the + * context, if NULL filename is used instead + * @param filename the name of the filename to use for allocating the + * context, may be NULL + * @return >= 0 in case of success, a negative AVERROR code in case of + * failure + */ +int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, + const char *format_name, const char *filename); + /** * @addtogroup lavf_decoding * @{ @@ -1062,6 +1161,15 @@ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max); /** + * Guess the file format. + * + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_ret The score of the best detection. + */ +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret); + +/** * Probe a bytestream to determine the input format. Each time a probe returns * with a score that is too low, the probe buffer size is increased and another * attempt is made. When the maximum probe size is reached, the input format @@ -1101,6 +1209,29 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, */ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); +attribute_deprecated +int av_demuxer_open(AVFormatContext *ic); + +#if FF_API_FORMAT_PARAMETERS +/** + * Read packets of a media file to get stream information. This + * is useful for file formats with no headers such as MPEG. This + * function also computes the real framerate in case of MPEG-2 repeat + * frame mode. + * The logical file position is not changed by this function; + * examined packets may be buffered for later processing. + * + * @param ic media file handle + * @return >=0 if OK, AVERROR_xxx on error + * @todo Let the user decide somehow what information is needed so that + * we do not waste time getting stuff the user does not need. + * + * @deprecated use avformat_find_stream_info. + */ +attribute_deprecated +int av_find_stream_info(AVFormatContext *ic); +#endif + /** * Read packets of a media file to get stream information. This * is useful for file formats with no headers such as MPEG. This @@ -1125,6 +1256,18 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); /** + * Find the programs which belong to a given stream. + * + * @param ic media file handle + * @param last the last found program, the search will start after this + * program, or from the beginning if it is NULL + * @param s stream index + * @return the next program which belongs to s, NULL if no program is found or + * the last program is not among the programs of ic. + */ +AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s); + +/** * Find the "best" stream in the file. * The best stream is determined according to various heuristics as the most * likely to be what the user expects. @@ -1268,6 +1411,30 @@ void avformat_close_input(AVFormatContext **s); * @} */ +#if FF_API_NEW_STREAM +/** + * Add a new stream to a media file. + * + * Can only be called in the read_header() function. If the flag + * AVFMTCTX_NOHEADER is in the format context, then new streams + * can be added in read_packet too. + * + * @param s media file handle + * @param id file-format-dependent stream ID + */ +attribute_deprecated +AVStream *av_new_stream(AVFormatContext *s, int id); +#endif + +#if FF_API_SET_PTS_INFO +/** + * @deprecated this function is not supposed to be called outside of lavf + */ +attribute_deprecated +void av_set_pts_info(AVStream *s, int pts_wrap_bits, + unsigned int pts_num, unsigned int pts_den); +#endif + #define AVSEEK_FLAG_BACKWARD 1 ///< seek backward #define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes #define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes @@ -1391,6 +1558,25 @@ enum CodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, enum AVMediaType type); /** + * Get timing information for the data currently output. + * The exact meaning of "currently output" depends on the format. + * It is mostly relevant for devices that have an internal buffer and/or + * work in real time. + * @param s media file handle + * @param stream stream in the media file + * @param dts[out] DTS of the last packet output for the stream, in stream + * time_base units + * @param wall[out] absolute time when that packet whas output, + * in microsecond + * @return 0 if OK, AVERROR(ENOSYS) if the format does not support it + * Note: some formats or devices may not allow to measure dts and wall + * atomically. + */ +int av_get_output_timestamp(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + + +/** * @} */ diff --git a/libavformat/avi.h b/libavformat/avi.h index e05db9c63f..34da76f715 100644 --- a/libavformat/avi.h +++ b/libavformat/avi.h @@ -1,20 +1,20 @@ /* * copyright (c) 2001 Fabrice Bellard * - * 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/libavformat/avidec.c b/libavformat/avidec.c index 26ccaadd12..93b15bddf7 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -2,26 +2,27 @@ * AVI demuxer * Copyright (c) 2001 Fabrice Bellard * - * 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/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/bswap.h" +#include "libavutil/opt.h" #include "libavutil/dict.h" #include "libavutil/avstring.h" #include "avformat.h" @@ -54,9 +55,12 @@ typedef struct AVIStream { AVFormatContext *sub_ctx; AVPacket sub_pkt; uint8_t *sub_buffer; + + int64_t seek_pos; } AVIStream; typedef struct { + const AVClass *class; int64_t riff_end; int64_t movi_end; int64_t fsize; @@ -68,9 +72,25 @@ typedef struct { int stream_index; DVDemuxContext* dv_demux; int odml_depth; + int use_odml; #define MAX_ODML_DEPTH 1000 + int64_t dts_max; } AVIContext; + +static const AVOption options[] = { + { "use_odml", "use odml index", offsetof(AVIContext, use_odml), AV_OPT_TYPE_INT, {.dbl = 1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM}, + { NULL }, +}; + +static const AVClass demuxer_class = { + "AVI demuxer", + av_default_item_name, + options, + LIBAVUTIL_VERSION_INT, +}; + + static const char avi_headers[][8] = { { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' }, { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' }, @@ -143,7 +163,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ AVIStream *ast; int i; int64_t last_pos= -1; - int64_t filesize= avio_size(s->pb); + 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); @@ -178,9 +198,10 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ int key= len >= 0; len &= 0x7FFFFFFF; - av_dlog(s, "pos:%"PRId64", len:%X\n", pos, len); - - if(pb->eof_reached) +#ifdef DEBUG_SEEK + av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len); +#endif + if(url_feof(pb)) return -1; if(last_pos == pos || pos == base - 8) @@ -197,7 +218,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ avio_rl32(pb); /* size */ duration = avio_rl32(pb); - if(pb->eof_reached) + if(url_feof(pb)) return -1; pos = avio_tell(pb); @@ -207,16 +228,21 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ return -1; } - avio_seek(pb, offset+8, SEEK_SET); + 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; - avio_seek(pb, pos, SEEK_SET); + if(avio_seek(pb, pos, SEEK_SET) < 0) { + av_log(s, AV_LOG_ERROR, "Failed to restore position after reading index"); + return -1; + } + } } - avi->index_loaded=1; + avi->index_loaded=2; return 0; } @@ -345,8 +371,10 @@ static int avi_read_header(AVFormatContext *s) if (get_riff(s, pb) < 0) return -1; + av_log(avi, AV_LOG_DEBUG, "use odml:%d\n", avi->use_odml); + avi->fsize = avio_size(pb); - if(avi->fsize<=0) + if(avi->fsize<=0 || avi->fsize < avi->riff_end) avi->fsize= avi->riff_end == 8 ? INT64_MAX : avi->riff_end; /* first list tag */ @@ -354,7 +382,7 @@ static int avi_read_header(AVFormatContext *s) codec_type = -1; frame_period = 0; for(;;) { - if (pb->eof_reached) + if (url_feof(pb)) goto fail; tag = avio_rl32(pb); size = avio_rl32(pb); @@ -372,7 +400,7 @@ 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 = avio_size(pb); + else avi->movi_end = avi->fsize; av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end); goto end_of_header; } @@ -400,7 +428,7 @@ static int avi_read_header(AVFormatContext *s) /* AVI header */ /* using frame_period is bad idea */ frame_period = avio_rl32(pb); - avio_skip(pb, 4); + avio_rl32(pb); /* max. bytes per second */ avio_rl32(pb); avi->non_interleaved |= avio_rl32(pb) & AVIF_MUSTUSEINDEX; @@ -511,6 +539,10 @@ static int avi_read_header(AVFormatContext *s) st->start_time = 0; avio_rl32(pb); /* buffer size */ avio_rl32(pb); /* quality */ + if (ast->cum_len*ast->scale/ast->rate > 3600) { + av_log(s, AV_LOG_ERROR, "crazy start time, iam scared, giving up\n"); + return AVERROR_INVALIDDATA; + } ast->sample_size = avio_rl32(pb); /* sample ssize */ ast->cum_len *= FFMAX(1, ast->sample_size); // av_log(s, AV_LOG_DEBUG, "%d %d %d %d\n", ast->rate, ast->scale, ast->start, ast->sample_size); @@ -531,8 +563,7 @@ static int avi_read_header(AVFormatContext *s) codec_type = AVMEDIA_TYPE_DATA; break; default: - av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1); - goto fail; + av_log(s, AV_LOG_INFO, "unknown stream type %X\n", tag1); } if(ast->sample_size == 0) st->duration = st->nb_frames; @@ -541,6 +572,8 @@ static int avi_read_header(AVFormatContext *s) break; case MKTAG('s', 't', 'r', 'f'): /* stream header */ + if (!size) + break; if (stream_index >= (unsigned)s->nb_streams || avi->dv_demux) { avio_skip(pb, size); } else { @@ -567,7 +600,7 @@ static int avi_read_header(AVFormatContext *s) break; } - if(size > 10*4 && size<(1<<30)){ + if(size > 10*4 && size<(1<<30) && size < avi->fsize){ 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) { @@ -582,19 +615,15 @@ static int avi_read_header(AVFormatContext *s) /* Extract palette from extradata if bpp <= 8. */ /* This code assumes that extradata contains only palette. */ - /* This is true for all paletted codecs implemented in Libav. */ + /* 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; -#if HAVE_BIGENDIAN for (i = 0; i < pal_size/4; i++) - ast->pal[i] = av_bswap32(((uint32_t*)pal_src)[i]); -#else - memcpy(ast->pal, pal_src, pal_size); -#endif + ast->pal[i] = 0xFF<<24 | AV_RL32(pal_src+4*i); ast->has_pal = 1; } @@ -612,7 +641,7 @@ static int avi_read_header(AVFormatContext *s) 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(st->codec->extradata, st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + 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); } @@ -644,6 +673,7 @@ static int avi_read_header(AVFormatContext *s) if (st->codec->stream_codec_tag == AV_RL32("Axan")){ st->codec->codec_id = CODEC_ID_XAN_DPCM; st->codec->codec_tag = 0; + ast->dshow_block_align = 0; } if (amv_file_format){ st->codec->codec_id = CODEC_ID_ADPCM_IMA_AMV; @@ -652,7 +682,7 @@ static int avi_read_header(AVFormatContext *s) break; case AVMEDIA_TYPE_SUBTITLE: st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - st->codec->codec_id = CODEC_ID_PROBE; + st->request_probe= 1; break; default: st->codec->codec_type = AVMEDIA_TYPE_DATA; @@ -663,11 +693,33 @@ static int avi_read_header(AVFormatContext *s) } } break; + case MKTAG('s', 't', 'r', 'd'): + if (stream_index >= (unsigned)s->nb_streams || s->streams[stream_index]->codec->extradata_size) { + avio_skip(pb, size); + } else { + uint64_t cur_pos = avio_tell(pb); + if (cur_pos < list_end) + 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_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) { + 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 + avio_r8(pb); + } + break; case MKTAG('i', 'n', 'd', 'x'): i= avio_tell(pb); - if(pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && - read_braindead_odml_indx(s, 0) < 0 && - (s->error_recognition & AV_EF_EXPLODE)) + 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); break; @@ -708,7 +760,7 @@ static int avi_read_header(AVFormatContext *s) if (s->error_recognition & AV_EF_EXPLODE) goto fail; avi->movi_list = avio_tell(pb) - 4; - avi->movi_end = avio_size(pb); + avi->movi_end = avi->fsize; goto end_of_header; } /* skip tag */ @@ -726,13 +778,17 @@ static int avi_read_header(AVFormatContext *s) if(!avi->index_loaded && pb->seekable) avi_load_index(s); - avi->index_loaded = 1; - avi->non_interleaved |= guess_ni_flag(s); + 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++){ AVStream *st = s->streams[i]; 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; @@ -850,7 +906,7 @@ static int avi_sync(AVFormatContext *s, int exit_early) start_sync: memset(d, -1, sizeof(d)); - for(i=sync=avio_tell(pb); !pb->eof_reached; i++) { + for(i=sync=avio_tell(pb); !url_feof(pb); i++) { int j; for(j=0; j<7; j++) @@ -934,7 +990,7 @@ start_sync: avio_rl16(pb); //flags for (; k <= last; k++) - ast->pal[k] = avio_rb32(pb)>>8;// b + (g << 8) + (r << 16); + ast->pal[k] = 0xFF<<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) || @@ -967,6 +1023,8 @@ start_sync: } } + if(pb->error) + return pb->error; return AVERROR_EOF; } @@ -1013,10 +1071,10 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) } } if(!best_st) - return -1; + return AVERROR_EOF; best_ast = best_st->priv_data; - best_ts = av_rescale_q(best_ts, (AVRational){FFMAX(1, best_ast->sample_size), AV_TIME_BASE}, best_st->time_base); + 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{ @@ -1029,7 +1087,8 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) if(i>=0){ int64_t pos= best_st->index_entries[i].pos; pos += best_ast->packet_size - best_ast->remaining; - avio_seek(s->pb, pos + 8, SEEK_SET); + if(avio_seek(s->pb, pos + 8, SEEK_SET) < 0) + return AVERROR_EOF; // av_log(s, AV_LOG_DEBUG, "pos=%"PRId64"\n", pos); assert(best_ast->remaining <= best_ast->packet_size); @@ -1039,6 +1098,8 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) best_ast->packet_size= best_ast->remaining= best_st->index_entries[i].size; } + else + return AVERROR_EOF; } resync: @@ -1079,7 +1140,7 @@ resync: if (CONFIG_DV_DEMUXER && avi->dv_demux) { dstr = pkt->destruct; size = avpriv_dv_produce_packet(avi->dv_demux, pkt, - pkt->data, pkt->size); + pkt->data, pkt->size, pkt->pos); pkt->destruct = dstr; pkt->flags |= AV_PKT_FLAG_KEY; if (size < 0) @@ -1108,6 +1169,23 @@ resync: e= &st->index_entries[index]; 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 == CODEC_ID_MPEG4){ + if(state == 0x1B6){ + key= !(pkt->data[i]&0xC0); + break; + } + }else + break; + state= (state<<8) + pkt->data[i]; + } + if(!key) + e->flags &= ~AVINDEX_KEYFRAME; + } if (e->flags & AVINDEX_KEYFRAME) pkt->flags |= AV_PKT_FLAG_KEY; } @@ -1122,6 +1200,22 @@ resync: ast->packet_size= 0; } + 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){ + int64_t dts= av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q); + + 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) + avi->dts_max = dts; + } + return size; } @@ -1157,6 +1251,9 @@ static int avi_read_idx1(AVFormatContext *s, int size) /* Read the entries and sort them in each stream component. */ for(i = 0; i < nb_index_entries; i++) { + if(url_feof(pb)) + return -1; + tag = avio_rl32(pb); flags = avio_rl32(pb); pos = avio_rl32(pb); @@ -1179,8 +1276,6 @@ static int avi_read_idx1(AVFormatContext *s, int size) av_dlog(s, "%d cum_len=%"PRId64"\n", len, ast->cum_len); - if(pb->eof_reached) - return -1; if(last_pos == pos) avi->non_interleaved= 1; @@ -1235,7 +1330,7 @@ static int avi_load_index(AVFormatContext *s) goto the_end; // maybe truncated file av_dlog(s, "movi_end=0x%"PRIx64"\n", avi->movi_end); for(;;) { - if (pb->eof_reached) + if (url_feof(pb)) break; tag = avio_rl32(pb); size = avio_rl32(pb); @@ -1248,6 +1343,7 @@ static int avi_load_index(AVFormatContext *s) if (tag == MKTAG('i', 'd', 'x', '1') && avi_read_idx1(s, size) >= 0) { + avi->index_loaded=2; ret = 0; break; } @@ -1276,13 +1372,13 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp AVIContext *avi = s->priv_data; AVStream *st; int i, index; - int64_t pos; + int64_t pos, pos_min; AVIStream *ast; if (!avi->index_loaded) { /* we only load the index on demand */ avi_load_index(s); - avi->index_loaded = 1; + avi->index_loaded |= 1; } assert(stream_index>= 0); @@ -1304,15 +1400,18 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp /* the av_index_search_timestamp call above. */ assert(stream_index == 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. */ dv_offset_reset(avi->dv_demux, timestamp); - avio_seek(s->pb, pos, SEEK_SET); avi->stream_index= -1; return 0; } + pos_min= pos; for(i = 0; i < s->nb_streams; i++) { AVStream *st2 = s->streams[i]; AVIStream *ast2 = st2->priv_data; @@ -1333,25 +1432,35 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp 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); + 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++) { + AVStream *st2 = s->streams[i]; + AVIStream *ast2 = st2->priv_data; - if(!avi->non_interleaved){ - while(index>0 && st2->index_entries[index].pos > pos) - index--; - while(index+1 < st2->nb_index_entries && st2->index_entries[index].pos < pos) - index++; - } + if (ast2->sub_ctx || st2->nb_index_entries <= 0) + continue; -// av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %"PRId64"\n", timestamp, index, st2->index_entries[index].timestamp); - /* extract the current frame number */ + 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; + while(!avi->non_interleaved && index>0 && st2->index_entries[index-1].pos >= pos_min) + index--; ast2->frame_offset = st2->index_entries[index].timestamp; } /* do the seek */ - avio_seek(s->pb, pos, SEEK_SET); + if (avio_seek(s->pb, pos_min, SEEK_SET) < 0) + return -1; avi->stream_index= -1; + avi->dts_max= INT_MIN; return 0; } @@ -1400,4 +1509,5 @@ AVInputFormat ff_avi_demuxer = { .read_packet = avi_read_packet, .read_close = avi_read_close, .read_seek = avi_read_seek, + .priv_class = &demuxer_class, }; diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 2a23c213b6..d27c2f58ed 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -2,20 +2,20 @@ * AVI muxer * Copyright (c) 2000 Fabrice Bellard * - * 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" @@ -520,16 +520,21 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) AVCodecContext *enc= s->streams[stream_index]->codec; int size= pkt->size; -// av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avi->packet_count[stream_index], stream_index); +// av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %d\n", pkt->dts, avist->packet_count, stream_index); while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count){ AVPacket empty_packet; + if(pkt->dts - avist->packet_count > 60000){ + av_log(s, AV_LOG_ERROR, "Too large number of skiped frames %"PRId64"\n", pkt->dts - avist->packet_count); + return AVERROR(EINVAL); + } + av_init_packet(&empty_packet); empty_packet.size= 0; empty_packet.data= NULL; empty_packet.stream_index= stream_index; avi_write_packet(s, &empty_packet); -// av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avi->packet_count[stream_index]); +// av_log(s, AV_LOG_DEBUG, "dup %"PRId64" %d\n", pkt->dts, avist->packet_count); } avist->packet_count++; @@ -559,7 +564,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; if (idx->ents_allocated <= idx->entry) { - idx->cluster = av_realloc(idx->cluster, (cl+1)*sizeof(void*)); + idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1); if (!idx->cluster) return -1; idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry)); diff --git a/libavformat/avio.c b/libavformat/avio.c index 067f2958e0..0f6ce31097 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -2,20 +2,20 @@ * unbuffered I/O * Copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -135,8 +135,32 @@ static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up, if (up->priv_data_size) { uc->priv_data = av_mallocz(up->priv_data_size); 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; av_opt_set_defaults(uc->priv_data); + if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){ + int ret= 0; + char *p= start; + char sep= *++p; + char *key, *val; + p++; + while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){ + *val= *key= 0; + ret= av_opt_set(uc->priv_data, p, key+1, 0); + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p); + *val= *key= sep; + p= val+1; + } + if(ret<0 || p!=key){ + av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start); + av_freep(&uc->priv_data); + av_freep(&uc); + goto fail; + } + memmove(start, key+1, strlen(key)); + } } } if (int_cb) @@ -181,11 +205,18 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, char proto_str[128], proto_nested[128], *ptr; size_t proto_len = strspn(filename, URL_SCHEME_CHARS); - if (filename[proto_len] != ':' || is_dos_path(filename)) + if (!first_protocol) { + av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. " + "Missing call to av_register_all()?\n"); + } + + if (filename[proto_len] != ':' && filename[proto_len] != ',' || is_dos_path(filename)) strcpy(proto_str, "file"); else av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str))); + if ((ptr = strchr(proto_str, ','))) + *ptr = '\0'; av_strlcpy(proto_nested, proto_str, sizeof(proto_nested)); if ((ptr = strchr(proto_nested, '+'))) *ptr = '\0'; @@ -243,7 +274,7 @@ static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int if (ret) fast_retries = FFMAX(fast_retries, 2); len += ret; - if (ff_check_interrupt(&h->interrupt_callback)) + if (len < size && ff_check_interrupt(&h->interrupt_callback)) return AVERROR_EXIT; } return len; @@ -271,7 +302,7 @@ int ffurl_write(URLContext *h, const unsigned char *buf, int size) if (h->max_packet_size && size > h->max_packet_size) return AVERROR(EIO); - return retry_transfer_wrapper(h, buf, size, size, h->prot->url_write); + return retry_transfer_wrapper(h, buf, size, size, (void*)h->prot->url_write); } int64_t ffurl_seek(URLContext *h, int64_t pos, int whence) diff --git a/libavformat/avio.h b/libavformat/avio.h index 0ab92c32e5..c29b267968 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -1,20 +1,20 @@ /* * copyright (c) 2001 Fabrice Bellard * - * 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 */ #ifndef AVFORMAT_AVIO_H @@ -115,6 +115,12 @@ typedef struct { * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable. */ int seekable; + + /** + * max filesize, used to limit allocations + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t maxsize; } AVIOContext; /* unbuffered I/O */ @@ -207,10 +213,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence); * Skip given number of bytes forward * @return new position or AVERROR. */ -static av_always_inline int64_t avio_skip(AVIOContext *s, int64_t offset) -{ - return avio_seek(s, offset, SEEK_CUR); -} +int64_t avio_skip(AVIOContext *s, int64_t offset); /** * ftell() equivalent for AVIOContext. @@ -227,6 +230,12 @@ static av_always_inline int64_t avio_tell(AVIOContext *s) */ int64_t avio_size(AVIOContext *s); +/** + * feof() equivalent for AVIOContext. + * @return non zero if and only if end of file + */ +int url_feof(AVIOContext *s); + /** @warning currently size is limited */ int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); @@ -374,6 +383,7 @@ int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer); /** * Iterate through names of available protocols. + * @note it is recommanded to use av_protocol_next() instead of this * * @param opaque A private pointer representing current protocol. * It must be a pointer to NULL on first iteration and will @@ -399,13 +409,13 @@ int avio_pause(AVIOContext *h, int pause); * If stream_index is (-1) the timestamp should be in AV_TIME_BASE * units from the beginning of the presentation. * If a stream_index >= 0 is used and the protocol does not support - * seeking based on component streams, the call will fail with ENOTSUP. + * seeking based on component streams, the call will fail. * @param timestamp timestamp in AVStream.time_base units * or if there is no stream specified then in AV_TIME_BASE units. * @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE * and AVSEEK_FLAG_ANY. The protocol may silently ignore * AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will - * fail with ENOTSUP if used and not supported. + * fail if used and not supported. * @return >= 0 on success * @see AVInputFormat::read_seek */ diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h index f2ccc36623..df614b22d9 100644 --- a/libavformat/avio_internal.h +++ b/libavformat/avio_internal.h @@ -1,19 +1,19 @@ /* * - * 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,6 +71,8 @@ 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); +int ffio_limit(AVIOContext *s, int size); + void ffio_init_checksum(AVIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum); diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 01a36475b2..d1520ed432 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -2,20 +2,20 @@ * buffered I/O * Copyright (c) 2000,2001 Fabrice Bellard * - * 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 */ @@ -234,6 +234,11 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence) return offset; } +int64_t avio_skip(AVIOContext *s, int64_t offset) +{ + return avio_seek(s, offset, SEEK_CUR); +} + int64_t avio_size(AVIOContext *s) { int64_t size; @@ -253,6 +258,17 @@ int64_t avio_size(AVIOContext *s) return size; } +int url_feof(AVIOContext *s) +{ + if(!s) + return 0; + if(s->eof_reached){ + s->eof_reached=0; + fill_buffer(s); + } + return s->eof_reached; +} + void avio_wl32(AVIOContext *s, unsigned int val) { avio_w8(s, val); @@ -374,7 +390,7 @@ static void fill_buffer(AVIOContext *s) } /* make buffer smaller in case it ended up large after probing */ - if (s->buffer_size > max_buffer_size) { + if (s->read_packet && s->buffer_size > max_buffer_size) { ffio_set_buf_size(s, max_buffer_size); s->checksum_ptr = dst = s->buffer; @@ -473,8 +489,8 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size) } } if (size1 == size) { - if (s->error) return s->error; - if (s->eof_reached) return AVERROR_EOF; + if (s->error) return s->error; + if (url_feof(s)) return AVERROR_EOF; } return size1 - size; } @@ -496,8 +512,8 @@ int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size) memcpy(buf, s->buf_ptr, len); s->buf_ptr += len; if (!len) { - if (s->error) return s->error; - if (s->eof_reached) return AVERROR_EOF; + if (s->error) return s->error; + if (url_feof(s)) return AVERROR_EOF; } return len; } @@ -713,7 +729,7 @@ int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char *buf, int buf_size alloc_size = FFMAX(s->buffer_size, new_size); if (alloc_size > buf_size) - if (!(buf = av_realloc(buf, alloc_size))) + if (!(buf = av_realloc_f(buf, 1, alloc_size))) return AVERROR(ENOMEM); if (new_size > buf_size) { @@ -830,7 +846,7 @@ static int dyn_buf_write(void *opaque, uint8_t *buf, int buf_size) } if (new_allocated_size > d->allocated_size) { - d->buffer = av_realloc(d->buffer, new_allocated_size); + d->buffer = av_realloc_f(d->buffer, 1, new_allocated_size); if(d->buffer == NULL) return AVERROR(ENOMEM); d->allocated_size = new_allocated_size; diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c index 3b695a9a0a..13b5f4309c 100644 --- a/libavformat/avisynth.c +++ b/libavformat/avisynth.c @@ -2,20 +2,20 @@ * AVISynth support * Copyright (c) 2006 DivX, Inc. * - * 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 */ @@ -125,6 +125,14 @@ static int avisynth_read_header(AVFormatContext *s) st->codec->bit_rate = (uint64_t)stream->info.dwSampleSize * (uint64_t)stream->info.dwRate * 8 / (uint64_t)stream->info.dwScale; st->codec->codec_tag = imgfmt.bmiHeader.biCompression; st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, imgfmt.bmiHeader.biCompression); + if (st->codec->codec_id == CODEC_ID_RAWVIDEO && imgfmt.bmiHeader.biCompression== BI_RGB) { + st->codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE); + if (st->codec->extradata) { + st->codec->extradata_size = 9; + memcpy(st->codec->extradata, "BottomUp", 9); + } + } + st->duration = stream->info.dwLength; } @@ -168,7 +176,6 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) res = AVIStreamRead(stream->handle, stream->read, stream->chunck_samples, pkt->data, stream->chunck_size, &read_size, NULL); - pkt->pts = stream->read; pkt->size = read_size; stream->read += stream->chunck_samples; diff --git a/libavformat/avlanguage.c b/libavformat/avlanguage.c index e606ef22f9..39f2560d94 100644 --- a/libavformat/avlanguage.c +++ b/libavformat/avlanguage.c @@ -1,20 +1,20 @@ /* * Cyril Comparon, Larbi Joubala, Resonate-MP4 2009 * - * 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/libavformat/avlanguage.h b/libavformat/avlanguage.h index 2ec3e2d372..7fb8968810 100644 --- a/libavformat/avlanguage.h +++ b/libavformat/avlanguage.h @@ -1,20 +1,20 @@ /* * Cyril Comparon, Larbi Joubala, Resonate-MP4 2009 * - * 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/libavformat/avs.c b/libavformat/avs.c index 32e7546d60..ed98ad7313 100644 --- a/libavformat/avs.c +++ b/libavformat/avs.c @@ -2,20 +2,20 @@ * AVS demuxer. * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/bethsoftvid.c b/libavformat/bethsoftvid.c index 2c8a980730..e1786c9351 100644 --- a/libavformat/bethsoftvid.c +++ b/libavformat/bethsoftvid.c @@ -2,20 +2,20 @@ * Bethsoft VID format Demuxer * Copyright (c) 2007 Nicholas Tung * - * 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 */ @@ -179,7 +179,7 @@ static int vid_read_packet(AVFormatContext *s, int audio_length; int ret_value; - if(vid->is_finished || pb->eof_reached) + if(vid->is_finished || url_feof(pb)) return AVERROR(EIO); block_type = avio_r8(pb); diff --git a/libavformat/bfi.c b/libavformat/bfi.c index 718e721356..97fa8025e7 100644 --- a/libavformat/bfi.c +++ b/libavformat/bfi.c @@ -2,20 +2,20 @@ * Brute Force & Ignorance (BFI) demuxer * Copyright (c) 2008 Sisir Koppaka * - * 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 */ @@ -110,7 +110,7 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt) BFIContext *bfi = s->priv_data; AVIOContext *pb = s->pb; int ret, audio_offset, video_offset, chunk_size, audio_size = 0; - if (bfi->nframes == 0 || pb->eof_reached) { + if (bfi->nframes == 0 || url_feof(pb)) { return AVERROR(EIO); } @@ -118,7 +118,7 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt) if (!bfi->avflag) { uint32_t state = 0; while(state != MKTAG('S','A','V','I')){ - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); state = 256*state + avio_r8(pb); } diff --git a/libavformat/bink.c b/libavformat/bink.c index d6af54f96e..20cf609cd0 100644 --- a/libavformat/bink.c +++ b/libavformat/bink.c @@ -3,20 +3,20 @@ * Copyright (c) 2008-2010 Peter Ross (pross@xvid.org) * Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu) * - * 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 */ @@ -257,7 +257,9 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, in return -1; /* seek to the first frame */ - avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET); + if (avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET) < 0) + return -1; + bink->video_pts = 0; memset(bink->audio_pts, 0, sizeof(bink->audio_pts)); bink->current_track = -1; diff --git a/libavformat/bintext.c b/libavformat/bintext.c new file mode 100644 index 0000000000..d9395f0798 --- /dev/null +++ b/libavformat/bintext.c @@ -0,0 +1,371 @@ +/* + * Binary text demuxer + * eXtended BINary text (XBIN) demuxer + * Artworx Data Format demuxer + * iCEDraw File demuxer + * Copyright (c) 2010 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 + */ + +/** + * @file + * Binary text demuxer + * eXtended BINary text (XBIN) demuxer + * Artworx Data Format demuxer + * iCEDraw File demuxer + */ + +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "sauce.h" +#include "libavcodec/bintext.h" + +#define LINE_RATE 6000 /** characters per second */ + +typedef struct { + int chars_per_frame; + uint64_t fsize; /**< file size less metadata buffer */ +} BinDemuxContext; + +#if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER +/** + * Given filesize and width, calculate height (assume font_height of 16) + */ +static void calculate_height(AVCodecContext *avctx, uint64_t fsize) +{ + avctx->height = (fsize / ((avctx->width>>3)*2)) << 4; +} +#endif + +#if CONFIG_BINTEXT_DEMUXER +static const uint8_t next_magic[]={ + 0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00 +}; + +static int next_tag_read(AVFormatContext *avctx, uint64_t *fsize) +{ + AVIOContext *pb = avctx->pb; + char buf[36]; + int len; + uint64_t start_pos = avio_size(pb) - 256; + + avio_seek(pb, start_pos, SEEK_SET); + if (avio_read(pb, buf, sizeof(next_magic)) != sizeof(next_magic)) + return -1; + if (memcmp(buf, next_magic, sizeof(next_magic))) + return -1; + if (avio_r8(pb) != 0x01) + return -1; + + *fsize -= 256; + +#define GET_EFI2_META(name,size) \ + len = avio_r8(pb); \ + if (len < 1 || len > size) \ + return -1; \ + if (avio_read(pb, buf, size) == size && *buf) { \ + buf[len] = 0; \ + av_dict_set(&avctx->metadata, name, buf, 0); \ + } + + GET_EFI2_META("filename", 12) + GET_EFI2_META("author", 20) + GET_EFI2_META("publisher", 20) + GET_EFI2_META("title", 35) + + return 0; +} + +static void predict_width(AVCodecContext *avctx, uint64_t fsize, int got_width) +{ + /** attempt to guess width */ + if (!got_width) + avctx->width = fsize > 4000 ? (160<<3) : (80<<3); +} + +static AVStream * init_stream(AVFormatContext *s) +{ + BinDemuxContext *bin = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return NULL; + st->codec->codec_tag = 0; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + +// if (!ap->time_base.num) { + avpriv_set_pts_info(st, 60, 1, 25); +// } else { +// avpriv_set_pts_info(st, 60, ap->time_base.num, ap->time_base.den); +// } + + /* simulate tty display speed */ + bin->chars_per_frame = FFMAX(av_q2d(st->time_base) * (/*ap->sample_rate ? ap->sample_rate :*/ LINE_RATE), 1); + + st->codec->width = /*ap->width ? ap->width :*/ (80<<3); + st->codec->height = /*ap->height ? ap->height :*/ (25<<4); + return st; +} + +static int bintext_read_header(AVFormatContext *s) +{ + BinDemuxContext *bin = s->priv_data; + AVIOContext *pb = s->pb; + + AVStream *st = init_stream(s); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_id = CODEC_ID_BINTEXT; + + st->codec->extradata_size = 2; + st->codec->extradata = av_malloc(st->codec->extradata_size); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata[0] = 16; + st->codec->extradata[1] = 0; + + if (pb->seekable) { + int got_width = 0; + bin->fsize = avio_size(pb); + if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0) + next_tag_read(s, &bin->fsize); +// if (!ap->width) + predict_width(st->codec, bin->fsize, got_width); +// if (!ap->height) + calculate_height(st->codec, bin->fsize); + avio_seek(pb, 0, SEEK_SET); + } + return 0; +}; +#endif /* CONFIG_BINTEXT_DEMUXER */ + +#if CONFIG_XBIN_DEMUXER +static int xbin_probe(AVProbeData *p) +{ + const uint8_t *d = p->buf; + + if (AV_RL32(d) == MKTAG('X','B','I','N') && d[4] == 0x1A && + AV_RL16(d+5) > 0 && AV_RL16(d+5) <= 160 && + d[9] > 0 && d[9] <= 32) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int xbin_read_header(AVFormatContext *s) +{ + BinDemuxContext *bin = s->priv_data; + AVIOContext *pb = s->pb; + char fontheight, flags; + + AVStream *st = init_stream(s); + if (!st) + return AVERROR(ENOMEM); + + avio_skip(pb, 5); + st->codec->width = avio_rl16(pb)<<3; + st->codec->height = avio_rl16(pb); + fontheight = avio_r8(pb); + st->codec->height *= fontheight; + flags = avio_r8(pb); + + st->codec->extradata_size = 2; + if ((flags & BINTEXT_PALETTE)) + st->codec->extradata_size += 48; + if ((flags & BINTEXT_FONT)) + st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256); + st->codec->codec_id = flags & 4 ? CODEC_ID_XBIN : CODEC_ID_BINTEXT; + + st->codec->extradata = av_malloc(st->codec->extradata_size); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata[0] = fontheight; + st->codec->extradata[1] = flags; + if (avio_read(pb, st->codec->extradata + 2, st->codec->extradata_size - 2) < 0) + return AVERROR(EIO); + + if (pb->seekable) { + bin->fsize = avio_size(pb) - 9 - st->codec->extradata_size; + ff_sauce_read(s, &bin->fsize, NULL, 0); + avio_seek(pb, 9 + st->codec->extradata_size, SEEK_SET); + } + + return 0; +} +#endif /* CONFIG_XBIN_DEMUXER */ + +#if CONFIG_ADF_DEMUXER +static int adf_read_header(AVFormatContext *s) +{ + BinDemuxContext *bin = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st; + + if (avio_r8(pb) != 1) + return AVERROR_INVALIDDATA; + + st = init_stream(s); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_id = CODEC_ID_BINTEXT; + + st->codec->extradata_size = 2 + 48 + 4096; + st->codec->extradata = av_malloc(st->codec->extradata_size); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata[0] = 16; + st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT; + + if (avio_read(pb, st->codec->extradata + 2, 24) < 0) + return AVERROR(EIO); + avio_skip(pb, 144); + if (avio_read(pb, st->codec->extradata + 2 + 24, 24) < 0) + return AVERROR(EIO); + if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0) + return AVERROR(EIO); + + if (pb->seekable) { + int got_width = 0; + bin->fsize = avio_size(pb) - 1 - 192 - 4096; + st->codec->width = 80<<3; + ff_sauce_read(s, &bin->fsize, &got_width, 0); +// if (!ap->height) + calculate_height(st->codec, bin->fsize); + avio_seek(pb, 1 + 192 + 4096, SEEK_SET); + } + return 0; +} +#endif /* CONFIG_ADF_DEMUXER */ + +#if CONFIG_IDF_DEMUXER +static const uint8_t idf_magic[] = { + 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00 +}; + +static int idf_probe(AVProbeData *p) +{ + if (p->buf_size < sizeof(idf_magic)) + return 0; + if (!memcmp(p->buf, idf_magic, sizeof(idf_magic))) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int idf_read_header(AVFormatContext *s) +{ + BinDemuxContext *bin = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st; + int got_width = 0; + + if (!pb->seekable) + return AVERROR(EIO); + + st = init_stream(s); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_id = CODEC_ID_IDF; + + st->codec->extradata_size = 2 + 48 + 4096; + st->codec->extradata = av_malloc(st->codec->extradata_size); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata[0] = 16; + st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT; + + avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET); + + if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0) + return AVERROR(EIO); + if (avio_read(pb, st->codec->extradata + 2, 48) < 0) + return AVERROR(EIO); + + bin->fsize = avio_size(pb) - 12 - 4096 - 48; + ff_sauce_read(s, &bin->fsize, &got_width, 0); +// if (!ap->height) + calculate_height(st->codec, bin->fsize); + avio_seek(pb, 12, SEEK_SET); + return 0; +} +#endif /* CONFIG_IDF_DEMUXER */ + +static int read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + BinDemuxContext *bin = s->priv_data; + + if (bin->fsize > 0) { + if (av_get_packet(s->pb, pkt, bin->fsize) < 0) + return AVERROR(EIO); + bin->fsize = -1; /* done */ + } else if (!bin->fsize) { + if (url_feof(s->pb)) + return AVERROR(EIO); + if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0) + return AVERROR(EIO); + } else { + return AVERROR(EIO); + } + + pkt->flags |= AV_PKT_FLAG_KEY; + return 0; +} + +#if CONFIG_BINTEXT_DEMUXER +AVInputFormat ff_bintext_demuxer = { + .name = "bin", + .long_name = NULL_IF_CONFIG_SMALL("Binary text"), + .priv_data_size = sizeof(BinDemuxContext), + .read_header = bintext_read_header, + .read_packet = read_packet, + .extensions = "bin", +}; +#endif + +#if CONFIG_XBIN_DEMUXER +AVInputFormat ff_xbin_demuxer = { + .name = "xbin", + .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"), + .priv_data_size = sizeof(BinDemuxContext), + .read_probe = xbin_probe, + .read_header = xbin_read_header, + .read_packet = read_packet, +}; +#endif + +#if CONFIG_ADF_DEMUXER +AVInputFormat ff_adf_demuxer = { + .name = "adf", + .long_name = NULL_IF_CONFIG_SMALL("Artworx Data Format"), + .priv_data_size = sizeof(BinDemuxContext), + .read_header = adf_read_header, + .read_packet = read_packet, + .extensions = "adf", +}; +#endif + +#if CONFIG_IDF_DEMUXER +AVInputFormat ff_idf_demuxer = { + .name = "idf", + .long_name = NULL_IF_CONFIG_SMALL("iCE Draw File"), + .priv_data_size = sizeof(BinDemuxContext), + .read_probe = idf_probe, + .read_header = idf_read_header, + .read_packet = read_packet, + .extensions = "idf", +}; +#endif diff --git a/libavformat/bit.c b/libavformat/bit.c new file mode 100644 index 0000000000..b0931f429b --- /dev/null +++ b/libavformat/bit.c @@ -0,0 +1,156 @@ +/* + * G.729 bit format muxer and demuxer + * Copyright (c) 2007-2008 Vladimir Voroshilov + * + * 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 "avformat.h" +#include "internal.h" +#include "libavcodec/get_bits.h" +#include "libavcodec/put_bits.h" + +#define MAX_FRAME_SIZE 10 + +#define SYNC_WORD 0x6b21 +#define BIT_0 0x7f +#define BIT_1 0x81 + +static int probe(AVProbeData *p) +{ + int i, j; + + if(p->buf_size < 0x40) + return 0; + + for(i=0; i+3<p->buf_size && i< 10*0x50; ){ + if(AV_RL16(&p->buf[0]) != SYNC_WORD) + return 0; + j=AV_RL16(&p->buf[2]); + if(j!=0x40 && j!=0x50) + return 0; + i+=j; + } + return AVPROBE_SCORE_MAX/2; +} + +static int read_header(AVFormatContext *s) +{ + AVStream* st; + + st=avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id=CODEC_ID_G729; + st->codec->sample_rate=8000; + st->codec->block_align = 16; + st->codec->channels=1; + + avpriv_set_pts_info(st, 64, 1, 100); + return 0; +} + +static int read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + AVIOContext *pb = s->pb; + PutBitContext pbo; + uint16_t buf[8 * MAX_FRAME_SIZE + 2]; + int packet_size; + uint16_t* src=buf; + int i, j, ret; + int64_t pos= avio_tell(pb); + + if(url_feof(pb)) + return AVERROR_EOF; + + avio_rl16(pb); // sync word + packet_size = avio_rl16(pb) / 8; + if(packet_size > MAX_FRAME_SIZE) + return AVERROR_INVALIDDATA; + + ret = avio_read(pb, (uint8_t*)buf, (8 * packet_size) * sizeof(uint16_t)); + if(ret<0) + return ret; + if(ret != 8 * packet_size * sizeof(uint16_t)) + return AVERROR(EIO); + + av_new_packet(pkt, packet_size); + + init_put_bits(&pbo, pkt->data, packet_size); + for(j=0; j < packet_size; j++) + for(i=0; i<8;i++) + put_bits(&pbo,1, AV_RL16(src++) == BIT_1 ? 1 : 0); + + flush_put_bits(&pbo); + + pkt->duration=1; + pkt->pos = pos; + return 0; +} + +AVInputFormat ff_bit_demuxer = { + .name = "bit", + .long_name = NULL_IF_CONFIG_SMALL("G.729 BIT file format"), + .read_probe = probe, + .read_header = read_header, + .read_packet = read_packet, + .extensions = "bit", +}; + +#if CONFIG_MUXERS +static int write_header(AVFormatContext *s) +{ + AVCodecContext *enc = s->streams[0]->codec; + + enc->codec_id = CODEC_ID_G729; + enc->channels = 1; + enc->bits_per_coded_sample = 16; + enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3; + + return 0; +} + +static int write_packet(AVFormatContext *s, AVPacket *pkt) +{ + AVIOContext *pb = s->pb; + GetBitContext gb; + int i; + + avio_wl16(pb, SYNC_WORD); + avio_wl16(pb, 8 * 10); + + 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; +} + +AVOutputFormat ff_bit_muxer = { + .name = "bit", + .long_name = NULL_IF_CONFIG_SMALL("G.729 BIT file format"), + .mime_type = "audio/bit", + .extensions = "bit", + .audio_codec = CODEC_ID_G729, + .video_codec = CODEC_ID_NONE, + .write_header = write_header, + .write_packet = write_packet, +}; +#endif diff --git a/libavformat/c93.c b/libavformat/c93.c index 21058da727..a5c2b5d7d6 100644 --- a/libavformat/c93.c +++ b/libavformat/c93.c @@ -2,20 +2,20 @@ * Interplay C93 demuxer * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.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 */ diff --git a/libavformat/cache.c b/libavformat/cache.c new file mode 100644 index 0000000000..3e60aea48f --- /dev/null +++ b/libavformat/cache.c @@ -0,0 +1,136 @@ +/* + * Input cache protocol. + * Copyright (c) 2011 Michael Niedermayer + * + * 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 + * + * Based on file.c by Fabrice Bellard + */ + +/** + * @TODO + * support non continuous caching + * support keeping files + * support filling with a background thread + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/file.h" +#include "avformat.h" +#include <fcntl.h> +#if HAVE_SETMODE +#include <io.h> +#endif +#include <unistd.h> +#include <sys/stat.h> +#include <stdlib.h> +#include "os_support.h" +#include "url.h" + +typedef struct Context { + int fd; + int64_t end; + int64_t pos; + URLContext *inner; +} Context; + +static int cache_open(URLContext *h, const char *arg, int flags) +{ + const char *buffername; + Context *c= h->priv_data; + + av_strstart(arg, "cache:", &arg); + + c->fd = av_tempfile("ffcache", &buffername, 0, h); + if (c->fd < 0){ + av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n"); + return c->fd; + } + + unlink(buffername); + av_freep(&buffername); + + return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL); +} + +static int cache_read(URLContext *h, unsigned char *buf, int size) +{ + Context *c= h->priv_data; + int r; + + if(c->pos<c->end){ + r = read(c->fd, buf, FFMIN(size, c->end - c->pos)); + if(r>0) + c->pos += r; + return (-1 == r)?AVERROR(errno):r; + }else{ + r = ffurl_read(c->inner, buf, size); + if(r > 0){ + int r2= write(c->fd, buf, r); + av_assert0(r2==r); // FIXME handle cache failure + c->pos += r; + c->end += r; + } + return r; + } +} + +static int64_t cache_seek(URLContext *h, int64_t pos, int whence) +{ + Context *c= h->priv_data; + + if (whence == AVSEEK_SIZE) { + pos= ffurl_seek(c->inner, pos, whence); + if(pos <= 0){ + pos= ffurl_seek(c->inner, -1, SEEK_END); + ffurl_seek(c->inner, c->end, SEEK_SET); + if(pos <= 0) + return c->end; + } + return pos; + } + + pos= lseek(c->fd, pos, whence); + if(pos<0){ + return pos; + }else if(pos <= c->end){ + c->pos= pos; + return pos; + }else{ + lseek(c->fd, c->pos, SEEK_SET); + return AVERROR(EPIPE); + } +} + +static int cache_close(URLContext *h) +{ + Context *c= h->priv_data; + close(c->fd); + ffurl_close(c->inner); + + return 0; +} + +URLProtocol ff_cache_protocol = { + .name = "cache", + .url_open = cache_open, + .url_read = cache_read, + .url_seek = cache_seek, + .url_close = cache_close, + .priv_data_size = sizeof(Context), +}; diff --git a/libavformat/caf.c b/libavformat/caf.c index c204c90ad1..054533038f 100644 --- a/libavformat/caf.c +++ b/libavformat/caf.c @@ -2,20 +2,20 @@ * CAF common code * Copyright (c) 2007 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 */ @@ -32,27 +32,34 @@ * Known codec tags for CAF */ const AVCodecTag ff_codec_caf_tags[] = { - { CODEC_ID_AAC, MKBETAG('a','a','c',' ') }, - { CODEC_ID_AC3, MKBETAG('a','c','-','3') }, - { CODEC_ID_ALAC, MKBETAG('a','l','a','c') }, + { CODEC_ID_AAC, MKTAG('a','a','c',' ') }, + { CODEC_ID_AC3, MKTAG('a','c','-','3') }, + { CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') }, + { CODEC_ID_ADPCM_IMA_WAV, MKTAG('m','s', 0, 17 ) }, + { CODEC_ID_ADPCM_MS, MKTAG('m','s', 0, 2 ) }, + { CODEC_ID_ALAC, MKTAG('a','l','a','c') }, + { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, /* FIXME: use DV demuxer, as done in MOV */ - /*{ CODEC_ID_DVAUDIO, MKBETAG('v','d','v','a') },*/ - /*{ CODEC_ID_DVAUDIO, MKBETAG('d','v','c','a') },*/ - { CODEC_ID_ADPCM_IMA_QT, MKBETAG('i','m','a','4') }, - { CODEC_ID_MACE3, MKBETAG('M','A','C','3') }, - { CODEC_ID_MACE6, MKBETAG('M','A','C','6') }, - { CODEC_ID_MP3, MKBETAG('.','m','p','3') }, - { CODEC_ID_MP2, MKBETAG('.','m','p','2') }, - { CODEC_ID_MP1, MKBETAG('.','m','p','1') }, - { CODEC_ID_PCM_ALAW, MKBETAG('a','l','a','w') }, - { CODEC_ID_PCM_MULAW, MKBETAG('u','l','a','w') }, - { CODEC_ID_QCELP, MKBETAG('Q','c','l','p') }, - { CODEC_ID_QDM2, MKBETAG('Q','D','M','2') }, - { CODEC_ID_QDM2, MKBETAG('Q','D','M','C') }, + /*{ CODEC_ID_DVAUDIO, MKTAG('v','d','v','a') },*/ + /*{ CODEC_ID_DVAUDIO, MKTAG('d','v','c','a') },*/ + { CODEC_ID_GSM, MKTAG('a','g','s','m') }, + { CODEC_ID_GSM_MS, MKTAG('m','s', 0, '1') }, + { CODEC_ID_MACE3, MKTAG('M','A','C','3') }, + { CODEC_ID_MACE6, MKTAG('M','A','C','6') }, + { CODEC_ID_MP1, MKTAG('.','m','p','1') }, + { CODEC_ID_MP2, MKTAG('.','m','p','2') }, + { CODEC_ID_MP3, MKTAG('.','m','p','3') }, + { CODEC_ID_MP3, MKTAG('m','s', 0 ,'U') }, + { CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') }, + { CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') }, + { CODEC_ID_QCELP, MKTAG('Q','c','l','p') }, + { CODEC_ID_QDM2, MKTAG('Q','D','M','2') }, + { CODEC_ID_QDM2, MKTAG('Q','D','M','C') }, /* currently unsupported codecs */ - /*{ AC-3 over S/PDIF MKBETAG('c','a','c','3') },*/ - /*{ MPEG4CELP MKBETAG('c','e','l','p') },*/ - /*{ MPEG4HVXC MKBETAG('h','v','x','c') },*/ - /*{ MPEG4TwinVQ MKBETAG('t','w','v','q') },*/ + /*{ AC-3 over S/PDIF MKTAG('c','a','c','3') },*/ + /*{ MPEG4CELP MKTAG('c','e','l','p') },*/ + /*{ MPEG4HVXC MKTAG('h','v','x','c') },*/ + /*{ MPEG4TwinVQ MKTAG('t','w','v','q') },*/ { CODEC_ID_NONE, 0 }, }; + diff --git a/libavformat/caf.h b/libavformat/caf.h index 7ca4dc5c66..9c25f2c683 100644 --- a/libavformat/caf.h +++ b/libavformat/caf.h @@ -2,20 +2,20 @@ * CAF common code * Copyright (c) 2007 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/libavformat/cafdec.c b/libavformat/cafdec.c index abde78d56c..8545c534ec 100644 --- a/libavformat/cafdec.c +++ b/libavformat/cafdec.c @@ -3,20 +3,20 @@ * Copyright (c) 2007 Justin Ruggles * Copyright (c) 2009 Peter Ross * - * 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 */ @@ -69,7 +69,7 @@ static int read_desc_chunk(AVFormatContext *s) /* parse format description */ st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->sample_rate = av_int2double(avio_rb64(pb)); - st->codec->codec_tag = avio_rb32(pb); + st->codec->codec_tag = avio_rl32(pb); flags = avio_rb32(pb); caf->bytes_per_packet = avio_rb32(pb); st->codec->block_align = caf->bytes_per_packet; @@ -86,7 +86,7 @@ static int read_desc_chunk(AVFormatContext *s) } /* determine codec */ - if (st->codec->codec_tag == MKBETAG('l','p','c','m')) + 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 ^ 0x2) | 0x4); else st->codec->codec_id = ff_codec_get_id(ff_codec_caf_tags, st->codec->codec_tag); @@ -121,18 +121,28 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size) } else if (st->codec->codec_id == CODEC_ID_ALAC) { #define ALAC_PREAMBLE 12 #define ALAC_HEADER 36 - if (size < ALAC_PREAMBLE + ALAC_HEADER) { - av_log(s, AV_LOG_ERROR, "invalid ALAC magic cookie\n"); - avio_skip(pb, size); - return AVERROR_INVALIDDATA; +#define ALAC_NEW_KUKI 24 + if (size == ALAC_NEW_KUKI) { + st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + memcpy(st->codec->extradata, "\0\0\0\24alac", 8); + avio_read(pb, st->codec->extradata + ALAC_HEADER - ALAC_NEW_KUKI, ALAC_NEW_KUKI); + st->codec->extradata_size = ALAC_HEADER; + } else { + if (size < ALAC_PREAMBLE + ALAC_HEADER) { + av_log(s, AV_LOG_ERROR, "invalid ALAC magic cookie\n"); + avio_skip(pb, size); + return AVERROR_INVALIDDATA; + } + avio_skip(pb, ALAC_PREAMBLE); + st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + avio_read(pb, st->codec->extradata, ALAC_HEADER); + st->codec->extradata_size = ALAC_HEADER; + avio_skip(pb, size - ALAC_PREAMBLE - ALAC_HEADER); } - avio_skip(pb, ALAC_PREAMBLE); - st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - avio_read(pb, st->codec->extradata, ALAC_HEADER); - st->codec->extradata_size = ALAC_HEADER; - avio_skip(pb, size - ALAC_PREAMBLE - ALAC_HEADER); } else { st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) @@ -188,7 +198,7 @@ static void read_info_chunk(AVFormatContext *s, int64_t size) for (i = 0; i < nb_entries; i++) { char key[32]; char value[1024]; - avio_get_str(pb, INT_MAX, key, sizeof(key)); + avio_get_str(pb, INT_MAX, key, sizeof(key)); avio_get_str(pb, INT_MAX, value, sizeof(value)); av_dict_set(&s->metadata, key, value, 0); } @@ -221,7 +231,7 @@ static int read_header(AVFormatContext *s) /* parse each chunk */ found_data = 0; - while (!pb->eof_reached) { + while (!url_feof(pb)) { /* stop at data chunk if seeking is not supported or data chunk size is unknown */ @@ -230,7 +240,7 @@ static int read_header(AVFormatContext *s) tag = avio_rb32(pb); size = avio_rb64(pb); - if (pb->eof_reached) + if (url_feof(pb)) break; switch (tag) { @@ -259,10 +269,16 @@ static int read_header(AVFormatContext *s) read_info_chunk(s, size); break; + case MKBETAG('c','h','a','n'): + if (size < 12) + return AVERROR_INVALIDDATA; + ff_mov_read_chan(s, size, st->codec); + break; + default: #define _(x) ((x) >= ' ' ? (x) : ' ') - av_log(s, AV_LOG_WARNING, "skipping CAF chunk: %08X (%c%c%c%c)\n", - tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF)); + av_log(s, AV_LOG_WARNING, "skipping CAF chunk: %08X (%c%c%c%c), size %"PRId64"\n", + tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF), size); #undef _ case MKBETAG('f','r','e','e'): if (size < 0) @@ -307,7 +323,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) int res, pkt_size = 0, pkt_frames = 0; int64_t left = CAF_MAX_PKT_SIZE; - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); /* don't read past end of data chunk */ @@ -358,6 +374,7 @@ static int read_seek(AVFormatContext *s, int stream_index, { AVStream *st = s->streams[0]; CaffContext *caf = s->priv_data; + CaffContext caf2 = *caf; int64_t pos; timestamp = FFMAX(timestamp, 0); @@ -377,7 +394,10 @@ static int read_seek(AVFormatContext *s, int stream_index, return -1; } - avio_seek(s->pb, pos + caf->data_start, SEEK_SET); + if (avio_seek(s->pb, pos + caf->data_start, SEEK_SET) < 0) { + *caf = caf2; + return -1; + } return 0; } diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c new file mode 100644 index 0000000000..c34705636d --- /dev/null +++ b/libavformat/cafenc.c @@ -0,0 +1,262 @@ +/* + * Core Audio Format muxer + * Copyright (c) 2011 Carl Eugen Hoyos + * + * 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 "avformat.h" +#include "caf.h" +#include "riff.h" +#include "isom.h" +#include "avio_internal.h" +#include "libavutil/intfloat.h" + +typedef struct { + int64_t data; + uint8_t *pkt_sizes; + int size_buffer_size; + int size_entries_used; + int packets; +} CAFContext; + +static uint32_t codec_flags(enum CodecID codec_id) { + switch (codec_id) { + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_F64BE: + return 1; //< kCAFLinearPCMFormatFlagIsFloat + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S32LE: + return 2; //< kCAFLinearPCMFormatFlagIsLittleEndian + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_F64LE: + return 3; //< kCAFLinearPCMFormatFlagIsFloat | kCAFLinearPCMFormatFlagIsLittleEndian + default: + return 0; + } +} + +static uint32_t samples_per_packet(enum CodecID codec_id, int channels) { + switch (codec_id) { + case CODEC_ID_PCM_S8: + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_F64LE: + case CODEC_ID_PCM_F64BE: + case CODEC_ID_PCM_ALAW: + case CODEC_ID_PCM_MULAW: + return 1; + case CODEC_ID_MACE3: + case CODEC_ID_MACE6: + return 6; + case CODEC_ID_ADPCM_IMA_QT: + return 64; + case CODEC_ID_AMR_NB: + case CODEC_ID_GSM: + case CODEC_ID_QCELP: + return 160; + case CODEC_ID_GSM_MS: + return 320; + case CODEC_ID_MP1: + return 384; + case CODEC_ID_MP2: + case CODEC_ID_MP3: + return 1152; + case CODEC_ID_AC3: + return 1536; + case CODEC_ID_ALAC: + case CODEC_ID_QDM2: + return 4096; + case CODEC_ID_ADPCM_IMA_WAV: + return (1024 - 4 * channels) * 8 / (4 * channels) + 1; + case CODEC_ID_ADPCM_MS: + return (1024 - 7 * channels) * 2 / channels + 2; + default: + return 0; + } +} + +static int caf_write_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVCodecContext *enc = s->streams[0]->codec; + CAFContext *caf = s->priv_data; + unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id); + + switch (enc->codec_id) { + case CODEC_ID_AAC: + case CODEC_ID_AC3: + av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n"); + return AVERROR_PATCHWELCOME; + } + + switch (enc->codec_id) { + case CODEC_ID_PCM_S8: + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_S24LE: + case CODEC_ID_PCM_S24BE: + case CODEC_ID_PCM_S32LE: + case CODEC_ID_PCM_S32BE: + case CODEC_ID_PCM_F32LE: + case CODEC_ID_PCM_F32BE: + case CODEC_ID_PCM_F64LE: + case CODEC_ID_PCM_F64BE: + case CODEC_ID_PCM_ALAW: + case CODEC_ID_PCM_MULAW: + codec_tag = MKTAG('l','p','c','m'); + } + + if (!codec_tag) { + av_log(s, AV_LOG_ERROR, "unsupported codec\n"); + return AVERROR_INVALIDDATA; + } + + if (!enc->block_align && !pb->seekable) { + av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n"); + return AVERROR_INVALIDDATA; + } + + ffio_wfourcc(pb, "caff"); //< mFileType + avio_wb16(pb, 1); //< mFileVersion + avio_wb16(pb, 0); //< mFileFlags + + ffio_wfourcc(pb, "desc"); //< Audio Description chunk + avio_wb64(pb, 32); //< mChunkSize + avio_wb64(pb, av_double2int(enc->sample_rate)); //< mSampleRate + avio_wl32(pb, codec_tag); //< mFormatID + avio_wb32(pb, codec_flags(enc->codec_id)); //< mFormatFlags + avio_wb32(pb, enc->block_align); //< mBytesPerPacket + avio_wb32(pb, samples_per_packet(enc->codec_id, enc->channels)); //< mFramesPerPacket + avio_wb32(pb, enc->channels); //< mChannelsPerFrame + avio_wb32(pb, av_get_bits_per_sample(enc->codec_id)); //< mBitsPerChannel + + if (enc->channel_layout) { + ffio_wfourcc(pb, "chan"); + avio_wb64(pb, 12); + ff_mov_write_chan(pb, enc->channel_layout); + } + + if (enc->codec_id == CODEC_ID_ALAC) { + ffio_wfourcc(pb, "kuki"); + avio_wb64(pb, 12 + enc->extradata_size); + avio_write(pb, "\0\0\0\14frmaalac", 12); + avio_write(pb, enc->extradata, enc->extradata_size); + } else if (enc->codec_id == CODEC_ID_AMR_NB) { + ffio_wfourcc(pb, "kuki"); + avio_wb64(pb, 29); + avio_write(pb, "\0\0\0\14frmasamr", 12); + avio_wb32(pb, 0x11); /* size */ + avio_write(pb, "samrFFMP", 8); + avio_w8(pb, 0); /* decoder version */ + + avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */ + avio_w8(pb, 0x00); /* Mode change period (no restriction) */ + avio_w8(pb, 0x01); /* Frames per sample */ + } else if (enc->codec_id == CODEC_ID_QDM2) { + ffio_wfourcc(pb, "kuki"); + avio_wb64(pb, enc->extradata_size); + avio_write(pb, enc->extradata, enc->extradata_size); + } + + ffio_wfourcc(pb, "data"); //< Audio Data chunk + caf->data = avio_tell(pb); + avio_wb64(pb, -1); //< mChunkSize + avio_wb32(pb, 0); //< mEditCount + + avio_flush(pb); + return 0; +} + +static int caf_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + CAFContext *caf = s->priv_data; + + avio_write(s->pb, pkt->data, pkt->size); + if (!s->streams[0]->codec->block_align) { + void *pkt_sizes = caf->pkt_sizes; + int i, alloc_size = caf->size_entries_used + 5; + if (alloc_size < 0) { + caf->pkt_sizes = NULL; + } else { + caf->pkt_sizes = av_fast_realloc(caf->pkt_sizes, + &caf->size_buffer_size, + alloc_size); + } + if (!caf->pkt_sizes) { + av_free(pkt_sizes); + return AVERROR(ENOMEM); + } + for (i = 4; i > 0; i--) { + unsigned top = pkt->size >> i * 7; + if (top) + caf->pkt_sizes[caf->size_entries_used++] = 128 | top; + } + caf->pkt_sizes[caf->size_entries_used++] = pkt->size & 127; + caf->packets++; + } + return 0; +} + +static int caf_write_trailer(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVCodecContext *enc = s->streams[0]->codec; + + if (pb->seekable) { + CAFContext *caf = s->priv_data; + int64_t file_size = avio_tell(pb); + + avio_seek(pb, caf->data, SEEK_SET); + avio_wb64(pb, file_size - caf->data - 8); + avio_seek(pb, file_size, SEEK_SET); + if (!enc->block_align) { + ffio_wfourcc(pb, "pakt"); + avio_wb64(pb, caf->size_entries_used + 24); + avio_wb64(pb, caf->packets); ///< mNumberPackets + avio_wb64(pb, caf->packets * samples_per_packet(enc->codec_id, enc->channels)); ///< mNumberValidFrames + avio_wb32(pb, 0); ///< mPrimingFrames + avio_wb32(pb, 0); ///< mRemainderFrames + avio_write(pb, caf->pkt_sizes, caf->size_entries_used); + av_freep(&caf->pkt_sizes); + caf->size_buffer_size = 0; + } + avio_flush(pb); + } + return 0; +} + +AVOutputFormat ff_caf_muxer = { + .name = "caf", + .long_name = NULL_IF_CONFIG_SMALL("Apple Core Audio Format"), + .mime_type = "audio/x-caf", + .extensions = "caf", + .priv_data_size = sizeof(CAFContext), + .audio_codec = CODEC_ID_PCM_S16BE, + .video_codec = CODEC_ID_NONE, + .write_header = caf_write_header, + .write_packet = caf_write_packet, + .write_trailer = caf_write_trailer, + .codec_tag= (const AVCodecTag* const []){ff_codec_caf_tags, 0}, +}; diff --git a/libavformat/cavsvideodec.c b/libavformat/cavsvideodec.c index 9aa9413f4c..4a399a26d1 100644 --- a/libavformat/cavsvideodec.c +++ b/libavformat/cavsvideodec.c @@ -2,20 +2,20 @@ * RAW Chinese AVS video demuxer * Copyright (c) 2009 Stefan Gehrer <stefan.gehrer@gmx.de> * - * 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/libavformat/cdg.c b/libavformat/cdg.c index c0adf3b917..e7788f35d2 100644 --- a/libavformat/cdg.c +++ b/libavformat/cdg.c @@ -2,20 +2,20 @@ * CD Graphics Demuxer * Copyright (c) 2009 Michael Tison * - * 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 */ @@ -60,6 +60,11 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) } pkt->stream_index = 0; + pkt->dts=pkt->pts= s->streams[0]->cur_dts; + + if(ret>5 && (pkt->data[0]&0x3F) == 9 && (pkt->data[1]&0x3F)==1 && !(pkt->data[2+2+1] & 0x0F)){ + pkt->flags = AV_PKT_FLAG_KEY; + } return ret; } @@ -68,5 +73,6 @@ AVInputFormat ff_cdg_demuxer = { .long_name = NULL_IF_CONFIG_SMALL("CD Graphics Format"), .read_header = read_header, .read_packet = read_packet, + .flags= AVFMT_GENERIC_INDEX, .extensions = "cdg" }; diff --git a/libavformat/concat.c b/libavformat/concat.c index 24c50c1e4e..f97354c788 100644 --- a/libavformat/concat.c +++ b/libavformat/concat.c @@ -4,20 +4,20 @@ * Copyright (c) 2007 Wolfram Gloger * Copyright (c) 2010 Michele Orrù * - * 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/libavformat/crcenc.c b/libavformat/crcenc.c index c67fd09960..1f5854e080 100644 --- a/libavformat/crcenc.c +++ b/libavformat/crcenc.c @@ -2,20 +2,20 @@ * CRC encoder (for codec/format testing) * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -57,7 +57,6 @@ static int crc_write_trailer(struct AVFormatContext *s) AVOutputFormat ff_crc_muxer = { .name = "crc", .long_name = NULL_IF_CONFIG_SMALL("CRC testing format"), - .extensions = "", .priv_data_size = sizeof(CRCState), .audio_codec = CODEC_ID_PCM_S16LE, .video_codec = CODEC_ID_RAWVIDEO, diff --git a/libavformat/cutils.c b/libavformat/cutils.c index 995524400e..22be2c3384 100644 --- a/libavformat/cutils.c +++ b/libavformat/cutils.c @@ -2,46 +2,25 @@ * various simple utilities for libavformat * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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 "internal.h" -/* add one element to a dynamic array */ -void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem) -{ - /* see similar avconv.c:grow_array() */ - int nb, nb_alloc; - intptr_t *tab; - - nb = *nb_ptr; - tab = *tab_ptr; - if ((nb & (nb - 1)) == 0) { - if (nb == 0) - nb_alloc = 1; - else - nb_alloc = nb * 2; - tab = av_realloc(tab, nb_alloc * sizeof(intptr_t)); - *tab_ptr = tab; - } - tab[nb++] = elem; - *nb_ptr = nb; -} - #define ISLEAP(y) (((y) % 4 == 0) && (((y) % 100) != 0 || ((y) % 400) == 0)) #define LEAPS_COUNT(y) ((y)/4 - (y)/100 + (y)/400) diff --git a/libavformat/daud.c b/libavformat/daud.c index 8de4aad119..de85a5fb84 100644 --- a/libavformat/daud.c +++ b/libavformat/daud.c @@ -2,20 +2,20 @@ * D-Cinema audio demuxer * Copyright (c) 2005 Reimar Döffinger * - * 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" @@ -38,7 +38,7 @@ static int daud_header(AVFormatContext *s) { static int daud_packet(AVFormatContext *s, AVPacket *pkt) { AVIOContext *pb = s->pb; int ret, size; - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); size = avio_rb16(pb); avio_rb16(pb); // unknown diff --git a/libavformat/dfa.c b/libavformat/dfa.c index 283a607168..a838b5bed1 100644 --- a/libavformat/dfa.c +++ b/libavformat/dfa.c @@ -2,20 +2,20 @@ * Chronomaster DFA Format 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 */ diff --git a/libavformat/diracdec.c b/libavformat/diracdec.c index 8cbd5b5146..6afda533dc 100644 --- a/libavformat/diracdec.c +++ b/libavformat/diracdec.c @@ -2,20 +2,20 @@ * RAW Dirac demuxer * Copyright (c) 2007 Marco Gerards <marco@gnu.org> * - * 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/libavformat/dnxhddec.c b/libavformat/dnxhddec.c index 2aa8017ad4..f89782a880 100644 --- a/libavformat/dnxhddec.c +++ b/libavformat/dnxhddec.c @@ -3,20 +3,20 @@ * Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@gmail.com> * Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de> * - * 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/libavformat/dsicin.c b/libavformat/dsicin.c index f8ba68d962..d525da650d 100644 --- a/libavformat/dsicin.c +++ b/libavformat/dsicin.c @@ -2,20 +2,20 @@ * Delphine Software International CIN File Demuxer * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) * - * 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 */ @@ -27,6 +27,7 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" +#include "avio_internal.h" typedef struct CinFileHeader { @@ -147,7 +148,7 @@ static int cin_read_frame_header(CinDemuxContext *cin, AVIOContext *pb) { hdr->video_frame_size = avio_rl32(pb); hdr->audio_frame_size = avio_rl32(pb); - if (pb->eof_reached || pb->error) + if (url_feof(pb) || pb->error) return AVERROR(EIO); if (avio_rl32(pb) != 0xAA55AA55) @@ -179,6 +180,8 @@ static int cin_read_packet(AVFormatContext *s, AVPacket *pkt) /* palette and video packet */ pkt_size = (palette_type + 3) * hdr->pal_colors_count + hdr->video_frame_size; + pkt_size = ffio_limit(pb, pkt_size); + ret = av_new_packet(pkt, 4 + pkt_size); if (ret < 0) return ret; diff --git a/libavformat/dtsdec.c b/libavformat/dtsdec.c index d61855d360..e762b85e19 100644 --- a/libavformat/dtsdec.c +++ b/libavformat/dtsdec.c @@ -2,20 +2,20 @@ * RAW DTS demuxer * Copyright (c) 2008 Benjamin Larsson * - * 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/libavformat/dv.c b/libavformat/dv.c index 4106dfdce3..106a878f7d 100644 --- a/libavformat/dv.c +++ b/libavformat/dv.c @@ -12,20 +12,20 @@ * Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com> * Funded by BBC Research & Development * - * 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 <time.h> @@ -35,6 +35,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "dv.h" +#include "libavutil/avassert.h" struct DVDemuxContext { const DVprofile* sys; /* Current DV profile. E.g.: 525/60, 625/50 */ @@ -87,6 +88,9 @@ static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t) case dv_video_control: offs = (80*5 + 48 + 5); break; + case dv_timecode: + offs = (80*1 + 3 + 3); + break; default: return NULL; } @@ -127,15 +131,19 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4], /* We work with 720p frames split in half, thus even frames have * channels 0,1 and odd 2,3. */ ipcm = (sys->height == 720 && !(frame[1] & 0x0C)) ? 2 : 0; - pcm = ppcm[ipcm++]; /* for each DIF channel */ for (chan = 0; chan < sys->n_difchan; chan++) { + av_assert0(ipcm<4); + pcm = ppcm[ipcm++]; + if (!pcm) + break; /* for each DIF segment */ for (i = 0; i < sys->difseg_size; i++) { frame += 6 * 80; /* skip DIF segment header */ if (quant == 1 && i == half_ch) { /* next stereo channel (12bit mode only) */ + av_assert0(ipcm<4); pcm = ppcm[ipcm++]; if (!pcm) break; @@ -180,9 +188,6 @@ static int dv_extract_audio(uint8_t* frame, uint8_t* ppcm[4], } /* next stereo channel (50Mbps and 100Mbps only) */ - pcm = ppcm[ipcm++]; - if (!pcm) - break; } return size; @@ -204,6 +209,12 @@ static int dv_extract_audio_info(DVDemuxContext* c, uint8_t* frame) stype = (as_pack[3] & 0x1f); /* 0 - 2CH, 2 - 4CH, 3 - 8CH */ quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */ + if (stype > 3) { + av_log(c->fctx, AV_LOG_ERROR, "stype %d is invalid\n", stype); + c->ach = 0; + return 0; + } + /* note: ach counts PAIRS of channels (i.e. stereo channels) */ ach = ((int[4]){ 1, 0, 2, 4})[stype]; if (ach == 1 && quant && freq == 2) @@ -248,10 +259,8 @@ 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; - if (!avctx->width){ - avctx->width = c->sys->width; - avctx->height = c->sys->height; - } + if (!avctx->width) + avcodec_set_dimensions(avctx, c->sys->width, c->sys->height); avctx->pix_fmt = c->sys->pix_fmt; /* finding out SAR is a little bit messy */ @@ -267,6 +276,45 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t* frame) return size; } +static int bcd2int(uint8_t bcd) +{ + int low = bcd & 0xf; + int high = bcd >> 4; + if (low > 9 || high > 9) + return -1; + return low + 10*high; +} + +static int dv_extract_timecode(DVDemuxContext* c, uint8_t* frame, char tc[32]) +{ + int hh, mm, ss, ff, drop_frame; + const uint8_t *tc_pack; + + tc_pack = dv_extract_pack(frame, dv_timecode); + if (!tc_pack) + return 0; + + ff = bcd2int(tc_pack[1] & 0x3f); + ss = bcd2int(tc_pack[2] & 0x7f); + mm = bcd2int(tc_pack[3] & 0x7f); + hh = bcd2int(tc_pack[4] & 0x3f); + drop_frame = tc_pack[1] >> 6 & 0x1; + + if (ff < 0 || ss < 0 || mm < 0 || hh < 0) + return -1; + + // For PAL systems, drop frame bit is replaced by an arbitrary + // bit so its value should not be considered. Drop frame timecode + // is only relevant for NTSC systems. + if(c->sys->ltc_divisor == 25 || c->sys->ltc_divisor == 50) { + drop_frame = 0; + } + + snprintf(tc, 32, "%02d:%02d:%02d%c%02d", + hh, mm, ss, drop_frame ? ';' : ':', ff); + return 1; +} + /* * The following 3 functions constitute our interface to the world */ @@ -318,7 +366,7 @@ int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt) } int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, - uint8_t* buf, int buf_size) + uint8_t* buf, int buf_size, int64_t pos) { int size, i; uint8_t *ppcm[4] = {0}; @@ -333,11 +381,13 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, /* FIXME: in case of no audio/bad audio we have to do something */ size = dv_extract_audio_info(c, buf); 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; ppcm[i] = c->audio_buf[i]; } - dv_extract_audio(buf, ppcm, c->sys); + if (c->ach) + dv_extract_audio(buf, ppcm, c->sys); /* We work with 720p frames split in half, thus even frames have * channels 0,1 and odd 2,3. */ @@ -356,6 +406,7 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt, size = dv_extract_video_info(c, buf); av_init_packet(pkt); pkt->data = buf; + pkt->pos = pos; pkt->size = size; pkt->flags |= AV_PKT_FLAG_KEY; pkt->stream_index = c->vst->id; @@ -402,6 +453,38 @@ typedef struct RawDVContext { uint8_t buf[DV_MAX_FRAME_SIZE]; } RawDVContext; +static int dv_read_timecode(AVFormatContext *s) { + int ret; + char timecode[32]; + int64_t pos = avio_tell(s->pb); + + // Read 3 DIF blocks: Header block and 2 Subcode blocks. + int partial_frame_size = 3 * 80; + uint8_t *partial_frame = av_mallocz(sizeof(*partial_frame) * + partial_frame_size); + + RawDVContext *c = s->priv_data; + ret = avio_read(s->pb, partial_frame, partial_frame_size); + if (ret < 0) + goto finish; + + if (ret < partial_frame_size) { + ret = -1; + goto finish; + } + + ret = dv_extract_timecode(c->dv_demux, partial_frame, timecode); + if (ret) + av_dict_set(&s->metadata, "timecode", timecode, 0); + else if (ret < 0) + av_log(s, AV_LOG_ERROR, "Detected timecode is invalid"); + +finish: + av_free(partial_frame); + avio_seek(s->pb, pos, SEEK_SET); + return ret; +} + static int dv_read_header(AVFormatContext *s) { unsigned state, marker_pos = 0; @@ -413,7 +496,7 @@ static int dv_read_header(AVFormatContext *s) state = avio_rb32(s->pb); while ((state & 0xffffff7f) != 0x1f07003f) { - if (s->pb->eof_reached) { + if (url_feof(s->pb)) { av_log(s, AV_LOG_ERROR, "Cannot find DV header.\n"); return -1; } @@ -441,6 +524,9 @@ static int dv_read_header(AVFormatContext *s) 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) + dv_read_timecode(s); + return 0; } @@ -453,13 +539,14 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) size = avpriv_dv_get_packet(c->dv_demux, pkt); if (size < 0) { + int64_t pos = avio_tell(s->pb); if (!c->dv_demux->sys) return AVERROR(EIO); size = c->dv_demux->sys->frame_size; if (avio_read(s->pb, c->buf, size) <= 0) return AVERROR(EIO); - size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size); + size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size, pos); } return size; @@ -472,10 +559,11 @@ static int dv_read_seek(AVFormatContext *s, int stream_index, DVDemuxContext *c = r->dv_demux; int64_t offset = dv_frame_offset(s, c, timestamp, flags); - dv_offset_reset(c, offset / c->sys->frame_size); + if (avio_seek(s->pb, offset, SEEK_SET) < 0) + return -1; - offset = avio_seek(s->pb, offset, SEEK_SET); - return (offset < 0) ? offset : 0; + dv_offset_reset(c, offset / c->sys->frame_size); + return 0; } static int dv_read_close(AVFormatContext *s) diff --git a/libavformat/dv.h b/libavformat/dv.h index b4bb10d4bc..722067f206 100644 --- a/libavformat/dv.h +++ b/libavformat/dv.h @@ -8,20 +8,20 @@ * Raw DV format * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -33,7 +33,7 @@ typedef struct DVDemuxContext DVDemuxContext; DVDemuxContext* avpriv_dv_init_demux(AVFormatContext* s); int avpriv_dv_get_packet(DVDemuxContext*, AVPacket *); -int avpriv_dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int); +int avpriv_dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int, int64_t); void dv_offset_reset(DVDemuxContext *c, int64_t frame_offset); typedef struct DVMuxContext DVMuxContext; diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c index 56db4d2691..205d3db027 100644 --- a/libavformat/dvenc.c +++ b/libavformat/dvenc.c @@ -11,20 +11,20 @@ * 50 Mbps (DVCPRO50) support * Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.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 */ #include <time.h> @@ -33,11 +33,15 @@ #include "avformat.h" #include "internal.h" #include "libavcodec/dvdata.h" +#include "libavcodec/timecode.h" #include "dv.h" #include "libavutil/fifo.h" #include "libavutil/mathematics.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" struct DVMuxContext { + AVClass *av_class; const DVprofile* sys; /* current DV profile, e.g.: 525/60, 625/50 */ int n_ast; /* number of stereo audio streams (up to 2) */ AVStream *ast[2]; /* stereo audio streams */ @@ -47,6 +51,7 @@ struct DVMuxContext { int has_audio; /* frame under contruction has audio */ int has_video; /* frame under contruction has video */ uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under contruction */ + struct ff_timecode tc; }; static const int dv_aaux_packs_dist[12][9] = { @@ -75,33 +80,23 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu struct tm tc; time_t ct; int ltc_frame; + uint32_t timecode; va_list ap; buf[0] = (uint8_t)pack_id; switch (pack_id) { case dv_timecode: - ct = (time_t)av_rescale_rnd(c->frames, c->sys->time_base.num, - c->sys->time_base.den, AV_ROUND_DOWN); - brktimegm(ct, &tc); /* * LTC drop-frame frame counter drops two frames (0 and 1) every * minute, unless it is exactly divisible by 10 */ - ltc_frame = (c->frames + 2 * ct / 60 - 2 * ct / 600) % c->sys->ltc_divisor; - buf[1] = (0 << 7) | /* color frame: 0 - unsync; 1 - sync mode */ - (1 << 6) | /* drop frame timecode: 0 - nondrop; 1 - drop */ - ((ltc_frame / 10) << 4) | /* tens of frames */ - (ltc_frame % 10); /* units of frames */ - buf[2] = (1 << 7) | /* biphase mark polarity correction: 0 - even; 1 - odd */ - ((tc.tm_sec / 10) << 4) | /* tens of seconds */ - (tc.tm_sec % 10); /* units of seconds */ - buf[3] = (1 << 7) | /* binary group flag BGF0 */ - ((tc.tm_min / 10) << 4) | /* tens of minutes */ - (tc.tm_min % 10); /* units of minutes */ - buf[4] = (1 << 7) | /* binary group flag BGF2 */ - (1 << 6) | /* binary group flag BGF1 */ - ((tc.tm_hour / 10) << 4) | /* tens of hours */ - (tc.tm_hour % 10); /* units of hours */ + ltc_frame = c->tc.start + c->frames; + if (c->tc.drop) + ltc_frame = avpriv_framenum_to_drop_timecode(ltc_frame); + timecode = avpriv_framenum_to_smpte_timecode(ltc_frame, c->sys->ltc_divisor, + c->tc.drop); + timecode |= 1<<23 | 1<<15 | 1<<7 | 1<<6; // biphase and binary group flags + AV_WB32(buf + 1, timecode); break; case dv_audio_source: /* AAUX source pack */ va_start(ap, buf); @@ -366,6 +361,8 @@ static void dv_delete_mux(DVMuxContext *c) static int dv_write_header(AVFormatContext *s) { + DVMuxContext *dvc = s->priv_data; + if (!dv_init_mux(s)) { av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n" "Make sure that you supply exactly two streams:\n" @@ -373,6 +370,12 @@ static int dv_write_header(AVFormatContext *s) " (50Mbps allows an optional second audio stream)\n"); return -1; } + if (dvc->tc.str) { + dvc->tc.rate.num = dvc->sys->time_base.den; + dvc->tc.rate.den = dvc->sys->time_base.num; + if (avpriv_init_smpte_timecode(s, &dvc->tc) < 0) + return -1; + } return 0; } @@ -402,6 +405,16 @@ static int dv_write_trailer(struct AVFormatContext *s) return 0; } +static const AVClass class = { + .class_name = "dv", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = (const AVOption[]){ + {TIMECODE_OPT(DVMuxContext, AV_OPT_FLAG_ENCODING_PARAM)}, + {NULL}, + }, +}; + AVOutputFormat ff_dv_muxer = { .name = "dv", .long_name = NULL_IF_CONFIG_SMALL("DV video format"), @@ -412,4 +425,5 @@ AVOutputFormat ff_dv_muxer = { .write_header = dv_write_header, .write_packet = dv_write_packet, .write_trailer = dv_write_trailer, + .priv_class = &class, }; diff --git a/libavformat/dxa.c b/libavformat/dxa.c index 13d2060465..f4e13835b2 100644 --- a/libavformat/dxa.c +++ b/libavformat/dxa.c @@ -2,20 +2,20 @@ * DXA demuxer * Copyright (c) 2007 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 */ @@ -108,7 +108,7 @@ static int dxa_read_header(AVFormatContext *s) if (ret < 0) return ret; // find 'data' chunk - while(avio_tell(pb) < c->vidpos && !pb->eof_reached){ + while(avio_tell(pb) < c->vidpos && !url_feof(pb)){ tag = avio_rl32(pb); fsize = avio_rl32(pb); if(tag == MKTAG('d', 'a', 't', 'a')) break; @@ -166,7 +166,7 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } avio_seek(s->pb, c->vidpos, SEEK_SET); - while(!s->pb->eof_reached && c->frames){ + while(!url_feof(s->pb) && c->frames){ avio_read(s->pb, buf, 4); switch(AV_RL32(buf)){ case MKTAG('N', 'U', 'L', 'L'): diff --git a/libavformat/eacdata.c b/libavformat/eacdata.c index ff9f1c8ef5..313cbe2aec 100644 --- a/libavformat/eacdata.c +++ b/libavformat/eacdata.c @@ -2,20 +2,20 @@ * Electronic Arts .cdata file Demuxer * Copyright (c) 2007 Peter Ross * - * 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 */ @@ -40,7 +40,7 @@ static int cdata_probe(AVProbeData *p) { const uint8_t *b = p->buf; - if (b[0] == 0x04 && (b[1] == 0x00 || b[1] == 0x04 || b[1] == 0x0C)) + if (b[0] == 0x04 && (b[1] == 0x00 || b[1] == 0x04 || b[1] == 0x0C || b[1] == 0x14)) return AVPROBE_SCORE_MAX/8; return 0; } @@ -51,19 +51,21 @@ static int cdata_read_header(AVFormatContext *s) AVIOContext *pb = s->pb; unsigned int sample_rate, header; AVStream *st; + int64_t channel_layout = 0; header = avio_rb16(pb); switch (header) { case 0x0400: cdata->channels = 1; break; case 0x0404: cdata->channels = 2; break; - case 0x040C: cdata->channels = 4; break; + case 0x040C: cdata->channels = 4; channel_layout = AV_CH_LAYOUT_QUAD; break; + case 0x0414: cdata->channels = 6; channel_layout = AV_CH_LAYOUT_5POINT1_BACK; break; default: av_log(s, AV_LOG_INFO, "unknown header 0x%04x\n", header); return -1; }; sample_rate = avio_rb16(pb); - avio_skip(pb, 12); + avio_skip(pb, (avio_r8(pb) & 0x20) ? 15 : 11); st = avformat_new_stream(s, NULL); if (!st) @@ -72,7 +74,9 @@ static int cdata_read_header(AVFormatContext *s) st->codec->codec_tag = 0; /* no fourcc */ st->codec->codec_id = CODEC_ID_ADPCM_EA_XAS; st->codec->channels = cdata->channels; + st->codec->channel_layout = channel_layout; st->codec->sample_rate = sample_rate; + st->codec->sample_fmt = AV_SAMPLE_FMT_S16; avpriv_set_pts_info(st, 64, 1, sample_rate); cdata->audio_pts = 0; diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c index a10e64592c..c901931dec 100644 --- a/libavformat/electronicarts.c +++ b/libavformat/electronicarts.c @@ -2,20 +2,20 @@ * Copyright (c) 2004 The ffmpeg Project * Copyright (c) 2006-2008 Peter Ross * - * 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 */ @@ -110,7 +110,7 @@ static int process_audio_header_elements(AVFormatContext *s) ea->sample_rate = -1; ea->num_channels = 1; - while (!pb->eof_reached && inHeader) { + while (!url_feof(pb) && inHeader) { int inSubheader; uint8_t byte; byte = avio_r8(pb); @@ -119,7 +119,7 @@ static int process_audio_header_elements(AVFormatContext *s) case 0xFD: av_log (s, AV_LOG_DEBUG, "entered audio subheader\n"); inSubheader = 1; - while (!pb->eof_reached && inSubheader) { + while (!url_feof(pb) && inSubheader) { uint8_t subbyte; subbyte = avio_r8(pb); @@ -331,12 +331,10 @@ static int process_ea_header(AVFormatContext *s) { case MVIh_TAG : ea->video_codec = CODEC_ID_CMV; - ea->time_base = (AVRational){0,0}; break; case kVGT_TAG: ea->video_codec = CODEC_ID_TGV; - ea->time_base = (AVRational){0,0}; break; case mTCD_TAG : @@ -405,7 +403,7 @@ static int ea_read_header(AVFormatContext *s) EaDemuxContext *ea = s->priv_data; AVStream *st; - if (!process_ea_header(s)) + if (process_ea_header(s)<=0) return AVERROR(EIO); if (ea->video_codec) { @@ -416,8 +414,12 @@ static int ea_read_header(AVFormatContext *s) ea->video_stream_index = st->index; 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 == CODEC_ID_MPEG2VIDEO) + st->need_parsing = AVSTREAM_PARSE_HEADERS; st->codec->codec_tag = 0; /* no fourcc */ - st->codec->time_base = ea->time_base; + if (ea->time_base.num) + avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den); st->codec->width = ea->width; st->codec->height = ea->height; } diff --git a/libavformat/ffm.h b/libavformat/ffm.h index 6ce5e0408c..04f19cc88e 100644 --- a/libavformat/ffm.h +++ b/libavformat/ffm.h @@ -1,21 +1,21 @@ /* - * FFM (avserver live feed) common header + * FFM (ffserver live feed) common header * Copyright (c) 2001 Fabrice Bellard * - * 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/libavformat/ffmdec.c b/libavformat/ffmdec.c index 259b6ead3f..f500511d44 100644 --- a/libavformat/ffmdec.c +++ b/libavformat/ffmdec.c @@ -1,21 +1,21 @@ /* - * FFM (avserver live feed) demuxer + * FFM (ffserver live feed) demuxer * Copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -24,7 +24,8 @@ #include "avformat.h" #include "internal.h" #include "ffm.h" -#if CONFIG_AVSERVER +#include "avio_internal.h" +#if CONFIG_FFSERVER #include <unistd.h> int64_t ffm_read_write_index(int fd) @@ -56,7 +57,7 @@ void ffm_set_write_index(AVFormatContext *s, int64_t pos, int64_t file_size) ffm->write_index = pos; ffm->file_size = file_size; } -#endif // CONFIG_AVSERVER +#endif // CONFIG_FFSERVER static int ffm_is_avail_data(AVFormatContext *s, int size) { @@ -93,7 +94,7 @@ static int ffm_resync(AVFormatContext *s, int state) { av_log(s, AV_LOG_ERROR, "resyncing\n"); while (state != PACKET_ID) { - if (s->pb->eof_reached) { + if (url_feof(s->pb)) { av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); return -1; } @@ -122,6 +123,11 @@ static int ffm_read_data(AVFormatContext *s, if (avio_tell(pb) == ffm->file_size) avio_seek(pb, ffm->packet_size, SEEK_SET); retry_read: + if (pb->buffer_size != ffm->packet_size) { + int64_t tell = avio_tell(pb); + ffio_set_buf_size(pb, ffm->packet_size); + avio_seek(pb, tell, SEEK_SET); + } id = avio_rb16(pb); /* PACKET_ID */ if (id != PACKET_ID) if (ffm_resync(s, id) < 0) @@ -167,7 +173,7 @@ static int ffm_read_data(AVFormatContext *s, /* ensure that acutal seeking happens between FFM_PACKET_SIZE and file_size - FFM_PACKET_SIZE */ -static void ffm_seek1(AVFormatContext *s, int64_t pos1) +static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1) { FFMContext *ffm = s->priv_data; AVIOContext *pb = s->pb; @@ -176,7 +182,7 @@ static void ffm_seek1(AVFormatContext *s, int64_t pos1) pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); pos = FFMAX(pos, FFM_PACKET_SIZE); av_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); - avio_seek(pb, pos, SEEK_SET); + return avio_seek(pb, pos, SEEK_SET); } static int64_t get_dts(AVFormatContext *s, int64_t pos) @@ -461,11 +467,25 @@ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, in av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); /* find the position using linear interpolation (better than dichotomy in typical cases) */ - pos_min = FFM_PACKET_SIZE; - pos_max = ffm->file_size - FFM_PACKET_SIZE; + if (ffm->write_index && ffm->write_index < ffm->file_size) { + if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) { + pos_min = FFM_PACKET_SIZE; + pos_max = ffm->write_index - FFM_PACKET_SIZE; + } else { + pos_min = ffm->write_index; + pos_max = ffm->file_size - FFM_PACKET_SIZE; + } + } else { + pos_min = FFM_PACKET_SIZE; + pos_max = ffm->file_size - FFM_PACKET_SIZE; + } while (pos_min <= pos_max) { pts_min = get_dts(s, pos_min); pts_max = get_dts(s, pos_max); + if (pts_min > wanted_pts || pts_max < wanted_pts) { + pos = pts_min > wanted_pts ? pos_min : pos_max; + goto found; + } /* linear interpolation */ pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / (double)(pts_max - pts_min); @@ -487,7 +507,8 @@ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, in pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; found: - ffm_seek1(s, pos); + if (ffm_seek1(s, pos) < 0) + return -1; /* reset read state */ ffm->read_state = READ_HEADER; @@ -509,7 +530,7 @@ static int ffm_probe(AVProbeData *p) AVInputFormat ff_ffm_demuxer = { .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed) format"), + .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed) format"), .priv_data_size = sizeof(FFMContext), .read_probe = ffm_probe, .read_header = ffm_read_header, diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c index b8d3d315bd..eb21fd79bb 100644 --- a/libavformat/ffmenc.c +++ b/libavformat/ffmenc.c @@ -1,21 +1,21 @@ /* - * FFM (avserver live feed) muxer + * FFM (ffserver live feed) muxer * Copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -241,8 +241,7 @@ static int ffm_write_trailer(AVFormatContext *s) AVOutputFormat ff_ffm_muxer = { .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (AVserver live feed) format"), - .mime_type = "", + .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed) format"), .extensions = "ffm", .priv_data_size = sizeof(FFMContext), .audio_codec = CODEC_ID_MP2, diff --git a/libavformat/ffmeta.h b/libavformat/ffmeta.h index a5380ca13d..ae8778d614 100644 --- a/libavformat/ffmeta.h +++ b/libavformat/ffmeta.h @@ -2,20 +2,20 @@ * Common data for metadata muxer/demuxer * Copyright (c) 2010 Anton Khirnov * - * 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/libavformat/ffmetadec.c b/libavformat/ffmetadec.c index 9774e946b2..98620bd321 100644 --- a/libavformat/ffmetadec.c +++ b/libavformat/ffmetadec.c @@ -2,20 +2,20 @@ * Metadata demuxer * Copyright (c) 2010 Anton Khirnov * - * 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 */ @@ -50,7 +50,7 @@ static void get_line(AVIOContext *s, uint8_t *buf, int size) buf[i++] = c; } buf[i] = 0; - } while (!s->eof_reached && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0)); + } while (!url_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0)); } static AVChapter *read_chapter(AVFormatContext *s) @@ -128,7 +128,7 @@ static int read_header(AVFormatContext *s) AVDictionary **m = &s->metadata; uint8_t line[1024]; - while(!s->pb->eof_reached) { + while(!url_feof(s->pb)) { get_line(s->pb, line, sizeof(line)); if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) { diff --git a/libavformat/ffmetaenc.c b/libavformat/ffmetaenc.c index 0aadb8a9cc..200c9940a4 100644 --- a/libavformat/ffmetaenc.c +++ b/libavformat/ffmetaenc.c @@ -2,20 +2,20 @@ * Metadata muxer * Copyright (c) 2010 Anton Khirnov * - * 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/libavformat/file.c b/libavformat/file.c index cca9ec1a06..1352bcc546 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -2,20 +2,20 @@ * buffered file I/O * Copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -37,13 +37,15 @@ static int file_read(URLContext *h, unsigned char *buf, int size) { int fd = (intptr_t) h->priv_data; - return read(fd, buf, size); + int r = read(fd, buf, size); + return (-1 == r)?AVERROR(errno):r; } static int file_write(URLContext *h, const unsigned char *buf, int size) { int fd = (intptr_t) h->priv_data; - return write(fd, buf, size); + int r = write(fd, buf, size); + return (-1 == r)?AVERROR(errno):r; } static int file_get_handle(URLContext *h) diff --git a/libavformat/filmstripdec.c b/libavformat/filmstripdec.c index 8d7b304472..0038dd3749 100644 --- a/libavformat/filmstripdec.c +++ b/libavformat/filmstripdec.c @@ -2,20 +2,20 @@ * Adobe Filmstrip demuxer * Copyright (c) 2010 Peter Ross * - * 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 int read_packet(AVFormatContext *s, FilmstripDemuxContext *film = s->priv_data; AVStream *st = s->streams[0]; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); pkt->dts = avio_tell(s->pb) / (st->codec->width * (st->codec->height + film->leading) * 4); pkt->size = av_get_packet(s->pb, pkt, st->codec->width * st->codec->height * 4); @@ -94,7 +94,8 @@ static int read_packet(AVFormatContext *s, static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { AVStream *st = s->streams[stream_index]; - avio_seek(s->pb, FFMAX(timestamp, 0) * st->codec->width * st->codec->height * 4, SEEK_SET); + if (avio_seek(s->pb, FFMAX(timestamp, 0) * st->codec->width * st->codec->height * 4, SEEK_SET) < 0) + return -1; return 0; } diff --git a/libavformat/filmstripenc.c b/libavformat/filmstripenc.c index 0e554081d5..3862cb1dba 100644 --- a/libavformat/filmstripenc.c +++ b/libavformat/filmstripenc.c @@ -2,20 +2,20 @@ * Adobe Filmstrip muxer * Copyright (c) 2010 Peter Ross * - * 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/libavformat/flacdec.c b/libavformat/flacdec.c index d127dc209f..65a75b2c48 100644 --- a/libavformat/flacdec.c +++ b/libavformat/flacdec.c @@ -2,20 +2,20 @@ * Raw FLAC demuxer * Copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -47,7 +47,7 @@ static int flac_read_header(AVFormatContext *s) } /* process metadata blocks */ - while (!s->pb->eof_reached && !metadata_last) { + while (!url_feof(s->pb) && !metadata_last) { avio_read(s->pb, header, 4); avpriv_flac_parse_block_header(header, &metadata_last, &metadata_type, &metadata_size); diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c index 725dc714ce..e7bbb783ab 100644 --- a/libavformat/flacenc.c +++ b/libavformat/flacenc.c @@ -2,20 +2,20 @@ * raw FLAC muxer * Copyright (c) 2006-2009 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 */ @@ -41,7 +41,7 @@ static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_byte static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, int last_block, int bitexact) { - const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT; + const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; unsigned int len, count; uint8_t *p, *p0; diff --git a/libavformat/flacenc.h b/libavformat/flacenc.h index 2edda67043..e83ee32aeb 100644 --- a/libavformat/flacenc.h +++ b/libavformat/flacenc.h @@ -2,20 +2,20 @@ * raw FLAC muxer * Copyright (C) 2009 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/libavformat/flacenc_header.c b/libavformat/flacenc_header.c index c1f7c86554..e16c14bf53 100644 --- a/libavformat/flacenc_header.c +++ b/libavformat/flacenc_header.c @@ -2,20 +2,20 @@ * raw FLAC muxer * Copyright (C) 2009 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/libavformat/flic.c b/libavformat/flic.c index 849ec6912d..3ad7c86cdc 100644 --- a/libavformat/flic.c +++ b/libavformat/flic.c @@ -2,20 +2,20 @@ * FLI/FLC Animation File Demuxer * Copyright (c) 2003 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 */ @@ -117,7 +117,7 @@ static int flic_read_header(AVFormatContext *s) if (!st->codec->width || !st->codec->height) { /* Ugly hack needed for the following sample: */ - /* http://samples.libav.org/fli-flc/fli-bugs/specular.flc */ + /* http://samples.mplayerhq.hu/fli-flc/fli-bugs/specular.flc */ av_log(s, AV_LOG_WARNING, "File with no specified width/height. Trying 640x480.\n"); st->codec->width = 640; diff --git a/libavformat/flv.h b/libavformat/flv.h index 6418b27419..ef8eaabb44 100644 --- a/libavformat/flv.h +++ b/libavformat/flv.h @@ -1,22 +1,22 @@ /* * FLV common header * - * Copyright (c) 2006 The Libav Project + * Copyright (c) 2006 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 */ @@ -46,6 +46,11 @@ #define AMF_END_OF_OBJECT 0x09 +#define KEYFRAMES_TAG "keyframes" +#define KEYFRAMES_TIMESTAMP_TAG "times" +#define KEYFRAMES_BYTEOFFSET_TAG "filepositions" + + enum { FLV_HEADER_FLAG_HASVIDEO = 1, FLV_HEADER_FLAG_HASAUDIO = 4, @@ -58,6 +63,13 @@ enum { }; enum { + FLV_STREAM_TYPE_VIDEO, + FLV_STREAM_TYPE_AUDIO, + FLV_STREAM_TYPE_DATA, + FLV_STREAM_TYPE_NB, +}; + +enum { FLV_MONO = 0, FLV_STEREO = 1, }; @@ -93,6 +105,8 @@ enum { FLV_CODECID_VP6A = 5, FLV_CODECID_SCREEN2 = 6, FLV_CODECID_H264 = 7, + FLV_CODECID_REALH263= 8, + FLV_CODECID_MPEG4 = 9, }; enum { diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 9296ef9d31..1f1424e949 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -1,26 +1,26 @@ /* * FLV demuxer - * Copyright (c) 2003 The Libav Project + * Copyright (c) 2003 The FFmpeg Project * * This demuxer will generate a 1 byte extradata for VP6F content. * It is composed of: * - upper 4bits: difference between encoded width and visible width * - lower 4bits: difference between encoded height and visible height * - * 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 */ @@ -35,14 +35,10 @@ #include "avio_internal.h" #include "flv.h" -#define KEYFRAMES_TAG "keyframes" -#define KEYFRAMES_TIMESTAMP_TAG "times" -#define KEYFRAMES_BYTEOFFSET_TAG "filepositions" - typedef struct { int wrong_dts; ///< wrong dts due to negative cts - uint8_t *new_extradata[2]; - int new_extradata_size[2]; + uint8_t *new_extradata[FLV_STREAM_TYPE_NB]; + int new_extradata_size[FLV_STREAM_TYPE_NB]; int last_sample_rate; int last_channels; } FLVContext; @@ -99,6 +95,7 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_co AVCodecContext *vcodec = vstream->codec; switch(flv_codecid) { case FLV_CODECID_H263 : vcodec->codec_id = CODEC_ID_FLV1 ; break; + case FLV_CODECID_REALH263: vcodec->codec_id = CODEC_ID_H263 ; break; // Really mean it this time case FLV_CODECID_SCREEN: vcodec->codec_id = CODEC_ID_FLASHSV; break; case FLV_CODECID_SCREEN2: vcodec->codec_id = CODEC_ID_FLASHSV2; break; case FLV_CODECID_VP6 : vcodec->codec_id = CODEC_ID_VP6F ; @@ -114,6 +111,9 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_co case FLV_CODECID_H264: vcodec->codec_id = CODEC_ID_H264; return 3; // not 4, reading packet type will consume one byte + case FLV_CODECID_MPEG4: + vcodec->codec_id = CODEC_ID_MPEG4; + return 3; default: av_log(s, AV_LOG_INFO, "Unsupported video codec (%x)\n", flv_codecid); vcodec->codec_tag = flv_codecid; @@ -137,63 +137,48 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) { } static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream *vstream, int64_t max_pos) { - unsigned int arraylen = 0, timeslen = 0, fileposlen = 0, i; - double num_val; + unsigned int timeslen = 0, fileposlen = 0, i; char str_val[256]; int64_t *times = NULL; int64_t *filepositions = NULL; int ret = AVERROR(ENOSYS); int64_t initial_pos = avio_tell(ioc); - AVDictionaryEntry *creator = av_dict_get(s->metadata, "metadatacreator", - NULL, 0); - - if (creator && !strcmp(creator->value, "MEGA")) { - /* Files with this metadatacreator tag seem to have filepositions - * pointing at the 4 trailer bytes of the previous packet, - * which isn't the norm (nor what we expect here, nor what - * jwplayer + lighttpd expect, nor what flvtool2 produces). - * Just ignore the index in this case, instead of risking trying - * to adjust it to something that might or might not work. */ + + if(vstream->nb_index_entries>0){ + av_log(s, AV_LOG_WARNING, "Skiping duplicate index\n"); return 0; } while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) { - int64_t* current_array; + int64_t** current_array; + unsigned int arraylen; // Expect array object in context if (avio_r8(ioc) != AMF_DATA_TYPE_ARRAY) break; arraylen = avio_rb32(ioc); - if (arraylen >> 28) + if(arraylen>>28) break; - /* - * Expect only 'times' or 'filepositions' sub-arrays in other case refuse to use such metadata - * for indexing - */ - if (!strcmp(KEYFRAMES_TIMESTAMP_TAG, str_val) && !times) { - if (!(times = av_mallocz(sizeof(*times) * arraylen))) { - ret = AVERROR(ENOMEM); - goto finish; - } - timeslen = arraylen; - current_array = times; - } else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) && !filepositions) { - if (!(filepositions = av_mallocz(sizeof(*filepositions) * arraylen))) { - ret = AVERROR(ENOMEM); - goto finish; - } - fileposlen = arraylen; - current_array = filepositions; - } 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))) { + ret = AVERROR(ENOMEM); + goto finish; + } + for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) { if (avio_r8(ioc) != AMF_DATA_TYPE_NUMBER) - goto finish; - num_val = av_int2double(avio_rb64(ioc)); - current_array[i] = num_val; + goto invalid; + current_array[0][i] = av_int2double(avio_rb64(ioc)); } if (times && filepositions) { // All done, exiting at a position allowing amf_parse_object @@ -203,19 +188,27 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream } } - if (!ret && timeslen == fileposlen) - for (i = 0; i < fileposlen; i++) + if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) { + int64_t dts, size0, size1; + avio_seek(ioc, filepositions[1]-4, SEEK_SET); + size0 = avio_rb32(ioc); + avio_r8(ioc); + size1 = avio_rb24(ioc); + dts = avio_rb24(ioc); + dts |= avio_r8(ioc) << 24; + if (size0 > filepositions[1] || FFABS(dts - times[1]*1000)>5000/*arbitraray threshold to detect invalid index*/) + goto invalid; + for(i = 0; i < timeslen; i++) av_add_index_entry(vstream, filepositions[i], times[i]*1000, 0, 0, AVINDEX_KEYFRAME); - else + } else { +invalid: av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n"); + } finish: av_freep(×); av_freep(&filepositions); - // If we got unexpected data, but successfully reset back to - // the start pos, the caller can continue parsing - if (ret < 0 && avio_seek(ioc, initial_pos, SEEK_SET) > 0) - return 0; + avio_seek(ioc, initial_pos, SEEK_SET); return ret; } @@ -243,10 +236,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst case AMF_DATA_TYPE_OBJECT: { unsigned int keylen; - if ((vstream || astream) && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1) + if ((vstream || astream) && ioc->seekable && key && !strcmp(KEYFRAMES_TAG, key) && depth == 1) if (parse_keyframes_index(s, ioc, vstream ? vstream : astream, max_pos) < 0) - return -1; + av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); while(avio_tell(ioc) < max_pos - 2 && (keylen = avio_rb16(ioc))) { avio_skip(ioc, keylen); //skip key string @@ -301,6 +294,11 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst acodec->bit_rate = num_val * 1024.0; } + if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 && + ((!acodec && !strcmp(key, "audiocodecid")) || + (!vcodec && !strcmp(key, "videocodecid")))) + s->ctx_flags &= ~AVFMTCTX_NOHEADER; //If there is either audio/video missing, codecid will be an empty object + if (!strcmp(key, "duration") || !strcmp(key, "filesize") || !strcmp(key, "width") || @@ -330,13 +328,12 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { AMFDataType type; - AVStream *stream, *astream, *vstream; + AVStream *stream, *astream, *vstream, *dstream; AVIOContext *ioc; int i; char buffer[11]; //only needs to hold the string "onMetaData". Anything longer is something we don't want. - astream = NULL; - vstream = NULL; + vstream = astream = dstream = NULL; ioc = s->pb; //first object needs to be "onMetaData" string @@ -347,8 +344,9 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { //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_AUDIO) astream = stream; - else if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) vstream = 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) @@ -358,12 +356,24 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { return 0; } -static AVStream *create_stream(AVFormatContext *s, int is_audio){ +static AVStream *create_stream(AVFormatContext *s, int stream_type){ AVStream *st = avformat_new_stream(s, NULL); if (!st) return NULL; - st->id = is_audio; - st->codec->codec_type = is_audio ? AVMEDIA_TYPE_AUDIO : AVMEDIA_TYPE_VIDEO; + st->id = stream_type; + switch(stream_type) { + case FLV_STREAM_TYPE_VIDEO: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; break; + case FLV_STREAM_TYPE_AUDIO: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; break; + case FLV_STREAM_TYPE_DATA: + st->codec->codec_type = AVMEDIA_TYPE_DATA; + st->codec->codec_id = CODEC_ID_NONE; // Going to rely on copy for now + av_log(s, AV_LOG_DEBUG, "Data stream created\n"); + } + 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; + avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */ return st; } @@ -380,19 +390,18 @@ static int flv_read_header(AVFormatContext *s) 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"); } - - if((flags & (FLV_HEADER_FLAG_HASVIDEO|FLV_HEADER_FLAG_HASAUDIO)) - != (FLV_HEADER_FLAG_HASVIDEO|FLV_HEADER_FLAG_HASAUDIO)) s->ctx_flags |= AVFMTCTX_NOHEADER; if(flags & FLV_HEADER_FLAG_HASVIDEO){ - if(!create_stream(s, 0)) + if(!create_stream(s, FLV_STREAM_TYPE_VIDEO)) return AVERROR(ENOMEM); } if(flags & FLV_HEADER_FLAG_HASAUDIO){ - if(!create_stream(s, 1)) + if(!create_stream(s, FLV_STREAM_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. offset = avio_rb32(s->pb); avio_seek(s->pb, offset, SEEK_SET); @@ -405,9 +414,10 @@ static int flv_read_header(AVFormatContext *s) static int flv_read_close(AVFormatContext *s) { + int i; FLVContext *flv = s->priv_data; - av_freep(&flv->new_extradata[0]); - av_freep(&flv->new_extradata[1]); + for(i=0; i<FLV_STREAM_TYPE_NB; i++) + av_freep(&flv->new_extradata[i]); return 0; } @@ -437,10 +447,12 @@ static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream, static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) { FLVContext *flv = s->priv_data; - int ret, i, type, size, flags, is_audio; + int ret, i, type, size, flags; + int stream_type=-1; int64_t next, pos; int64_t dts, pts = AV_NOPTS_VALUE; - int sample_rate = 0, channels = 0; + 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 */ @@ -450,7 +462,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) 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 (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR_EOF; avio_skip(s->pb, 3); /* stream id, always 0 */ flags = 0; @@ -461,20 +473,26 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) next= size + avio_tell(s->pb); if (type == FLV_TAG_TYPE_AUDIO) { - is_audio=1; + stream_type=FLV_STREAM_TYPE_AUDIO; flags = avio_r8(s->pb); size--; } else if (type == FLV_TAG_TYPE_VIDEO) { - is_audio=0; + stream_type=FLV_STREAM_TYPE_VIDEO; flags = avio_r8(s->pb); size--; if ((flags & 0xf0) == 0x50) /* video info / command frame */ goto skip; - } else { - if (type == FLV_TAG_TYPE_META && size > 13+1+4) + } else if (type == FLV_TAG_TYPE_META) { + if (size > 13+1+4 && dts == 0) { // Header-type metadata stuff flv_read_metabody(s, next); - else /* skip packet */ - av_log(s, AV_LOG_DEBUG, "skipping flv packet: type %d, size %d, flags %d\n", type, size, flags); + goto skip; + } else if (dts != 0) { // Script-data "special" metadata frames - don't skip + stream_type=FLV_STREAM_TYPE_DATA; + } else { + goto skip; + } + } 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; @@ -487,17 +505,16 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) /* now find stream */ for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; - if (st->id == is_audio) + if (st->id == stream_type) break; } if(i == s->nb_streams){ - av_log(s, AV_LOG_ERROR, "invalid stream\n"); - st= create_stream(s, is_audio); - s->ctx_flags &= ~AVFMTCTX_NOHEADER; + av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n"); + st= create_stream(s, stream_type); } - av_dlog(s, "%d %X %d \n", is_audio, flags, st->discard); - if( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || is_audio)) - ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && !is_audio)) + 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); @@ -524,7 +541,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) avio_seek(s->pb, pos, SEEK_SET); } - if(is_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); @@ -544,15 +561,16 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) flv_set_audio_codec(s, st, &ctx, flags & FLV_AUDIO_CODECID_MASK); sample_rate = ctx.sample_rate; } - }else{ + } else if(stream_type == FLV_STREAM_TYPE_VIDEO) { size -= flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK); } if (st->codec->codec_id == CODEC_ID_AAC || - st->codec->codec_id == CODEC_ID_H264) { + st->codec->codec_id == CODEC_ID_H264 || + st->codec->codec_id == CODEC_ID_MPEG4) { int type = avio_r8(s->pb); size--; - if (st->codec->codec_id == CODEC_ID_H264) { + if (st->codec->codec_id == CODEC_ID_H264 || st->codec->codec_id == CODEC_ID_MPEG4) { int32_t cts = (avio_rb24(s->pb)+0xff800000)^0xff800000; // sign extension pts = dts + cts; if (cts < 0) { // dts are wrong @@ -562,9 +580,9 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) if (flv->wrong_dts) dts = AV_NOPTS_VALUE; } - if (type == 0) { + if (type == 0 && !st->codec->extradata) { if (st->codec->extradata) { - if ((ret = flv_queue_extradata(flv, s->pb, is_audio, size)) < 0) + if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0) return ret; ret = AVERROR(EAGAIN); goto leave; @@ -573,8 +591,8 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; if (st->codec->codec_id == CODEC_ID_AAC) { MPEG4AudioConfig cfg; - avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata, - st->codec->extradata_size * 8, 1); + if (avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata, + st->codec->extradata_size * 8, 1) >= 0) { st->codec->channels = cfg.channels; if (cfg.ext_sample_rate) st->codec->sample_rate = cfg.ext_sample_rate; @@ -582,6 +600,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) st->codec->sample_rate = cfg.sample_rate; av_dlog(s, "mp4a config channels %d sample rate %d\n", st->codec->channels, st->codec->sample_rate); + } } ret = AVERROR(EAGAIN); @@ -605,24 +624,26 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->dts = dts; pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts; pkt->stream_index = st->index; - if (flv->new_extradata[is_audio]) { + if (flv->new_extradata[stream_type]) { uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, - flv->new_extradata_size[is_audio]); + flv->new_extradata_size[stream_type]); if (side) { - memcpy(side, flv->new_extradata[is_audio], - flv->new_extradata_size[is_audio]); - av_freep(&flv->new_extradata[is_audio]); - flv->new_extradata_size[is_audio] = 0; + memcpy(side, flv->new_extradata[stream_type], + flv->new_extradata_size[stream_type]); + av_freep(&flv->new_extradata[stream_type]); + flv->new_extradata_size[stream_type] = 0; } } - if (is_audio && (sample_rate != flv->last_sample_rate || + 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); } - if (is_audio || ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)) + if ( stream_type == FLV_STREAM_TYPE_AUDIO || + ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) || + stream_type == FLV_STREAM_TYPE_DATA) pkt->flags |= AV_PKT_FLAG_KEY; leave: diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c index 623bea701e..3f034bc31a 100644 --- a/libavformat/flvenc.c +++ b/libavformat/flvenc.c @@ -1,24 +1,25 @@ /* * FLV muxer - * Copyright (c) 2003 The Libav Project + * Copyright (c) 2003 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/intreadwrite.h" #include "libavutil/intfloat.h" #include "avformat.h" #include "flv.h" @@ -32,6 +33,8 @@ static const AVCodecTag flv_video_codec_ids[] = { {CODEC_ID_FLV1, FLV_CODECID_H263 }, + {CODEC_ID_H263, FLV_CODECID_REALH263}, + {CODEC_ID_MPEG4, FLV_CODECID_MPEG4 }, {CODEC_ID_FLASHSV, FLV_CODECID_SCREEN}, {CODEC_ID_FLASHSV2, FLV_CODECID_SCREEN2}, {CODEC_ID_VP6F, FLV_CODECID_VP6 }, @@ -197,7 +200,7 @@ static int flv_write_header(AVFormatContext *s) av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n"); return -1; } - } else { + } else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { audio_enc = enc; if(get_audio_flags(enc)<0) return -1; @@ -288,6 +291,22 @@ static int flv_write_header(AVFormatContext *s) } while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { + if( !strcmp(tag->key, "width") + ||!strcmp(tag->key, "height") + ||!strcmp(tag->key, "videodatarate") + ||!strcmp(tag->key, "framerate") + ||!strcmp(tag->key, "videocodecid") + ||!strcmp(tag->key, "audiodatarate") + ||!strcmp(tag->key, "audiosamplerate") + ||!strcmp(tag->key, "audiosamplesize") + ||!strcmp(tag->key, "stereo") + ||!strcmp(tag->key, "audiocodecid") + ||!strcmp(tag->key, "duration") + ||!strcmp(tag->key, "onMetaData") + ){ + av_log(s, AV_LOG_DEBUG, "ignoring metadata for %s\n", tag->key); + continue; + } put_amf_string(pb, tag->key); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, tag->value); @@ -314,7 +333,7 @@ static int flv_write_header(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; - if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264) { + if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) { int64_t pos; avio_w8(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); @@ -357,7 +376,7 @@ static int flv_write_trailer(AVFormatContext *s) AVCodecContext *enc = s->streams[i]->codec; FLVStreamContext *sc = s->streams[i]->priv_data; if (enc->codec_type == AVMEDIA_TYPE_VIDEO && - enc->codec_id == CODEC_ID_H264) { + (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4)) { put_avc_eos_tag(pb, sc->last_ts); } } @@ -390,7 +409,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if(enc->codec_id == CODEC_ID_VP6 || enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_AAC) flags_size= 2; - else if(enc->codec_id == CODEC_ID_H264) + else if(enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) flags_size= 5; else flags_size= 1; @@ -400,26 +419,35 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) flags = enc->codec_tag; if(flags == 0) { - av_log(enc, AV_LOG_ERROR, "video codec %X not compatible with flv\n",enc->codec_id); + av_log(enc, AV_LOG_ERROR, "video codec %s not compatible with flv\n", avcodec_get_name(enc->codec_id)); return -1; } flags |= pkt->flags & AV_PKT_FLAG_KEY ? FLV_FRAME_KEY : FLV_FRAME_INTER; - } else { - assert(enc->codec_type == AVMEDIA_TYPE_AUDIO); + } else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { flags = get_audio_flags(enc); assert(size); avio_w8(pb, FLV_TAG_TYPE_AUDIO); + } else { + // In-band flv metadata ("scriptdata") + assert(enc->codec_type == AVMEDIA_TYPE_DATA); + avio_w8(pb, FLV_TAG_TYPE_META); + flags_size = 0; + flags = 0; } - if (enc->codec_id == CODEC_ID_H264) { - /* check if extradata looks like MP4 */ + if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) { + /* check if extradata looks like mp4 formated */ if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1) { if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0) return -1; } + } else if (enc->codec_id == 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; } if (flv->delay == AV_NOPTS_VALUE) flv->delay = -pkt->dts; @@ -445,14 +473,17 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) avio_wb24(pb,ts); avio_w8(pb,(ts >> 24) & 0x7F); // timestamps are 32bits _signed_ avio_wb24(pb,flv->reserved); - avio_w8(pb,flags); + + if(flags_size) + avio_w8(pb,flags); + if (enc->codec_id == CODEC_ID_VP6) avio_w8(pb,0); if (enc->codec_id == CODEC_ID_VP6F) avio_w8(pb, enc->extradata_size ? enc->extradata[0] : 0); else if (enc->codec_id == CODEC_ID_AAC) avio_w8(pb,1); // AAC raw - else if (enc->codec_id == CODEC_ID_H264) { + else if (enc->codec_id == CODEC_ID_H264 || enc->codec_id == CODEC_ID_MPEG4) { avio_w8(pb,1); // AVC NALU avio_wb24(pb,pkt->pts - pkt->dts); } diff --git a/libavformat/framecrcenc.c b/libavformat/framecrcenc.c index d845e79c41..8e66a8daf3 100644 --- a/libavformat/framecrcenc.c +++ b/libavformat/framecrcenc.c @@ -2,20 +2,20 @@ * frame CRC encoder (for codec/format testing) * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -36,7 +36,6 @@ static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt) AVOutputFormat ff_framecrc_muxer = { .name = "framecrc", .long_name = NULL_IF_CONFIG_SMALL("framecrc testing format"), - .extensions = "", .audio_codec = CODEC_ID_PCM_S16LE, .video_codec = CODEC_ID_RAWVIDEO, .write_packet = framecrc_write_packet, diff --git a/libavformat/g723_1.c b/libavformat/g723_1.c new file mode 100644 index 0000000000..a12a47a1ae --- /dev/null +++ b/libavformat/g723_1.c @@ -0,0 +1,82 @@ +/* + * G.723.1 demuxer + * Copyright (c) 2010 Mohamed Naufal Basheer + * + * 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 + */ + +/** + * @file + * G.723.1 demuxer + */ + +#include "avformat.h" +#include "internal.h" + +static const uint8_t frame_size[4] = {24, 20, 4, 1}; + +static int g723_1_init(AVFormatContext *s) +{ + AVStream *st; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_G723_1; + st->codec->channels = 1; + st->codec->sample_rate = 8000; + + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + + return 0; +} + +static int g723_1_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int size, byte, ret; + + pkt->pos = avio_tell(s->pb); + byte = avio_r8(s->pb); + size = frame_size[byte & 3]; + + ret = av_new_packet(pkt, size); + if (ret < 0) + return ret; + + pkt->data[0] = byte; + pkt->duration = 240; + pkt->stream_index = 0; + + ret = avio_read(s->pb, pkt->data + 1, size - 1); + if (ret < size - 1) { + av_free_packet(pkt); + return ret < 0 ? ret : AVERROR_EOF; + } + + return pkt->size; +} + +AVInputFormat ff_g723_1_demuxer = { + .name = "g723_1", + .long_name = NULL_IF_CONFIG_SMALL("G.723.1 format"), + .read_header = g723_1_init, + .read_packet = g723_1_read_packet, + .extensions = "tco,rco", + .flags = AVFMT_GENERIC_INDEX +}; diff --git a/libavformat/g729dec.c b/libavformat/g729dec.c new file mode 100644 index 0000000000..d56da5cd7b --- /dev/null +++ b/libavformat/g729dec.c @@ -0,0 +1,103 @@ +/* + * G.729 raw format demuxer + * Copyright (c) 2011 Vladimir Voroshilov + * + * 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 "avformat.h" +#include "internal.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" + +typedef struct G729DemuxerContext { + AVClass *class; + int bit_rate; +} G729DemuxerContext; + +static int g729_read_header(AVFormatContext *s) +{ + AVStream* st; + G729DemuxerContext *s1 = s->priv_data; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_G729; + st->codec->sample_rate = 8000; + st->codec->channels = 1; + + if (s1 && s1->bit_rate) { + s->bit_rate = s1->bit_rate; + } + + if (s->bit_rate == 0) { + av_log(s, AV_LOG_DEBUG, "No bitrate specified. Assuming 8000 b/s\n"); + s->bit_rate = 8000; + } + + if (s->bit_rate == 6400) { + st->codec->block_align = 8; + } else if (s->bit_rate == 8000) { + st->codec->block_align = 10; + } else { + av_log(s, AV_LOG_ERROR, "Only 8000 b/s and 6400 b/s bitrates are supported. Provided: %d b/s\n", s->bit_rate); + return AVERROR_INVALIDDATA; + } + + avpriv_set_pts_info(st, st->codec->block_align << 3, 1, st->codec->sample_rate); + return 0; +} +static int g729_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int ret; + + ret = av_get_packet(s->pb, pkt, s->streams[0]->codec->block_align); + + pkt->stream_index = 0; + if (ret < 0) + return ret; + + pkt->dts = pkt->pts = pkt->pos / s->streams[0]->codec->block_align; + + return ret; +} + +static const AVOption g729_options[] = { + { "bit_rate", "", offsetof(G729DemuxerContext, bit_rate), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass g729_demuxer_class = { + .class_name = "g729 demuxer", + .item_name = av_default_item_name, + .option = g729_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_g729_demuxer = { + .name = "g729", + .long_name = NULL_IF_CONFIG_SMALL("G.729 raw format demuxer"), + .priv_data_size = sizeof(G729DemuxerContext), + .read_header = g729_read_header, + .read_packet = g729_read_packet, + .flags = AVFMT_GENERIC_INDEX, + .extensions = "g729", + .priv_class = &g729_demuxer_class, +}; diff --git a/libavformat/gif.c b/libavformat/gif.c index eb1e9f04fb..dc63af9778 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -2,20 +2,20 @@ * Animated GIF muxer * Copyright (c) 2000 Fabrice Bellard * - * 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/libavformat/gopher.c b/libavformat/gopher.c index a149f7fd6b..9dc155ad11 100644 --- a/libavformat/gopher.c +++ b/libavformat/gopher.c @@ -5,20 +5,20 @@ * * based on libavformat/http.c, Copyright (c) 2000, 2001 Fabrice Bellard * - * 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/libavformat/gxf.c b/libavformat/gxf.c index fcf6c93858..e557370f87 100644 --- a/libavformat/gxf.c +++ b/libavformat/gxf.c @@ -2,20 +2,20 @@ * GXF demuxer. * Copyright (c) 2006 Reimar Doeffinger * - * 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 */ @@ -29,9 +29,31 @@ struct gxf_stream_info { int64_t last_field; AVRational frames_per_second; int32_t fields_per_frame; + int64_t track_aux_data; }; /** + * @brief parse gxf timecode and add it to metadata + */ +static int add_timecode_metadata(AVDictionary **pm, const char *key, uint32_t timecode, int fields_per_frame) +{ + char tmp[128]; + int field = timecode & 0xff; + int frame = fields_per_frame ? field / fields_per_frame : field; + int second = (timecode >> 8) & 0xff; + int minute = (timecode >> 16) & 0xff; + int hour = (timecode >> 24) & 0x1f; + int drop = (timecode >> 29) & 1; + // bit 30: color_frame, unused + // ignore invalid time code + if (timecode >> 31) + return 0; + snprintf(tmp, sizeof(tmp), "%02d:%02d:%02d%c%02d", + hour, minute, second, drop ? ';' : ':', frame); + return av_dict_set(pm, key, tmp, 0); +} + +/** * @brief parses a packet header, extracting type and length * @param pb AVIOContext to read header from * @param type detected packet type is stored here @@ -210,6 +232,7 @@ static AVRational fps_umf2avr(uint32_t flags) { static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si) { si->frames_per_second = (AVRational){0, 0}; si->fields_per_frame = 0; + si->track_aux_data = 0x80000000; while (*len >= 2) { GXFTrackTag tag = avio_r8(pb); int tlen = avio_r8(pb); @@ -223,7 +246,9 @@ static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si si->frames_per_second = fps_tag2avr(value); else if (tag == TRACK_FPF && (value == 1 || value == 2)) si->fields_per_frame = value; - } else + } else if (tlen == 8 && tag == TRACK_AUX) + si->track_aux_data = avio_rl64(pb); + else avio_skip(pb, tlen); } } @@ -301,8 +326,6 @@ static int gxf_header(AVFormatContext *s) { track_id = avio_r8(pb); track_len = avio_rb16(pb); len -= track_len; - gxf_track_tags(pb, &track_len, si); - avio_skip(pb, track_len); if (!(track_type & 0x80)) { av_log(s, AV_LOG_ERROR, "invalid track type %x\n", track_type); continue; @@ -313,6 +336,16 @@ static int gxf_header(AVFormatContext *s) { continue; } track_id &= 0x3f; + gxf_track_tags(pb, &track_len, si); + // check for timecode tracks + if (track_type == 7 || track_type == 8 || track_type == 24) { + add_timecode_metadata(&s->metadata, "timecode", + si->track_aux_data & 0xffffffff, + si->fields_per_frame); + + } + avio_skip(pb, track_len); + idx = get_sindex(s, track_id, track_type); if (idx < 0) continue; st = s->streams[idx]; @@ -347,10 +380,21 @@ static int gxf_header(AVFormatContext *s) { avio_skip(pb, 0x30); // payload description fps = fps_umf2avr(avio_rl32(pb)); if (!main_timebase.num || !main_timebase.den) { + av_log(s, AV_LOG_WARNING, "No FPS track tag, using UMF fps tag." + " This might give wrong results.\n"); // this may not always be correct, but simply the best we can get main_timebase.num = fps.den; main_timebase.den = fps.num * 2; } + + if (len >= 0x18) { + len -= 0x18; + avio_skip(pb, 0x10); + add_timecode_metadata(&s->metadata, "timecode_at_mark_in", + avio_rl32(pb), si->fields_per_frame); + add_timecode_metadata(&s->metadata, "timecode_at_mark_out", + avio_rl32(pb), si->fields_per_frame); + } } else av_log(s, AV_LOG_INFO, "UMF packet too short\n"); } else @@ -369,7 +413,7 @@ static int gxf_header(AVFormatContext *s) { #define READ_ONE() \ { \ - if (!max_interval-- || pb->eof_reached) \ + if (!max_interval-- || url_feof(pb)) \ goto out; \ tmp = tmp << 8 | avio_r8(pb); \ } @@ -431,7 +475,7 @@ static int gxf_packet(AVFormatContext *s, AVPacket *pkt) { int field_nr, field_info, skip = 0; int stream_index; if (!parse_packet_header(pb, &pkt_type, &pkt_len)) { - if (!pb->eof_reached) + if (!url_feof(pb)) av_log(s, AV_LOG_ERROR, "sync lost\n"); return -1; } diff --git a/libavformat/gxf.h b/libavformat/gxf.h index c1ac399458..dcdcdefc2d 100644 --- a/libavformat/gxf.h +++ b/libavformat/gxf.h @@ -2,20 +2,20 @@ * GXF demuxer * copyright (c) 2006 Reimar Doeffinger * - * 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/libavformat/gxfenc.c b/libavformat/gxfenc.c index dcd2a8c84d..752e042cdd 100644 --- a/libavformat/gxfenc.c +++ b/libavformat/gxfenc.c @@ -2,25 +2,27 @@ * GXF muxer. * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot 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 */ #include "libavutil/intfloat.h" +#include "libavutil/opt.h" #include "libavutil/mathematics.h" +#include "libavcodec/timecode.h" #include "avformat.h" #include "internal.h" #include "gxf.h" @@ -29,6 +31,19 @@ #define GXF_AUDIO_PACKET_SIZE 65536 +#define GXF_TIMECODE(c, d, h, m, s, f) \ + ((c) << 30 | (d) << 29 | (h) << 24 | (m) << 16 | (s) << 8 | (f)) + +typedef struct GXFTimecode{ + int hh; + int mm; + int ss; + int ff; + int color; + int drop; + char *str; +} GXFTimecode; + typedef struct GXFStreamContext { AudioInterleaveContext aic; uint32_t track_type; @@ -49,6 +64,7 @@ typedef struct GXFStreamContext { } GXFStreamContext; typedef struct GXFContext { + AVClass *av_class; uint32_t nb_fields; uint16_t audio_tracks; uint16_t mpeg_tracks; @@ -67,6 +83,7 @@ typedef struct GXFContext { uint64_t *map_offsets; ///< offset of map packets unsigned map_offsets_nb; unsigned packet_count; + GXFTimecode tc; } GXFContext; static const struct { @@ -200,19 +217,21 @@ static int gxf_write_mpeg_auxiliary(AVIOContext *pb, AVStream *st) return size + 3; } -static int gxf_write_timecode_auxiliary(AVIOContext *pb, GXFStreamContext *sc) +static int gxf_write_timecode_auxiliary(AVIOContext *pb, GXFContext *gxf) { - avio_w8(pb, 0); /* fields */ - avio_w8(pb, 0); /* seconds */ - avio_w8(pb, 0); /* minutes */ - avio_w8(pb, 0); /* flags + hours */ + uint32_t timecode = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop, + gxf->tc.hh, gxf->tc.mm, + gxf->tc.ss, gxf->tc.ff); + + avio_wl32(pb, timecode); /* reserved */ - avio_wb32(pb, 0); + avio_wl32(pb, 0); return 8; } static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc, int index) { + GXFContext *gxf = s->priv_data; AVIOContext *pb = s->pb; int64_t pos; int mpeg = sc->track_type == 4 || sc->track_type == 9; @@ -236,7 +255,7 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc, avio_w8(pb, TRACK_AUX); avio_w8(pb, 8); if (sc->track_type == 3) - gxf_write_timecode_auxiliary(pb, sc); + gxf_write_timecode_auxiliary(pb, gxf); else avio_wl64(pb, 0); } @@ -343,8 +362,9 @@ static int gxf_write_map_packet(AVFormatContext *s, int rewrite) if (!rewrite) { if (!(gxf->map_offsets_nb % 30)) { - gxf->map_offsets = av_realloc(gxf->map_offsets, - (gxf->map_offsets_nb+30)*sizeof(*gxf->map_offsets)); + gxf->map_offsets = av_realloc_f(gxf->map_offsets, + sizeof(*gxf->map_offsets), + gxf->map_offsets_nb+30); if (!gxf->map_offsets) { av_log(s, AV_LOG_ERROR, "could not realloc map offsets\n"); return -1; @@ -397,25 +417,36 @@ static int gxf_write_umf_material_description(AVFormatContext *s) int timecode_base = gxf->time_base.den == 60000 ? 60 : 50; int64_t timestamp = 0; AVDictionaryEntry *t; - uint32_t timecode; + uint64_t nb_fields; + uint32_t timecode_in; // timecode at mark in + uint32_t timecode_out; // timecode at mark out if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) timestamp = ff_iso8601_to_unix_time(t->value); - // XXX drop frame - timecode = - gxf->nb_fields / (timecode_base * 3600) % 24 << 24 | // hours - gxf->nb_fields / (timecode_base * 60) % 60 << 16 | // minutes - gxf->nb_fields / timecode_base % 60 << 8 | // seconds - gxf->nb_fields % timecode_base; // fields + timecode_in = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop, + gxf->tc.hh, gxf->tc.mm, + gxf->tc.ss, gxf->tc.ff); + + nb_fields = gxf->nb_fields + + gxf->tc.hh * (timecode_base * 3600) + + gxf->tc.mm * (timecode_base * 60) + + gxf->tc.ss * timecode_base + + gxf->tc.ff; + + timecode_out = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop, + nb_fields / (timecode_base * 3600) % 24, + nb_fields / (timecode_base * 60) % 60, + nb_fields / timecode_base % 60, + nb_fields % timecode_base); avio_wl32(pb, gxf->flags); avio_wl32(pb, gxf->nb_fields); /* length of the longest track */ avio_wl32(pb, gxf->nb_fields); /* length of the shortest track */ avio_wl32(pb, 0); /* mark in */ avio_wl32(pb, gxf->nb_fields); /* mark out */ - avio_wl32(pb, 0); /* timecode mark in */ - avio_wl32(pb, timecode); /* timecode mark out */ + avio_wl32(pb, timecode_in); /* timecode mark in */ + avio_wl32(pb, timecode_out); /* timecode mark out */ avio_wl64(pb, timestamp); /* modification time */ avio_wl64(pb, timestamp); /* creation time */ avio_wl16(pb, 0); /* reserved */ @@ -490,9 +521,9 @@ static int gxf_write_umf_media_mpeg(AVIOContext *pb, AVStream *st) return 32; } -static int gxf_write_umf_media_timecode(AVIOContext *pb, GXFStreamContext *sc) +static int gxf_write_umf_media_timecode(AVIOContext *pb, int drop) { - avio_wl32(pb, 1); /* non drop frame */ + avio_wl32(pb, drop); /* drop frame */ avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ avio_wl32(pb, 0); /* reserved */ @@ -572,7 +603,7 @@ static int gxf_write_umf_media_description(AVFormatContext *s) avio_wl32(pb, 0); /* reserved */ if (sc == &gxf->timecode_track) - gxf_write_umf_media_timecode(pb, sc); /* 8 0bytes */ + gxf_write_umf_media_timecode(pb, gxf->tc.drop); else { AVStream *st = s->streams[i]; switch (st->codec->codec_id) { @@ -635,6 +666,25 @@ static void gxf_init_timecode_track(GXFStreamContext *sc, GXFStreamContext *vsc) sc->fields = vsc->fields; } +static int gxf_init_timecode(AVFormatContext *s, GXFTimecode *tc, int fields) +{ + char c; + + if (sscanf(tc->str, "%d:%d:%d%c%d", &tc->hh, &tc->mm, &tc->ss, &c, &tc->ff) != 5) { + av_log(s, AV_LOG_ERROR, "unable to parse timecode, " + "syntax: hh:mm:ss[:;.]ff\n"); + return -1; + } + + tc->color = 0; + tc->drop = c != ':'; + + if (fields == 2) + tc->ff = tc->ff * 2; + + return 0; +} + static int gxf_write_header(AVFormatContext *s) { AVIOContext *pb = s->pb; @@ -753,6 +803,10 @@ static int gxf_write_header(AVFormatContext *s) if (ff_audio_interleave_init(s, GXF_samples_per_frame, (AVRational){ 1, 48000 }) < 0) return -1; + if (gxf->tc.str) { + gxf_init_timecode(s, &gxf->tc, vsc->fields); + } + gxf_init_timecode_track(&gxf->timecode_track, vsc); gxf->flags |= 0x200000; // time code track is non-drop frame @@ -885,8 +939,9 @@ 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(gxf->flt_entries, - (gxf->flt_entries_nb+500)*sizeof(*gxf->flt_entries)); + gxf->flt_entries = av_realloc_f(gxf->flt_entries, + sizeof(*gxf->flt_entries), + gxf->flt_entries_nb+500); if (!gxf->flt_entries) { av_log(s, AV_LOG_ERROR, "could not reallocate flt entries\n"); return -1; @@ -939,6 +994,18 @@ static int gxf_interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *pk av_interleave_packet_per_dts, gxf_compare_field_nb); } +static const AVOption options[] = { + { TIMECODE_OPT(GXFContext, AV_OPT_FLAG_ENCODING_PARAM) }, + { NULL } +}; + +static const AVClass gxf_muxer_class = { + .class_name = "GXF muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_gxf_muxer = { .name = "gxf", .long_name = NULL_IF_CONFIG_SMALL("GXF format"), @@ -950,4 +1017,5 @@ AVOutputFormat ff_gxf_muxer = { .write_packet = gxf_write_packet, .write_trailer = gxf_write_trailer, .interleave_packet = gxf_interleave_packet, + .priv_class = &gxf_muxer_class, }; diff --git a/libavformat/h261dec.c b/libavformat/h261dec.c index 1b416d4fc7..354a7c78c1 100644 --- a/libavformat/h261dec.c +++ b/libavformat/h261dec.c @@ -2,20 +2,20 @@ * RAW H.261 video demuxer * Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at> * - * 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/libavformat/h263dec.c b/libavformat/h263dec.c index b9185cbcb6..b07e9782b8 100644 --- a/libavformat/h263dec.c +++ b/libavformat/h263dec.c @@ -2,20 +2,20 @@ * RAW H.263 video demuxer * Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at> * - * 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/libavformat/h264dec.c b/libavformat/h264dec.c index f9086476d5..e7c6d70deb 100644 --- a/libavformat/h264dec.c +++ b/libavformat/h264dec.c @@ -2,20 +2,20 @@ * RAW H.264 video demuxer * Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at> * - * 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 */ @@ -54,7 +54,7 @@ static int h264_probe(AVProbeData *p) case 1: sli++; break; case 5: idr++; break; case 7: - if(p->buf[i+2]&0x0F) + if(p->buf[i+2]&0x03) return 0; sps++; break; diff --git a/libavformat/http.c b/libavformat/http.c index eea8dedcbc..8922a74441 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -1,21 +1,21 @@ /* - * HTTP protocol for avconv client + * HTTP protocol for ffmpeg client * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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 */ @@ -30,7 +30,7 @@ #include "url.h" #include "libavutil/opt.h" -/* XXX: POST protocol is not completely implemented because avconv uses +/* XXX: POST protocol is not completely implemented because ffmpeg uses only a subset of it. */ /* used for protocol handling */ @@ -44,6 +44,7 @@ typedef struct { int line_count; int http_code; int64_t chunksize; /**< Used if "Transfer-Encoding: chunked" otherwise -1. */ + char *user_agent; int64_t off, filesize; char location[MAX_URL_SIZE]; HTTPAuthState auth_state; @@ -56,9 +57,11 @@ typedef struct { #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 static const AVOption options[] = { {"chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, E }, {"headers", "custom HTTP headers, can override built in default headers", OFFSET(headers), 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}, {NULL} }; #define HTTP_CLASS(flavor)\ @@ -342,8 +345,9 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, /* 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", LIBAVFORMAT_IDENT); + len += av_strlcatf(headers + len, sizeof(headers) - len, + "User-Agent: %s\r\n", + s->user_agent ? s->user_agent : LIBAVFORMAT_IDENT); if (!has_header(s->headers, "\r\nAccept: ")) len += av_strlcpy(headers + len, "Accept: */*\r\n", sizeof(headers) - len); diff --git a/libavformat/http.h b/libavformat/http.h index 8dfb192364..342434d202 100644 --- a/libavformat/http.h +++ b/libavformat/http.h @@ -2,20 +2,20 @@ * HTTP definitions * Copyright (c) 2010 Josh Allmann * - * 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/libavformat/httpauth.c b/libavformat/httpauth.c index c8b8ace3c2..2ce5432993 100644 --- a/libavformat/httpauth.c +++ b/libavformat/httpauth.c @@ -2,20 +2,20 @@ * HTTP authentication * Copyright (c) 2010 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/libavformat/httpauth.h b/libavformat/httpauth.h index d2a4a55305..ebab3fca29 100644 --- a/libavformat/httpauth.h +++ b/libavformat/httpauth.h @@ -2,20 +2,20 @@ * HTTP authentication * Copyright (c) 2010 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/libavformat/icodec.c b/libavformat/icodec.c new file mode 100644 index 0000000000..81ad0b0824 --- /dev/null +++ b/libavformat/icodec.c @@ -0,0 +1,181 @@ +/* + * Microsoft Windows ICO demuxer + * Copyright (c) 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 + */ + +/** + * @file + * Microsoft Windows ICO demuxer + */ + +#include "libavutil/intreadwrite.h" +#include "libavcodec/bytestream.h" +#include "libavcodec/bmp.h" +#include "avformat.h" +#include "internal.h" + +typedef struct { + int offset; + int size; + int nb_pal; +} IcoImage; + +typedef struct { + int current_image; + int nb_images; + IcoImage * images; +} IcoDemuxContext; + +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 0; +} + +static int read_header(AVFormatContext *s) +{ + IcoDemuxContext *ico = s->priv_data; + AVIOContext *pb = s->pb; + int i; + + avio_skip(pb, 4); + ico->nb_images = avio_rl16(pb); + + ico->images = av_malloc(ico->nb_images * sizeof(IcoImage)); + if (!ico->images) + return AVERROR(ENOMEM); + + for (i = 0; i < ico->nb_images; i++) { + AVStream *st; + int tmp; + + if (avio_seek(pb, 6 + i * 16, SEEK_SET) < 0) + break; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->width = avio_r8(pb); + st->codec->height = avio_r8(pb); + ico->images[i].nb_pal = avio_r8(pb); + if (ico->images[i].nb_pal == 255) + ico->images[i].nb_pal = 0; + + avio_skip(pb, 5); + + ico->images[i].size = avio_rl32(pb); + ico->images[i].offset = avio_rl32(pb); + + if (avio_seek(pb, ico->images[i].offset, SEEK_SET) < 0) + break; + + switch(avio_rl32(pb)) { + case MKTAG(0x89, 'P', 'N', 'G'): + st->codec->codec_id = CODEC_ID_PNG; + st->codec->width = 0; + st->codec->height = 0; + break; + case 40: + if (ico->images[i].size < 40) + return AVERROR_INVALIDDATA; + st->codec->codec_id = CODEC_ID_BMP; + tmp = avio_rl32(pb); + if (tmp) + st->codec->width = tmp; + tmp = avio_rl32(pb); + if (tmp) + st->codec->height = tmp / 2; + break; + default: + av_log_ask_for_sample(s, "unsupported codec\n"); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int read_packet(AVFormatContext *s, AVPacket *pkt) +{ + IcoDemuxContext *ico = s->priv_data; + IcoImage *image; + AVIOContext *pb = s->pb; + AVStream *st = s->streams[0]; + int ret; + + if (ico->current_image >= ico->nb_images) + return AVERROR(EIO); + + image = &ico->images[ico->current_image]; + + if ((ret = avio_seek(pb, image->offset, SEEK_SET)) < 0) + return ret; + + if (s->streams[ico->current_image]->codec->codec_id == CODEC_ID_PNG) { + if ((ret = av_get_packet(pb, pkt, image->size)) < 0) + return ret; + } else { + uint8_t *buf; + if ((ret = av_new_packet(pkt, 14 + image->size)) < 0) + return ret; + buf = pkt->data; + + /* add BMP header */ + bytestream_put_byte(&buf, 'B'); + bytestream_put_byte(&buf, 'M'); + bytestream_put_le32(&buf, pkt->size); + bytestream_put_le16(&buf, 0); + bytestream_put_le16(&buf, 0); + bytestream_put_le32(&buf, 0); + + if ((ret = avio_read(pb, buf, image->size)) < 0) + return ret; + + st->codec->bits_per_coded_sample = AV_RL16(buf + 14); + + if (AV_RL32(buf + 32)) + image->nb_pal = AV_RL32(buf + 32); + + if (st->codec->bits_per_coded_sample <= 8 && !image->nb_pal) { + image->nb_pal = 1 << st->codec->bits_per_coded_sample; + AV_WL32(buf + 32, image->nb_pal); + } + + AV_WL32(buf - 4, 14 + 40 + image->nb_pal * 4); + AV_WL32(buf + 8, AV_RL32(buf + 8) / 2); + } + + pkt->stream_index = ico->current_image++; + pkt->flags |= AV_PKT_FLAG_KEY; + + return 0; +} + +AVInputFormat ff_ico_demuxer = { + .name = "ico", + .long_name = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"), + .priv_data_size = sizeof(IcoDemuxContext), + .read_probe = probe, + .read_header = read_header, + .read_packet = read_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; diff --git a/libavformat/id3v1.c b/libavformat/id3v1.c index 87930ff361..2d1e806920 100644 --- a/libavformat/id3v1.c +++ b/libavformat/id3v1.c @@ -2,20 +2,20 @@ * ID3v1 header parser * Copyright (c) 2003 Fabrice Bellard * - * 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/libavformat/id3v1.h b/libavformat/id3v1.h index 4842f16f53..8eb58be2d1 100644 --- a/libavformat/id3v1.h +++ b/libavformat/id3v1.h @@ -2,20 +2,20 @@ * ID3v1 header parser * Copyright (c) 2003 Fabrice Bellard * - * 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/libavformat/id3v2.c b/libavformat/id3v2.c index deb652d60c..250281c357 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -1,24 +1,37 @@ /* - * ID3v2 header parser * Copyright (c) 2003 Fabrice Bellard * - * 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 */ +/** + * @file + * ID3v2 header parser + * + * Specifications available at: + * http://id3.org/Developer_Information + */ + +#include "config.h" + +#if CONFIG_ZLIB +#include <zlib.h> +#endif + #include "id3v2.h" #include "id3v1.h" #include "libavutil/avstring.h" @@ -402,7 +415,7 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34) { int i = 0; while (id3v2_extra_meta_funcs[i].tag3) { - if (!memcmp(tag, + if (tag && !memcmp(tag, (isv34 ? id3v2_extra_meta_funcs[i].tag4 : id3v2_extra_meta_funcs[i].tag3), (isv34 ? 4 : 3))) @@ -414,7 +427,8 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34) static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta) { - int isv34, tlen, unsync; + int isv34, unsync; + unsigned tlen; char tag[5]; int64_t next, end = avio_tell(s->pb) + len; int taghdrlen; @@ -423,7 +437,9 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t AVIOContext *pbx; unsigned char *buffer = NULL; int buffer_size = 0; - const ID3v2EMFunc *extra_func; + const ID3v2EMFunc *extra_func = NULL; + unsigned char *compressed_buffer = NULL; + int compressed_buffer_size = 0; switch (version) { case 2: @@ -448,12 +464,29 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t unsync = flags & 0x80; - if (isv34 && flags & 0x40) /* Extended header present, just skip over it */ - avio_skip(s->pb, get_size(s->pb, 4)); + /* Extended header present, just skip over it */ + if (isv34 && flags & 0x40) { + int size = get_size(s->pb, 4); + if (size < 6) { + reason = "extended header too short."; + goto error; + } + len -= size; + if (len < 0) { + reason = "extended header too long."; + goto error; + } + /* already seeked past size, skip the reset */ + size -= 4; + avio_skip(s->pb, size); + } while (len >= taghdrlen) { unsigned int tflags = 0; int tunsync = 0; + int tcomp = 0; + int tencr = 0; + unsigned long dlen; if (isv34) { avio_read(s->pb, tag, 4); @@ -469,11 +502,13 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t tag[3] = 0; tlen = avio_rb24(s->pb); } - if (tlen < 0 || tlen > len - taghdrlen) { - av_log(s, AV_LOG_WARNING, "Invalid size in frame %s, skipping the rest of tag.\n", tag); + if (tlen > (1<<28)) break; - } len -= taghdrlen + tlen; + + if (len < 0) + break; + next = avio_tell(s->pb) + tlen; if (!tlen) { @@ -483,24 +518,67 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t } if (tflags & ID3v2_FLAG_DATALEN) { - avio_rb32(s->pb); + if (tlen < 4) + break; + dlen = avio_rb32(s->pb); tlen -= 4; - } + } else + dlen = tlen; + + tcomp = tflags & ID3v2_FLAG_COMPRESSION; + tencr = tflags & ID3v2_FLAG_ENCRYPTION; + + /* skip encrypted tags and, if no zlib, compressed tags */ + if (tencr || (!CONFIG_ZLIB && tcomp)) { + const char *type; + if (!tcomp) + type = "encrypted"; + else if (!tencr) + type = "compressed"; + else + type = "encrypted and compressed"; - if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) { - av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag); + 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)))) { - if (unsync || tunsync) { + if (unsync || tunsync || tcomp) { int i, j; - av_fast_malloc(&buffer, &buffer_size, tlen); + + av_fast_malloc(&buffer, &buffer_size, dlen); if (!buffer) { - av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen); + av_log(s, AV_LOG_ERROR, "Failed to alloc %ld bytes\n", dlen); goto seek; } - for (i = 0, j = 0; i < tlen; i++, j++) { - buffer[j] = avio_r8(s->pb); +#if CONFIG_ZLIB + if (tcomp) { + int n, err; + + av_log(s, AV_LOG_DEBUG, "Compresssed frame %s tlen=%d dlen=%ld\n", tag, tlen, dlen); + + av_fast_malloc(&compressed_buffer, &compressed_buffer_size, tlen); + if (!compressed_buffer) { + av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen); + goto seek; + } + + n = avio_read(s->pb, compressed_buffer, tlen); + if (n < 0) { + av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n"); + goto seek; + } + + err = uncompress(buffer, &dlen, compressed_buffer, n); + if (err != Z_OK) { + av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err); + goto seek; + } + } +#endif + + for (i = 0, j = 0; i < dlen; i++, j++) { + if (!tcomp) + buffer[j] = avio_r8(s->pb); if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) { /* Unsynchronised byte, skip it */ j--; @@ -538,6 +616,7 @@ seek: 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(compressed_buffer); return; } diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index a296e0315b..ebd4a67a33 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -2,20 +2,20 @@ * ID3v2 header parser * Copyright (c) 2003 Fabrice Bellard * - * 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/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index 36c73bfecb..c3732e4789 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -1,25 +1,25 @@ /* * ID3v2 header writer * - * 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 <stdint.h> - +#include "libavutil/avstring.h" #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "avformat.h" @@ -97,6 +97,44 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const return -1; } +static void id3v2_3_metadata_split_date(AVDictionary **pm) +{ + AVDictionaryEntry *mtag = NULL; + AVDictionary *dst = NULL; + const char *key, *value; + char year[5] = {0}, day_month[5] = {0}; + int i; + + while ((mtag = av_dict_get(*pm, "", mtag, AV_DICT_IGNORE_SUFFIX))) { + key = mtag->key; + if (!av_strcasecmp(key, "date")) { + /* split date tag using "YYYY-MM-DD" format into year and month/day segments */ + value = mtag->value; + i = 0; + while (value[i] >= '0' && value[i] <= '9') i++; + if (value[i] == '\0' || value[i] == '-') { + av_strlcpy(year, value, sizeof(year)); + av_dict_set(&dst, "TYER", year, 0); + + if (value[i] == '-' && + value[i+1] >= '0' && value[i+1] <= '1' && + value[i+2] >= '0' && value[i+2] <= '9' && + value[i+3] == '-' && + value[i+4] >= '0' && value[i+4] <= '3' && + value[i+5] >= '0' && value[i+5] <= '9' && + (value[i+6] == '\0' || value[i+6] == ' ')) { + snprintf(day_month, sizeof(day_month), "%.2s%.2s", value + i + 4, value + i + 1); + av_dict_set(&dst, "TDAT", day_month, 0); + } + } else + av_dict_set(&dst, key, value, 0); + } else + av_dict_set(&dst, key, mtag->value, 0); + } + av_dict_free(pm); + *pm = dst; +} + int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, const char *magic) { @@ -116,7 +154,9 @@ int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, avio_wb32(s->pb, 0); ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL); - if (id3v2_version == 4) + if (id3v2_version == 3) + id3v2_3_metadata_split_date(&s->metadata); + else if (id3v2_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))) { diff --git a/libavformat/idcin.c b/libavformat/idcin.c index eb2cb8bf55..fd4504a566 100644 --- a/libavformat/idcin.c +++ b/libavformat/idcin.c @@ -2,20 +2,20 @@ * id Quake II CIN File Demuxer * Copyright (c) 2003 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 */ @@ -224,7 +224,7 @@ static int idcin_read_packet(AVFormatContext *s, unsigned char palette_buffer[768]; uint32_t palette[256]; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); if (idcin->next_chunk_is_video) { @@ -247,7 +247,9 @@ static int idcin_read_packet(AVFormatContext *s, r = palette_buffer[i * 3 ] << palette_scale; g = palette_buffer[i * 3 + 1] << palette_scale; b = palette_buffer[i * 3 + 2] << palette_scale; - palette[i] = (r << 16) | (g << 8) | (b); + palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); + if (palette_scale == 2) + palette[i] |= palette[i] >> 6 & 0x30303; } } @@ -263,8 +265,8 @@ static int idcin_read_packet(AVFormatContext *s, pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); - if (ret < 0) - return ret; + if (!pal) + return AVERROR(ENOMEM); memcpy(pal, palette, AVPALETTE_SIZE); } pkt->stream_index = idcin->video_stream_index; diff --git a/libavformat/idroqdec.c b/libavformat/idroqdec.c index 5c1528de0f..096ada2ba9 100644 --- a/libavformat/idroqdec.c +++ b/libavformat/idroqdec.c @@ -2,20 +2,20 @@ * id RoQ (.roq) File Demuxer * Copyright (c) 2003 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 */ @@ -30,6 +30,7 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" +#include "avio_internal.h" #define RoQ_MAGIC_NUMBER 0x1084 #define RoQ_CHUNK_PREAMBLE_SIZE 8 @@ -104,7 +105,7 @@ static int roq_read_packet(AVFormatContext *s, while (!packet_read) { - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); /* get the next chunk preamble */ @@ -117,6 +118,8 @@ static int roq_read_packet(AVFormatContext *s, if(chunk_size > INT_MAX) return AVERROR_INVALIDDATA; + chunk_size = ffio_limit(pb, chunk_size); + switch (chunk_type) { case RoQ_INFO: diff --git a/libavformat/idroqenc.c b/libavformat/idroqenc.c index 266a731cc3..b8305261fd 100644 --- a/libavformat/idroqenc.c +++ b/libavformat/idroqenc.c @@ -2,20 +2,20 @@ * id RoQ (.roq) File muxer * Copyright (c) 2007 Vitor Sessak * - * 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/libavformat/iff.c b/libavformat/iff.c index f5f39f06aa..6566a15ddb 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -1,23 +1,22 @@ /* - * IFF (.iff) file demuxer * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net> * Copyright (c) 2010 Peter Ross <pross@xvid.org> * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.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 */ @@ -29,6 +28,7 @@ * http://wiki.multimedia.cx/index.php?title=IFF */ +#include "libavcodec/bytestream.h" #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "avformat.h" @@ -42,7 +42,9 @@ #define ID_PBM MKTAG('P','B','M',' ') #define ID_ILBM MKTAG('I','L','B','M') #define ID_BMHD MKTAG('B','M','H','D') +#define ID_CAMG MKTAG('C','A','M','G') #define ID_CMAP MKTAG('C','M','A','P') +#define ID_ACBM MKTAG('A','C','B','M') #define ID_FORM MKTAG('F','O','R','M') #define ID_ANNO MKTAG('A','N','N','O') @@ -53,6 +55,7 @@ #define ID_FVER MKTAG('F','V','E','R') #define ID_NAME MKTAG('N','A','M','E') #define ID_TEXT MKTAG('T','E','X','T') +#define ID_ABIT MKTAG('A','B','I','T') #define ID_BODY MKTAG('B','O','D','Y') #define ID_ANNO MKTAG('A','N','N','O') @@ -60,6 +63,16 @@ #define RIGHT 4 #define STEREO 6 +/** + * This number of bytes if added at the beginning of each AVPacket + * which contain additional information about video properties + * which has to be shared between demuxer and decoder. + * This number may change between frames, e.g. the demuxer might + * set it to smallest possible size of 2 to indicate that there's + * no extradata changing in this frame. + */ +#define IFF_EXTRA_VIDEO_SIZE 9 + typedef enum { COMP_NONE, COMP_FIB, @@ -75,9 +88,15 @@ typedef struct { uint64_t body_pos; uint32_t body_size; uint32_t sent_bytes; + svx8_compression_type svx8_compression; + bitmap_compression_type bitmap_compression; ///< delta compression method used + unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM) + unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise) + unsigned flags; ///< 1 for EHB, 0 is no extra half darkening + unsigned transparency; ///< transparency color index in palette + unsigned masking; ///< masking method used } IffDemuxContext; - /* Metadata string read */ static int get_metadata(AVFormatContext *s, const char *const tag, @@ -102,7 +121,7 @@ static int iff_probe(AVProbeData *p) const uint8_t *d = p->buf; if ( AV_RL32(d) == ID_FORM && - (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ILBM) ) + (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ILBM || AV_RL32(d+8) == ID_ACBM) ) return AVPROBE_SCORE_MAX; return 0; } @@ -112,8 +131,11 @@ static int iff_read_header(AVFormatContext *s) IffDemuxContext *iff = s->priv_data; AVIOContext *pb = s->pb; AVStream *st; + uint8_t *buf; uint32_t chunk_id, data_size; - int compression = -1; + uint32_t screenmode = 0; + unsigned transparency = 0; + unsigned masking = 0; // no mask st = avformat_new_stream(s, NULL); if (!st) @@ -124,7 +146,7 @@ static int iff_read_header(AVFormatContext *s) // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content st->codec->codec_tag = avio_rl32(pb); - while(!pb->eof_reached) { + while(!url_feof(pb)) { uint64_t orig_pos; int res; const char *metadata_tag = NULL; @@ -142,10 +164,11 @@ static int iff_read_header(AVFormatContext *s) st->codec->sample_rate = avio_rb16(pb); if (data_size >= 16) { avio_skip(pb, 1); - compression = avio_r8(pb); + iff->svx8_compression = avio_r8(pb); } break; + case ID_ABIT: case ID_BODY: iff->body_pos = avio_tell(pb); iff->body_size = data_size; @@ -157,16 +180,23 @@ static int iff_read_header(AVFormatContext *s) st->codec->channels = (avio_rb32(pb) < 6) ? 1 : 2; break; + case ID_CAMG: + if (data_size < 4) + return AVERROR_INVALIDDATA; + screenmode = avio_rb32(pb); + break; + case ID_CMAP: - st->codec->extradata_size = data_size; - st->codec->extradata = av_malloc(data_size); + st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE; + st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) return AVERROR(ENOMEM); - if (avio_read(pb, st->codec->extradata, data_size) < 0) + if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0) return AVERROR(EIO); break; case ID_BMHD: + iff->bitmap_compression = -1; st->codec->codec_type = AVMEDIA_TYPE_VIDEO; if (data_size <= 8) return AVERROR_INVALIDDATA; @@ -174,33 +204,25 @@ static int iff_read_header(AVFormatContext *s) st->codec->height = avio_rb16(pb); avio_skip(pb, 4); // x, y offset st->codec->bits_per_coded_sample = avio_r8(pb); - if (data_size >= 11) { - avio_skip(pb, 1); // masking - compression = avio_r8(pb); + if (data_size >= 10) + masking = avio_r8(pb); + if (data_size >= 11) + iff->bitmap_compression = avio_r8(pb); + if (data_size >= 14) { + avio_skip(pb, 1); // padding + transparency = avio_rb16(pb); } if (data_size >= 16) { - avio_skip(pb, 3); // paddding, transparent st->sample_aspect_ratio.num = avio_r8(pb); st->sample_aspect_ratio.den = avio_r8(pb); } break; case ID_ANNO: - case ID_TEXT: - metadata_tag = "comment"; - break; - - case ID_AUTH: - metadata_tag = "artist"; - break; - - case ID_COPYRIGHT: - metadata_tag = "copyright"; - break; - - case ID_NAME: - metadata_tag = "title"; - break; + case ID_TEXT: metadata_tag = "comment"; break; + case ID_AUTH: metadata_tag = "artist"; break; + case ID_COPYRIGHT: metadata_tag = "copyright"; break; + case ID_NAME: metadata_tag = "title"; break; } if (metadata_tag) { @@ -218,7 +240,7 @@ static int iff_read_header(AVFormatContext *s) case AVMEDIA_TYPE_AUDIO: avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate); - switch(compression) { + switch (iff->svx8_compression) { case COMP_NONE: st->codec->codec_id = CODEC_ID_PCM_S8_PLANAR; break; @@ -229,17 +251,42 @@ static int iff_read_header(AVFormatContext *s) st->codec->codec_id = CODEC_ID_8SVX_EXP; break; default: - av_log(s, AV_LOG_ERROR, "unknown compression method\n"); + av_log(s, AV_LOG_ERROR, + "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); return -1; } - st->codec->bits_per_coded_sample = 8; + st->codec->bits_per_coded_sample = iff->svx8_compression == COMP_NONE ? 8 : 4; 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; break; case AVMEDIA_TYPE_VIDEO: - switch (compression) { + iff->bpp = st->codec->bits_per_coded_sample; + if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) { + iff->ham = iff->bpp > 6 ? 6 : 4; + st->codec->bits_per_coded_sample = 24; + } + iff->flags = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8; + iff->masking = masking; + iff->transparency = transparency; + + if (!st->codec->extradata) { + st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE; + st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + } + buf = st->codec->extradata; + bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE); + bytestream_put_byte(&buf, iff->bitmap_compression); + bytestream_put_byte(&buf, iff->bpp); + bytestream_put_byte(&buf, iff->ham); + bytestream_put_byte(&buf, iff->flags); + bytestream_put_be16(&buf, iff->transparency); + bytestream_put_byte(&buf, iff->masking); + + switch (iff->bitmap_compression) { case BITMAP_RAW: st->codec->codec_id = CODEC_ID_IFF_ILBM; break; @@ -247,7 +294,8 @@ static int iff_read_header(AVFormatContext *s) st->codec->codec_id = CODEC_ID_IFF_BYTERUN1; break; default: - av_log(s, AV_LOG_ERROR, "unknown compression method\n"); + av_log(s, AV_LOG_ERROR, + "Unknown bitmap compression method '%d'\n", iff->bitmap_compression); return AVERROR_INVALIDDATA; } break; @@ -263,14 +311,27 @@ static int iff_read_packet(AVFormatContext *s, { IffDemuxContext *iff = s->priv_data; AVIOContext *pb = s->pb; + AVStream *st = s->streams[0]; int ret; if(iff->sent_bytes >= iff->body_size) return AVERROR_EOF; - ret = av_get_packet(pb, pkt, iff->body_size); - if (ret < 0) - return ret; + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + ret = av_get_packet(pb, pkt, iff->body_size); + } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + uint8_t *buf; + + if (av_new_packet(pkt, iff->body_size + 2) < 0) { + return AVERROR(ENOMEM); + } + + buf = pkt->data; + bytestream_put_be16(&buf, 2); + ret = avio_read(pb, buf, iff->body_size); + } else { + av_abort(); + } if(iff->sent_bytes == 0) pkt->flags |= AV_PKT_FLAG_KEY; diff --git a/libavformat/img2.c b/libavformat/img2.c index f7a9fa5e30..18b9cde230 100644 --- a/libavformat/img2.c +++ b/libavformat/img2.c @@ -3,20 +3,20 @@ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * Copyright (c) 2004 Michael Niedermayer * - * 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 */ @@ -37,11 +37,13 @@ typedef struct { int img_number; int img_count; int is_pipe; + 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 loop; + int updatefirst; } VideoData; typedef struct { @@ -53,6 +55,7 @@ static const IdStrMap img_tags[] = { { CODEC_ID_MJPEG , "jpeg"}, { CODEC_ID_MJPEG , "jpg"}, { CODEC_ID_LJPEG , "ljpg"}, + { CODEC_ID_JPEGLS , "jls"}, { CODEC_ID_PNG , "png"}, { CODEC_ID_PNG , "mng"}, { CODEC_ID_PPM , "ppm"}, @@ -66,6 +69,7 @@ static const IdStrMap img_tags[] = { { CODEC_ID_MPEG4 , "mpg4-img"}, { CODEC_ID_FFV1 , "ffv1-img"}, { CODEC_ID_RAWVIDEO , "y"}, + { CODEC_ID_RAWVIDEO , "raw"}, { CODEC_ID_BMP , "bmp"}, { CODEC_ID_GIF , "gif"}, { CODEC_ID_TARGA , "tga"}, @@ -81,6 +85,8 @@ static const IdStrMap img_tags[] = { { CODEC_ID_SUNRAST , "im8"}, { CODEC_ID_SUNRAST , "im24"}, { CODEC_ID_SUNRAST , "sunras"}, + { CODEC_ID_JPEG2000 , "j2c"}, + { CODEC_ID_JPEG2000 , "j2k"}, { CODEC_ID_JPEG2000 , "jp2"}, { CODEC_ID_JPEG2000 , "jpc"}, { CODEC_ID_DPX , "dpx"}, @@ -265,8 +271,12 @@ static int read_header(AVFormatContext *s1) st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = s1->audio_codec_id; }else{ + const char *str= strrchr(s->path, '.'); + s->split_planes = str && !av_strcasecmp(str + 1, "y"); st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = av_str2id(img_tags, s->path); + if (st->codec->codec_id == CODEC_ID_LJPEG) + st->codec->codec_id = CODEC_ID_MJPEG; } if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pix_fmt != PIX_FMT_NONE) st->codec->pix_fmt = pix_fmt; @@ -303,7 +313,7 @@ static int read_packet(AVFormatContext *s1, AVPacket *pkt) } size[i]= avio_size(f[i]); - if(codec->codec_id != CODEC_ID_RAWVIDEO) + if(!s->split_planes) break; filename[ strlen(filename) - 1 ]= 'U' + i; } @@ -312,7 +322,7 @@ static int read_packet(AVFormatContext *s1, AVPacket *pkt) infer_size(&codec->width, &codec->height, size[0]); } else { f[0] = s1->pb; - if (f[0]->eof_reached) + if (url_feof(f[0])) return AVERROR(EIO); size[0]= 4096; } @@ -349,6 +359,7 @@ static int read_packet(AVFormatContext *s1, AVPacket *pkt) static int write_header(AVFormatContext *s) { VideoData *img = s->priv_data; + const char *str; img->img_number = 1; av_strlcpy(img->path, s->filename, sizeof(img->path)); @@ -359,6 +370,8 @@ static int write_header(AVFormatContext *s) else img->is_pipe = 1; + str = strrchr(img->path, '.'); + img->split_planes = str && !av_strcasecmp(str + 1, "y"); return 0; } @@ -372,11 +385,11 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) if (!img->is_pipe) { if (av_get_frame_filename(filename, sizeof(filename), - img->path, img->img_number) < 0 && img->img_number>1) { + img->path, img->img_number) < 0 && img->img_number>1 && !img->updatefirst) { av_log(s, AV_LOG_ERROR, "Could not get frame filename number %d from pattern '%s'\n", img->img_number, img->path); - return AVERROR(EIO); + return AVERROR(EINVAL); } for(i=0; i<3; i++){ if (avio_open2(&pb[i], filename, AVIO_FLAG_WRITE, @@ -385,7 +398,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EIO); } - if(codec->codec_id != CODEC_ID_RAWVIDEO) + if(!img->split_planes) break; filename[ strlen(filename) - 1 ]= 'U' + i; } @@ -393,7 +406,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) pb[0] = s->pb; } - if(codec->codec_id == CODEC_ID_RAWVIDEO){ + if(img->split_planes){ int ysize = codec->width * codec->height; avio_write(pb[0], pkt->data , ysize); avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize)/2); @@ -418,11 +431,13 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) avio_wb32(pb[0], 0); ffio_wfourcc(pb[0], "jp2 "); avio_write(pb[0], st->codec->extradata, st->codec->extradata_size); + }else if(pkt->size >= 8 && AV_RB32(pkt->data) == 0xFF4FFF51){ + //jpeg2000 codestream }else if(pkt->size < 8 || (!st->codec->extradata_size && AV_RL32(pkt->data+4) != MKTAG('j','P',' ',' '))){ // signature error: - av_log(s, AV_LOG_ERROR, "malformed JPEG 2000 codestream\n"); + av_log(s, AV_LOG_ERROR, "malformed JPEG 2000 codestream %X\n", AV_RB32(pkt->data)); return -1; } } @@ -441,6 +456,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) #define OFFSET(x) offsetof(VideoData, x) #define DEC AV_OPT_FLAG_DECODING_PARAM +#define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "pixel_format", "", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, { "video_size", "", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, @@ -449,6 +465,11 @@ static const AVOption options[] = { { NULL }, }; +static const AVOption muxoptions[] = { + { "updatefirst", "", OFFSET(updatefirst), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, ENC }, + { NULL }, +}; + /* input */ #if CONFIG_IMAGE2_DEMUXER static const AVClass img2_class = { @@ -487,16 +508,23 @@ AVInputFormat ff_image2pipe_demuxer = { /* output */ #if CONFIG_IMAGE2_MUXER +static const AVClass img2mux_class = { + .class_name = "image2 muxer", + .item_name = av_default_item_name, + .option = muxoptions, + .version = LIBAVUTIL_VERSION_INT, +}; AVOutputFormat ff_image2_muxer = { .name = "image2", .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), - .extensions = "bmp,dpx,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png," - "ppm,sgi,tga,tif,tiff,jp2,xwd", + .extensions = "bmp,dpx,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png," + "ppm,sgi,tga,tif,tiff,jp2,j2c,xwd", .priv_data_size = sizeof(VideoData), .video_codec = CODEC_ID_MJPEG, .write_header = write_header, .write_packet = write_packet, - .flags = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS | AVFMT_NOFILE + .flags = AVFMT_NOTIMESTAMPS | AVFMT_NODIMENSIONS | AVFMT_NOFILE, + .priv_class = &img2mux_class, }; #endif #if CONFIG_IMAGE2PIPE_MUXER diff --git a/libavformat/ingenientdec.c b/libavformat/ingenientdec.c index 35ac649695..97774abbcd 100644 --- a/libavformat/ingenientdec.c +++ b/libavformat/ingenientdec.c @@ -2,20 +2,20 @@ * RAW Ingenient MJPEG demuxer * Copyright (c) 2005 Alex Beregszaszi * - * 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/libavformat/internal.h b/libavformat/internal.h index 559e710014..c8376f7dda 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -1,20 +1,20 @@ /* * copyright (c) 2001 Fabrice Bellard * - * 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 */ @@ -37,20 +37,18 @@ typedef struct AVCodecTag { unsigned int tag; } AVCodecTag; -void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem); - #ifdef __GNUC__ #define dynarray_add(tab, nb_ptr, elem)\ do {\ __typeof__(tab) _tab = (tab);\ __typeof__(elem) _elem = (elem);\ (void)sizeof(**_tab == _elem); /* check that types are compatible */\ - ff_dynarray_add((intptr_t **)_tab, nb_ptr, (intptr_t)_elem);\ + av_dynarray_add(_tab, nb_ptr, _elem);\ } while(0) #else #define dynarray_add(tab, nb_ptr, elem)\ do {\ - ff_dynarray_add((intptr_t **)(tab), nb_ptr, (intptr_t)(elem));\ + av_dynarray_add((tab), nb_ptr, (elem));\ } while(0) #endif @@ -73,8 +71,9 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i /** * Add packet to AVFormatContext->packet_buffer list, determining its * interleaved position using compare() function argument. + * @return 0, or < 0 on error */ -void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, +int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, int (*compare)(AVFormatContext *, AVPacket *, AVPacket *)); void ff_read_frame_flush(AVFormatContext *s); diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c index 152b40ec7b..a60b961573 100644 --- a/libavformat/ipmovie.c +++ b/libavformat/ipmovie.c @@ -2,20 +2,20 @@ * Interplay MVE File Demuxer * Copyright (c) 2003 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 */ @@ -116,7 +116,7 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, int chunk_type; - if (s->audio_chunk_offset) { + if (s->audio_chunk_offset && s->audio_channels && s->audio_bits) { if (s->audio_type == CODEC_ID_NONE) { av_log(NULL, AV_LOG_ERROR, "Can not read audio packet before" "audio codec is known\n"); @@ -236,7 +236,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, return chunk_type; /* read the next chunk, wherever the file happens to be pointing */ - if (pb->eof_reached) + if (url_feof(pb)) return CHUNK_EOF; if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != CHUNK_PREAMBLE_SIZE) @@ -282,7 +282,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { /* read the next chunk, wherever the file happens to be pointing */ - if (pb->eof_reached) { + if (url_feof(pb)) { chunk_type = CHUNK_EOF; break; } @@ -475,7 +475,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, r = scratch[j++] * 4; g = scratch[j++] * 4; b = scratch[j++] * 4; - s->palette[i] = (r << 16) | (g << 8) | (b); + s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); + s->palette[i] |= s->palette[i] >> 6 & 0x30303; } s->has_palette = 1; break; @@ -542,14 +543,14 @@ static int ipmovie_read_header(AVFormatContext *s) AVPacket pkt; AVStream *st; unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; - int chunk_type; + int chunk_type, i; uint8_t signature_buffer[sizeof(signature)]; avio_read(pb, signature_buffer, sizeof(signature_buffer)); while (memcmp(signature_buffer, signature, sizeof(signature))) { memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1); signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb); - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR_EOF; } /* initialize private context members */ @@ -560,6 +561,9 @@ static int ipmovie_read_header(AVFormatContext *s) /* on the first read, this will position the stream at the first chunk */ ipmovie->next_chunk_offset = avio_tell(pb) + 4; + for (i = 0; i < 256; i++) + ipmovie->palette[i] = 0xFFU << 24; + /* process the first chunk which should be CHUNK_INIT_VIDEO */ if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO) return AVERROR_INVALIDDATA; @@ -619,6 +623,7 @@ static int ipmovie_read_packet(AVFormatContext *s, AVIOContext *pb = s->pb; int ret; + for (;;) { ret = process_ipmovie_chunk(ipmovie, pb, pkt); if (ret == CHUNK_BAD) ret = AVERROR_INVALIDDATA; @@ -628,10 +633,13 @@ static int ipmovie_read_packet(AVFormatContext *s, ret = AVERROR(ENOMEM); else if (ret == CHUNK_VIDEO) ret = 0; + else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO) + continue; else ret = -1; return ret; + } } AVInputFormat ff_ipmovie_demuxer = { diff --git a/libavformat/isom.c b/libavformat/isom.c index eab304c006..01a4ec558c 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -4,20 +4,20 @@ * Copyright (c) 2002 Francois Revol <revol@free.fr> * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@free.fr> * - * 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 */ @@ -89,8 +89,13 @@ const AVCodecTag codec_movvideo_tags[] = { { CODEC_ID_R10K, MKTAG('R', '1', '0', 'k') }, /* UNCOMPRESSED 10BIT RGB */ { CODEC_ID_R10K, MKTAG('R', '1', '0', 'g') }, /* UNCOMPRESSED 10BIT RGB */ { CODEC_ID_R210, MKTAG('r', '2', '1', '0') }, /* UNCOMPRESSED 10BIT RGB */ + { CODEC_ID_AVRP, MKTAG('A', 'V', 'r', 'p') }, /* Avid 1:1 10-bit RGB Packer */ + { CODEC_ID_AVRP, MKTAG('S', 'U', 'D', 'S') }, /* Avid DS Uncompressed */ { CODEC_ID_V210, MKTAG('v', '2', '1', '0') }, /* UNCOMPRESSED 10BIT 4:2:2 */ + { CODEC_ID_V308, MKTAG('v', '3', '0', '8') }, /* UNCOMPRESSED 4:4:4 */ { CODEC_ID_V410, MKTAG('v', '4', '1', '0') }, /* UNCOMPRESSED 10BIT 4:4:4 */ + { CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') }, /* UNCOMPRESSED 12BIT 4:1:1 */ + { CODEC_ID_YUV4, MKTAG('y', 'u', 'v', '4') }, /* libquicktime packed yuv420p */ { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */ { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */ @@ -155,6 +160,7 @@ const AVCodecTag codec_movvideo_tags[] = { { CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */ { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'e', 'g') }, /* MPEG */ + { CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') }, { CODEC_ID_MPEG2VIDEO, MKTAG('m', '2', 'v', '1') }, /* Apple MPEG-2 Camcorder */ { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '1') }, /* MPEG2 HDV 720p30 */ { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '2') }, /* MPEG2 HDV 1080i60 */ @@ -207,7 +213,7 @@ const AVCodecTag codec_movvideo_tags[] = { { CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') }, { CODEC_ID_DNXHD, MKTAG('A', 'V', 'd', 'n') }, /* AVID DNxHD */ - { CODEC_ID_FLV1, MKTAG('H', '2', '6', '3') }, /* Flash Media Server */ +// { CODEC_ID_FLV1, MKTAG('H', '2', '6', '3') }, /* Flash Media Server */ { CODEC_ID_MSMPEG4V3, MKTAG('3', 'I', 'V', 'D') }, /* 3ivx DivX Doctor */ { CODEC_ID_RAWVIDEO, MKTAG('A', 'V', '1', 'x') }, /* AVID 1:1x */ { CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'u', 'p') }, @@ -235,6 +241,7 @@ const AVCodecTag codec_movaudio_tags[] = { { CODEC_ID_DTS, MKTAG('D', 'T', 'S', ' ') }, /* non-standard */ { CODEC_ID_DVAUDIO, MKTAG('v', 'd', 'v', 'a') }, { CODEC_ID_DVAUDIO, MKTAG('d', 'v', 'c', 'a') }, + { CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') }, /* ETSI TS 102 366 Annex F */ { CODEC_ID_GSM, MKTAG('a', 'g', 's', 'm') }, { CODEC_ID_MACE3, MKTAG('M', 'A', 'C', '3') }, { CODEC_ID_MACE6, MKTAG('M', 'A', 'C', '6') }, @@ -441,3 +448,87 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext } return 0; } + +typedef struct MovChannelLayout { + int64_t channel_layout; + uint32_t layout_tag; +} MovChannelLayout; + +static const MovChannelLayout mov_channel_layout[] = { + { AV_CH_LAYOUT_MONO, (100<<16) | 1}, // kCAFChannelLayoutTag_Mono + { AV_CH_LAYOUT_STEREO, (101<<16) | 2}, // kCAFChannelLayoutTag_Stereo + { AV_CH_LAYOUT_STEREO, (102<<16) | 2}, // kCAFChannelLayoutTag_StereoHeadphones + { AV_CH_LAYOUT_2_1, (131<<16) | 3}, // kCAFChannelLayoutTag_ITU_2_1 + { AV_CH_LAYOUT_QUAD, (132<<16) | 4}, // kCAFChannelLayoutTag_ITU_2_2 + { AV_CH_LAYOUT_2_2, (132<<16) | 4}, // kCAFChannelLayoutTag_ITU_2_2 + { AV_CH_LAYOUT_QUAD, (108<<16) | 4}, // kCAFChannelLayoutTag_Quadraphonic + { AV_CH_LAYOUT_SURROUND, (113<<16) | 3}, // kCAFChannelLayoutTag_MPEG_3_0_A + { AV_CH_LAYOUT_4POINT0, (115<<16) | 4}, // kCAFChannelLayoutTag_MPEG_4_0_A + { AV_CH_LAYOUT_5POINT0_BACK, (117<<16) | 5}, // kCAFChannelLayoutTag_MPEG_5_0_A + { AV_CH_LAYOUT_5POINT0, (117<<16) | 5}, // kCAFChannelLayoutTag_MPEG_5_0_A + { AV_CH_LAYOUT_5POINT1_BACK, (121<<16) | 6}, // kCAFChannelLayoutTag_MPEG_5_1_A + { AV_CH_LAYOUT_5POINT1, (121<<16) | 6}, // kCAFChannelLayoutTag_MPEG_5_1_A + { AV_CH_LAYOUT_7POINT1, (128<<16) | 8}, // kCAFChannelLayoutTag_MPEG_7_1_C + { AV_CH_LAYOUT_7POINT1_WIDE, (126<<16) | 8}, // kCAFChannelLayoutTag_MPEG_7_1_A + { AV_CH_LAYOUT_5POINT1_BACK|AV_CH_LAYOUT_STEREO_DOWNMIX, (130<<16) | 8}, // kCAFChannelLayoutTag_SMPTE_DTV + { AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY, (133<<16) | 3}, // kCAFChannelLayoutTag_DVD_4 + { AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY, (134<<16) | 4}, // kCAFChannelLayoutTag_DVD_5 + { AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY, (135<<16) | 4}, // kCAFChannelLayoutTag_DVD_6 + { AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY, (135<<16) | 4}, // kCAFChannelLayoutTag_DVD_6 + { AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, (136<<16) | 4}, // kCAFChannelLayoutTag_DVD_10 + { AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, (137<<16) | 5}, // kCAFChannelLayoutTag_DVD_11 + { 0, 0}, +}; + +void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec) +{ + uint32_t layout_tag; + AVIOContext *pb = s->pb; + const MovChannelLayout *layouts = mov_channel_layout; + layout_tag = avio_rb32(pb); + size -= 4; + if (layout_tag == 0) { // kCAFChannelLayoutTag_UseChannelDescriptions + // Channel descriptions not implemented + av_log_ask_for_sample(s, "Unimplemented container channel layout.\n"); + avio_skip(pb, size); + return; + } + if (layout_tag == 0x10000) { // kCAFChannelLayoutTag_UseChannelBitmap + codec->channel_layout = avio_rb32(pb); + size -= 4; + avio_skip(pb, size); + return; + } + while (layouts->channel_layout) { + if (layout_tag == layouts->layout_tag) { + codec->channel_layout = layouts->channel_layout; + break; + } + layouts++; + } + if (!codec->channel_layout) + av_log(s, AV_LOG_WARNING, "Unknown container channel layout.\n"); + avio_skip(pb, size); +} + +void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout) +{ + const MovChannelLayout *layouts; + uint32_t layout_tag = 0; + + for (layouts = mov_channel_layout; layouts->channel_layout; layouts++) + if (channel_layout == layouts->channel_layout) { + layout_tag = layouts->layout_tag; + break; + } + + if (layout_tag) { + avio_wb32(pb, layout_tag); // mChannelLayoutTag + avio_wb32(pb, 0); // mChannelBitmap + } else { + avio_wb32(pb, 0x10000); // kCAFChannelLayoutTag_UseChannelBitmap + avio_wb32(pb, channel_layout); + } + avio_wb32(pb, 0); // mNumberChannelDescriptions +} + diff --git a/libavformat/isom.h b/libavformat/isom.h index 16d777651a..da2b74a329 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -4,20 +4,20 @@ * copyright (c) 2002 Francois Revol <revol@free.fr> * copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@free.fr> * - * 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 */ @@ -109,7 +109,9 @@ typedef struct MOVStreamContext { unsigned int keyframe_count; int *keyframes; int time_scale; - int64_t time_offset; ///< time offset of the first edit list entry + int64_t empty_duration; ///< empty duration of the first edit list entry + int64_t start_time; ///< start time of the media + int64_t time_offset; ///< time offset of the edit list entries int current_sample; unsigned int bytes_per_frame; unsigned int samples_per_frame; @@ -129,6 +131,7 @@ typedef struct MOVStreamContext { } MOVStreamContext; typedef struct MOVContext { + AVClass *avclass; AVFormatContext *fc; int time_scale; int64_t duration; ///< duration of the longest track @@ -142,6 +145,7 @@ typedef struct MOVContext { unsigned trex_count; int itunes_metadata; ///< metadata are itunes style int chapter_track; + int use_absolute_path; } MOVContext; int ff_mp4_read_descr_len(AVIOContext *pb); @@ -160,5 +164,7 @@ int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb, MOVAtom atom); enum CodecID ff_mov_get_lpcm_codec_id(int bps, int flags); int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries); +void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec); +void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout); #endif /* AVFORMAT_ISOM_H */ diff --git a/libavformat/iss.c b/libavformat/iss.c index c2ba1f0eb5..a60dc1f4a0 100644 --- a/libavformat/iss.c +++ b/libavformat/iss.c @@ -2,20 +2,20 @@ * ISS (.iss) file demuxer * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net> * - * 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 */ @@ -87,6 +87,11 @@ static av_cold int iss_read_header(AVFormatContext *s) get_token(pb, token, sizeof(token)); //Version ID get_token(pb, token, sizeof(token)); //Size + if (iss->packet_size <= 0) { + av_log(s, AV_LOG_ERROR, "packet_size %d is invalid\n", iss->packet_size); + return AVERROR_INVALIDDATA; + } + iss->sample_start_pos = avio_tell(pb); st = avformat_new_stream(s, NULL); diff --git a/libavformat/iv8.c b/libavformat/iv8.c index 903de6f8a4..e431c342db 100644 --- a/libavformat/iv8.c +++ b/libavformat/iv8.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2009 Michael Niedermayer * - * 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/libavformat/ivfdec.c b/libavformat/ivfdec.c index ae84a6fd81..1a6e671be5 100644 --- a/libavformat/ivfdec.c +++ b/libavformat/ivfdec.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2010 David Conrad * - * 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/libavformat/ivfenc.c b/libavformat/ivfenc.c index 55ce58615b..5fffaf7959 100644 --- a/libavformat/ivfenc.c +++ b/libavformat/ivfenc.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2010 Reimar Döffinger * - * 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" diff --git a/libavformat/jvdec.c b/libavformat/jvdec.c index 82d96ca071..31cba6f468 100644 --- a/libavformat/jvdec.c +++ b/libavformat/jvdec.c @@ -2,20 +2,20 @@ * Bitmap Brothers JV demuxer * Copyright (c) 2005, 2011 Peter Ross <pross@xvid.org> * - * 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 */ @@ -139,7 +139,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) AVIOContext *pb = s->pb; AVStream *ast = s->streams[0]; - while (!s->pb->eof_reached && jv->pts < ast->nb_index_entries) { + while (!url_feof(s->pb) && jv->pts < ast->nb_index_entries) { const AVIndexEntry *e = ast->index_entries + jv->pts; const JVFrame *jvf = jv->frames + jv->pts; @@ -207,10 +207,11 @@ static int read_seek(AVFormatContext *s, int stream_index, if (i < 0 || i >= ast->nb_index_entries) return 0; + if (avio_seek(s->pb, ast->index_entries[i].pos, SEEK_SET) < 0) + return -1; jv->state = JV_AUDIO; jv->pts = i; - avio_seek(s->pb, ast->index_entries[i].pos, SEEK_SET); return 0; } diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c index 423710ddea..c71f78b78a 100644 --- a/libavformat/latmenc.c +++ b/libavformat/latmenc.c @@ -25,6 +25,7 @@ #include "libavcodec/mpeg4audio.h" #include "libavutil/opt.h" #include "avformat.h" +#include "rawenc.h" typedef struct { AVClass *av_class; @@ -76,6 +77,9 @@ static int latm_write_header(AVFormatContext *s) LATMContext *ctx = s->priv_data; AVCodecContext *avctx = s->streams[0]->codec; + if (avctx->codec_id == CODEC_ID_AAC_LATM) + return 0; + if (avctx->extradata_size > 0 && latm_decode_extradata(ctx, avctx->extradata, avctx->extradata_size) < 0) return AVERROR_INVALIDDATA; @@ -136,6 +140,9 @@ static int latm_write_packet(AVFormatContext *s, AVPacket *pkt) uint8_t loas_header[] = "\x56\xe0\x00"; uint8_t *buf; + if (s->streams[0]->codec->codec_id == CODEC_ID_AAC_LATM) + return ff_raw_write_packet(s, pkt); + if (pkt->size > 2 && pkt->data[0] == 0xff && (pkt->data[1] >> 4) == 0xf) { av_log(s, AV_LOG_ERROR, "ADTS header detected - ADTS will not be incorrectly muxed into LATM\n"); return AVERROR_INVALIDDATA; @@ -181,7 +188,7 @@ AVOutputFormat ff_latm_muxer = { .name = "latm", .long_name = NULL_IF_CONFIG_SMALL("LOAS/LATM"), .mime_type = "audio/MP4A-LATM", - .extensions = "latm", + .extensions = "latm,loas", .priv_data_size = sizeof(LATMContext), .audio_codec = CODEC_ID_AAC, .video_codec = CODEC_ID_NONE, diff --git a/libavformat/libavformat.v b/libavformat/libavformat.v index c5dc982878..6949884af6 100644 --- a/libavformat/libavformat.v +++ b/libavformat/libavformat.v @@ -1,6 +1,6 @@ LIBAVFORMAT_$MAJOR { global: av*; - #FIXME those are for avserver + #FIXME those are for ffserver ff_inet_aton; ff_socket_nonblock; ffm_set_write_index; @@ -10,6 +10,9 @@ LIBAVFORMAT_$MAJOR { ff_rtp_get_local_rtp_port; ff_rtp_get_local_rtcp_port; ffio_open_dyn_packet_buf; + ffurl_close; + ffurl_open; + ffurl_write; url_open; url_close; url_write; @@ -19,6 +22,10 @@ LIBAVFORMAT_$MAJOR { parse_date; dump_format; url_*; + ff_timefilter_destroy; + ff_timefilter_new; + ff_timefilter_update; + ff_timefilter_reset; get_*; put_*; udp_set_remote_url; diff --git a/libavformat/libmodplug.c b/libavformat/libmodplug.c new file mode 100644 index 0000000000..a662dbafbc --- /dev/null +++ b/libavformat/libmodplug.c @@ -0,0 +1,368 @@ +/* + * 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 + */ + +/** +* @file +* ModPlug demuxer +* @todo better probing than extensions matching +*/ + +#include <libmodplug/modplug.h> +#include "libavutil/avstring.h" +#include "libavutil/eval.h" +#include "libavutil/opt.h" +#include "avformat.h" +#include "internal.h" + +typedef struct ModPlugContext { + const AVClass *class; + ModPlugFile *f; + uint8_t *buf; ///< input file content + + /* options */ + int noise_reduction; + int reverb_depth; + int reverb_delay; + int bass_amount; + int bass_range; + int surround_depth; + int surround_delay; + + int max_size; ///< max file size to allocate + + /* optional video stream */ + double ts_per_packet; ///< used to define the pts/dts using packet_count; + int packet_count; ///< total number of audio packets + int print_textinfo; ///< bool flag for printing speed, tempo, order, ... + int video_stream; ///< 1 if the user want a video stream, otherwise 0 + int w; ///< video stream width in char (one char = 8x8px) + int h; ///< video stream height in char (one char = 8x8px) + int video_switch; ///< 1 if current packet is video, otherwise 0 + int fsize; ///< constant frame size + int linesize; ///< line size in bytes + char *color_eval; ///< color eval user input expression + AVExpr *expr; ///< parsed color eval expression +} ModPlugContext; + +static const char *var_names[] = { + "x", "y", + "w", "h", + "t", + "speed", "tempo", "order", "pattern", "row", + NULL +}; + +enum var_name { + VAR_X, VAR_Y, + VAR_W, VAR_H, + VAR_TIME, + VAR_SPEED, VAR_TEMPO, VAR_ORDER, VAR_PATTERN, VAR_ROW, + VAR_VARS_NB +}; + +#define FF_MODPLUG_MAX_FILE_SIZE (100 * 1<<20) // 100M +#define FF_MODPLUG_DEF_FILE_SIZE ( 5 * 1<<20) // 5M + +#define OFFSET(x) offsetof(ModPlugContext, x) +#define D AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + {"noise_reduction", "Enable noise reduction 0(off)-1(on)", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, D}, + {"reverb_depth", "Reverb level 0(quiet)-100(loud)", OFFSET(reverb_depth), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, + {"reverb_delay", "Reverb delay in ms, usually 40-200ms", OFFSET(reverb_delay), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, D}, + {"bass_amount", "XBass level 0(quiet)-100(loud)", OFFSET(bass_amount), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, + {"bass_range", "XBass cutoff in Hz 10-100", OFFSET(bass_range), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, + {"surround_depth", "Surround level 0(quiet)-100(heavy)", OFFSET(surround_depth), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 100, D}, + {"surround_delay", "Surround delay in ms, usually 5-40ms", OFFSET(surround_delay), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, D}, + {"max_size", "Max file size supported (in bytes). Default is 5MB. Set to 0 for no limit (not recommended)", + OFFSET(max_size), AV_OPT_TYPE_INT, {.dbl = FF_MODPLUG_DEF_FILE_SIZE}, 0, FF_MODPLUG_MAX_FILE_SIZE, D}, + {"video_stream_expr", "Color formula", OFFSET(color_eval), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D}, + {"video_stream", "Make demuxer output a video stream", OFFSET(video_stream), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, D}, + {"video_stream_w", "Video stream width in char (one char = 8x8px)", OFFSET(w), AV_OPT_TYPE_INT, {.dbl = 30}, 20, 512, D}, + {"video_stream_h", "Video stream height in char (one char = 8x8px)", OFFSET(h), AV_OPT_TYPE_INT, {.dbl = 30}, 20, 512, D}, + {"video_stream_ptxt", "Print speed, tempo, order, ... in video stream", OFFSET(print_textinfo), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, D}, + {NULL}, +}; + +#define SET_OPT_IF_REQUESTED(libopt, opt, flag) do { \ + if (modplug->opt) { \ + settings.libopt = modplug->opt; \ + settings.mFlags |= flag; \ + } \ +} while (0) + +#define ADD_META_MULTIPLE_ENTRIES(entry_name, fname) do { \ + if (n_## entry_name ##s) { \ + unsigned i, n = 0; \ + \ + for (i = 0; i < n_## entry_name ##s; i++) { \ + char item_name[64] = {0}; \ + fname(f, i, item_name); \ + if (!*item_name) \ + continue; \ + if (n) \ + av_dict_set(&s->metadata, #entry_name, "\n", AV_DICT_APPEND); \ + av_dict_set(&s->metadata, #entry_name, item_name, AV_DICT_APPEND); \ + n++; \ + } \ + \ + extra = av_asprintf(", %u/%u " #entry_name "%s", \ + n, n_## entry_name ##s, n > 1 ? "s" : ""); \ + if (!extra) \ + return AVERROR(ENOMEM); \ + av_dict_set(&s->metadata, "extra info", extra, AV_DICT_APPEND); \ + av_free(extra); \ + } \ +} while (0) + +static int modplug_load_metadata(AVFormatContext *s) +{ + ModPlugContext *modplug = s->priv_data; + ModPlugFile *f = modplug->f; + char *extra; + const char *name = ModPlug_GetName(f); + const char *msg = ModPlug_GetMessage(f); + + unsigned n_instruments = ModPlug_NumInstruments(f); + unsigned n_samples = ModPlug_NumSamples(f); + unsigned n_patterns = ModPlug_NumPatterns(f); + unsigned n_channels = ModPlug_NumChannels(f); + + if (name && *name) av_dict_set(&s->metadata, "name", name, 0); + if (msg && *msg) av_dict_set(&s->metadata, "message", msg, 0); + + extra = av_asprintf("%u pattern%s, %u channel%s", + n_patterns, n_patterns > 1 ? "s" : "", + n_channels, n_channels > 1 ? "s" : ""); + if (!extra) + return AVERROR(ENOMEM); + av_dict_set(&s->metadata, "extra info", extra, AV_DICT_DONT_STRDUP_VAL); + + ADD_META_MULTIPLE_ENTRIES(instrument, ModPlug_InstrumentName); + ADD_META_MULTIPLE_ENTRIES(sample, ModPlug_SampleName); + + return 0; +} + +#define AUDIO_PKT_SIZE 512 + +static int modplug_read_header(AVFormatContext *s) +{ + AVStream *st; + AVIOContext *pb = s->pb; + ModPlug_Settings settings; + ModPlugContext *modplug = s->priv_data; + int 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 " + "but demuxing is likely to fail due to incomplete buffer\n", + sz == FF_MODPLUG_DEF_FILE_SIZE ? " (see -max_size)" : "", sz); + } + + if (modplug->color_eval) { + int r = av_expr_parse(&modplug->expr, modplug->color_eval, var_names, + NULL, NULL, NULL, NULL, 0, s); + if (r < 0) + return r; + } + + modplug->buf = av_malloc(modplug->max_size); + if (!modplug->buf) + return AVERROR(ENOMEM); + sz = avio_read(pb, modplug->buf, sz); + + ModPlug_GetSettings(&settings); + settings.mChannels = 2; + settings.mBits = 16; + settings.mFrequency = 44100; + settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; // best quality + settings.mLoopCount = 0; // prevents looping forever + + if (modplug->noise_reduction) settings.mFlags |= MODPLUG_ENABLE_NOISE_REDUCTION; + SET_OPT_IF_REQUESTED(mReverbDepth, reverb_depth, MODPLUG_ENABLE_REVERB); + SET_OPT_IF_REQUESTED(mReverbDelay, reverb_delay, MODPLUG_ENABLE_REVERB); + SET_OPT_IF_REQUESTED(mBassAmount, bass_amount, MODPLUG_ENABLE_MEGABASS); + SET_OPT_IF_REQUESTED(mBassRange, bass_range, MODPLUG_ENABLE_MEGABASS); + SET_OPT_IF_REQUESTED(mSurroundDepth, surround_depth, MODPLUG_ENABLE_SURROUND); + SET_OPT_IF_REQUESTED(mSurroundDelay, surround_delay, MODPLUG_ENABLE_SURROUND); + + if (modplug->reverb_depth) settings.mReverbDepth = modplug->reverb_depth; + if (modplug->reverb_delay) settings.mReverbDelay = modplug->reverb_delay; + if (modplug->bass_amount) settings.mBassAmount = modplug->bass_amount; + if (modplug->bass_range) settings.mBassRange = modplug->bass_range; + if (modplug->surround_depth) settings.mSurroundDepth = modplug->surround_depth; + if (modplug->surround_delay) settings.mSurroundDelay = modplug->surround_delay; + + ModPlug_SetSettings(&settings); + + modplug->f = ModPlug_Load(modplug->buf, sz); + if (!modplug->f) + return AVERROR_INVALIDDATA; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + avpriv_set_pts_info(st, 64, 1, 1000); + st->duration = ModPlug_GetLength(modplug->f); + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_PCM_S16LE; + st->codec->channels = settings.mChannels; + st->codec->sample_rate = settings.mFrequency; + + // timebase = 1/1000, 2ch 16bits 44.1kHz-> 2*2*44100 + modplug->ts_per_packet = 1000*AUDIO_PKT_SIZE / (4*44100.); + + if (modplug->video_stream) { + AVStream *vst = avformat_new_stream(s, NULL); + if (!vst) + return AVERROR(ENOMEM); + avpriv_set_pts_info(vst, 64, 1, 1000); + vst->duration = st->duration; + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; + vst->codec->codec_id = CODEC_ID_XBIN; + vst->codec->width = modplug->w << 3; + vst->codec->height = modplug->h << 3; + modplug->linesize = modplug->w * 3; + modplug->fsize = modplug->linesize * modplug->h; + } + + return modplug_load_metadata(s); +} + +static void write_text(uint8_t *dst, const char *s, int linesize, int x, int y) +{ + int i; + dst += y*linesize + x*3; + for (i = 0; s[i]; i++, dst += 3) { + dst[0] = 0x0; // count - 1 + dst[1] = s[i]; // char + dst[2] = 0x0f; // background / foreground + } +} + +#define PRINT_INFO(line, name, idvalue) do { \ + snprintf(intbuf, sizeof(intbuf), "%.0f", var_values[idvalue]); \ + write_text(pkt->data, name ":", modplug->linesize, 0+1, line+1); \ + write_text(pkt->data, intbuf, modplug->linesize, 10+1, line+1); \ +} while (0) + +static int modplug_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + ModPlugContext *modplug = s->priv_data; + + if (modplug->video_stream) { + modplug->video_switch ^= 1; // one video packet for one audio packet + if (modplug->video_switch) { + double var_values[VAR_VARS_NB]; + + var_values[VAR_W ] = modplug->w; + var_values[VAR_H ] = modplug->h; + var_values[VAR_TIME ] = modplug->packet_count * modplug->ts_per_packet; + var_values[VAR_SPEED ] = ModPlug_GetCurrentSpeed (modplug->f); + var_values[VAR_TEMPO ] = ModPlug_GetCurrentTempo (modplug->f); + var_values[VAR_ORDER ] = ModPlug_GetCurrentOrder (modplug->f); + var_values[VAR_PATTERN] = ModPlug_GetCurrentPattern(modplug->f); + var_values[VAR_ROW ] = ModPlug_GetCurrentRow (modplug->f); + + if (av_new_packet(pkt, modplug->fsize) < 0) + return AVERROR(ENOMEM); + pkt->stream_index = 1; + memset(pkt->data, 0, modplug->fsize); + + if (modplug->print_textinfo) { + char intbuf[32]; + PRINT_INFO(0, "speed", VAR_SPEED); + PRINT_INFO(1, "tempo", VAR_TEMPO); + PRINT_INFO(2, "order", VAR_ORDER); + PRINT_INFO(3, "pattern", VAR_PATTERN); + PRINT_INFO(4, "row", VAR_ROW); + PRINT_INFO(5, "ts", VAR_TIME); + } + + if (modplug->expr) { + int x, y; + for (y = 0; y < modplug->h; y++) { + for (x = 0; x < modplug->w; x++) { + double color; + var_values[VAR_X] = x; + var_values[VAR_Y] = y; + color = av_expr_eval(modplug->expr, var_values, NULL); + pkt->data[y*modplug->linesize + x*3 + 2] |= av_clip((int)color, 0, 0xf)<<4; + } + } + } + pkt->pts = pkt->dts = var_values[VAR_TIME]; + pkt->flags |= AV_PKT_FLAG_KEY; + return 0; + } + } + + if (av_new_packet(pkt, AUDIO_PKT_SIZE) < 0) + return AVERROR(ENOMEM); + + if (modplug->video_stream) + pkt->pts = pkt->dts = modplug->packet_count++ * modplug->ts_per_packet; + + pkt->size = ModPlug_Read(modplug->f, pkt->data, AUDIO_PKT_SIZE); + if (pkt->size <= 0) { + av_free_packet(pkt); + return pkt->size == 0 ? AVERROR_EOF : AVERROR(EIO); + } + return 0; +} + +static int modplug_read_close(AVFormatContext *s) +{ + ModPlugContext *modplug = s->priv_data; + ModPlug_Unload(modplug->f); + av_freep(&modplug->buf); + return 0; +} + +static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags) +{ + ModPlugContext *modplug = s->priv_data; + ModPlug_Seek(modplug->f, (int)ts); + if (modplug->video_stream) + modplug->packet_count = ts / modplug->ts_per_packet; + return 0; +} + +static const AVClass modplug_class = { + .class_name = "ModPlug demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_libmodplug_demuxer = { + .name = "libmodplug", + .long_name = NULL_IF_CONFIG_SMALL("ModPlug demuxer"), + .priv_data_size = sizeof(ModPlugContext), + .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 + .priv_class = &modplug_class, +}; diff --git a/libavformat/libnut.c b/libavformat/libnut.c index 3bb355852e..c6d552db59 100644 --- a/libavformat/libnut.c +++ b/libavformat/libnut.c @@ -2,20 +2,20 @@ * NUT (de)muxing via libnut * copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org> * - * 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,6 +71,8 @@ static int nut_write_header(AVFormatContext * avf) { int i; priv->s = s = av_mallocz((avf->nb_streams + 1) * sizeof*s); + if(!s) + return AVERROR(ENOMEM); for (i = 0; i < avf->nb_streams; i++) { AVCodecContext * codec = avf->streams[i]->codec; @@ -205,9 +207,13 @@ static int nut_read_header(AVFormatContext * avf) { nut_stream_header_tt * s; int ret, i; + if(!nut) + return -1; + if ((ret = nut_read_headers(nut, &s, NULL))) { av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret)); nut_demuxer_uninit(nut); + priv->nut = NULL; return -1; } @@ -224,6 +230,11 @@ static int nut_read_header(AVFormatContext * avf) { 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){ + nut_demuxer_uninit(nut); + priv->nut = NULL; + return AVERROR(ENOMEM); + } memcpy(st->codec->extradata, s[i].codec_specific, st->codec->extradata_size); } diff --git a/libavformat/librtmp.c b/libavformat/librtmp.c index 2d028b05e2..e433860823 100644 --- a/libavformat/librtmp.c +++ b/libavformat/librtmp.c @@ -2,20 +2,20 @@ * RTMP network protocol * Copyright (c) 2010 Howard Chu * - * 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/libavformat/lmlm4.c b/libavformat/lmlm4.c index 8daf7b45c4..24ae289cbe 100644 --- a/libavformat/lmlm4.c +++ b/libavformat/lmlm4.c @@ -5,20 +5,20 @@ * Due to a lack of sample files, only files with one channel are supported. * u-law and ADPCM audio are unsupported for the same reason. * - * 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/libavformat/loasdec.c b/libavformat/loasdec.c new file mode 100644 index 0000000000..5c8a8be573 --- /dev/null +++ b/libavformat/loasdec.c @@ -0,0 +1,88 @@ +/* + * LOAS AudioSyncStream demuxer + * Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at> + * + * 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/intreadwrite.h" +#include "libavutil/internal.h" +#include "avformat.h" +#include "internal.h" +#include "rawdec.h" + +static int loas_probe(AVProbeData *p) +{ + int max_frames = 0, first_frames = 0; + int fsize, frames; + uint8_t *buf0 = p->buf; + uint8_t *buf2; + uint8_t *buf; + uint8_t *end = buf0 + p->buf_size - 3; + buf = buf0; + + for(; buf < end; buf= buf2+1) { + buf2 = buf; + + for(frames = 0; buf2 < end; frames++) { + uint32_t header = AV_RB24(buf2); + if((header >> 13) != 0x2B7) + break; + fsize = (header & 0x1FFF) + 3; + if(fsize < 7) + break; + fsize = FFMIN(fsize, end - buf2); + buf2 += fsize; + } + max_frames = FFMAX(max_frames, frames); + 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; + else if(max_frames>=1) return 1; + else return 0; +} + +static int loas_read_header(AVFormatContext *s) +{ + AVStream *st; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = s->iformat->value; + st->need_parsing = AVSTREAM_PARSE_FULL; + + //LCM of all possible AAC sample rates + avpriv_set_pts_info(st, 64, 1, 28224000); + + return 0; +} + +AVInputFormat ff_loas_demuxer = { + .name = "loas", + .long_name = NULL_IF_CONFIG_SMALL("LOAS AudioSyncStream"), + .read_probe = loas_probe, + .read_header = loas_read_header, + .read_packet = ff_raw_read_partial_packet, + .flags= AVFMT_GENERIC_INDEX, + .value = CODEC_ID_AAC_LATM, +}; diff --git a/libavformat/lxfdec.c b/libavformat/lxfdec.c index ee12dfbb98..6969b144ab 100644 --- a/libavformat/lxfdec.c +++ b/libavformat/lxfdec.c @@ -2,20 +2,20 @@ * LXF demuxer * Copyright (c) 2010 Tomas Härdin * - * 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 */ @@ -91,7 +91,7 @@ static int sync(AVFormatContext *s, uint8_t *header) return ret < 0 ? ret : AVERROR_EOF; while (memcmp(buf, LXF_IDENT, LXF_IDENT_LENGTH)) { - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR_EOF; memmove(buf, &buf[1], LXF_IDENT_LENGTH-1); diff --git a/libavformat/m4vdec.c b/libavformat/m4vdec.c index e856aadc10..88f838022e 100644 --- a/libavformat/m4vdec.c +++ b/libavformat/m4vdec.c @@ -2,20 +2,20 @@ * RAW MPEG-4 video demuxer * Copyright (c) 2006 Thijs Vermeir <thijs.vermeir@barco.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 */ @@ -45,7 +45,7 @@ static int mpeg4video_probe(AVProbeData *probe_packet) } if (VOP >= VISO && VOP >= VOL && VO >= VOL && VOL > 0 && res==0) - return AVPROBE_SCORE_MAX/2; + return VOP+VO > 3 ? AVPROBE_SCORE_MAX/2 : AVPROBE_SCORE_MAX/4; return 0; } diff --git a/libavformat/matroska.c b/libavformat/matroska.c index b448af21aa..52481d7556 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -2,20 +2,20 @@ * Matroska common data * Copyright (c) 2003-2004 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 */ @@ -99,3 +99,27 @@ const AVMetadataConv ff_mkv_metadata_conv[] = { { "PART_NUMBER" , "track" }, { 0 } }; + +const char * const matroska_video_stereo_mode[MATROSKA_VIDEO_STEREO_MODE_COUNT] = { + "mono", + "left_right", + "bottom_top", + "top_bottom", + "checkerboard_rl", + "checkerboard_lr" + "row_interleaved_rl", + "row_interleaved_lr", + "col_interleaved_rl", + "col_interleaved_lr", + "anaglyph_cyan_red", + "right_left", + "anaglyph_green_magenta", + "block_lr", + "block_rl", +}; + +const char * const matroska_video_stereo_plane[MATROSKA_VIDEO_STEREO_PLANE_COUNT] = { + "left", + "right", + "background", +}; diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 8e747e6a9c..ab7e3269fa 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -2,20 +2,20 @@ * Matroska constants * Copyright (c) 2003-2004 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 */ @@ -77,8 +77,13 @@ #define MATROSKA_ID_TRACKNUMBER 0xD7 #define MATROSKA_ID_TRACKUID 0x73C5 #define MATROSKA_ID_TRACKTYPE 0x83 -#define MATROSKA_ID_TRACKAUDIO 0xE1 -#define MATROSKA_ID_TRACKVIDEO 0xE0 +#define MATROSKA_ID_TRACKVIDEO 0xE0 +#define MATROSKA_ID_TRACKAUDIO 0xE1 +#define MATROSKA_ID_TRACKOPERATION 0xE2 +#define MATROSKA_ID_TRACKCOMBINEPLANES 0xE3 +#define MATROSKA_ID_TRACKPLANE 0xE4 +#define MATROSKA_ID_TRACKPLANEUID 0xE5 +#define MATROSKA_ID_TRACKPLANETYPE 0xE6 #define MATROSKA_ID_CODECID 0x86 #define MATROSKA_ID_CODECPRIVATE 0x63A2 #define MATROSKA_ID_CODECNAME 0x258688 @@ -253,8 +258,13 @@ typedef struct CodecMime{ /* max. depth in the EBML tree structure */ #define EBML_MAX_DEPTH 16 +#define MATROSKA_VIDEO_STEREO_MODE_COUNT 15 +#define MATROSKA_VIDEO_STEREO_PLANE_COUNT 3 + extern const CodecTags ff_mkv_codec_tags[]; extern const CodecMime ff_mkv_mime_tags[]; extern const AVMetadataConv ff_mkv_metadata_conv[]; +extern const char * const matroska_video_stereo_mode[MATROSKA_VIDEO_STEREO_MODE_COUNT]; +extern const char * const matroska_video_stereo_plane[MATROSKA_VIDEO_STEREO_PLANE_COUNT]; #endif /* AVFORMAT_MATROSKA_H */ diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 8f34289eb5..df54762c5e 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1,21 +1,21 @@ /* * Matroska file demuxer - * Copyright (c) 2003-2008 The Libav Project + * Copyright (c) 2003-2008 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 */ @@ -112,7 +112,8 @@ typedef struct { uint64_t display_height; uint64_t pixel_width; uint64_t pixel_height; - uint64_t fourcc; + EbmlBin color_space; + uint64_t stereo_mode; } MatroskaTrackVideo; typedef struct { @@ -133,6 +134,15 @@ typedef struct { } MatroskaTrackAudio; typedef struct { + uint64_t uid; + uint64_t type; +} MatroskaTrackPlane; + +typedef struct { + EbmlList combine_planes; +} MatroskaTrackOperation; + +typedef struct { uint64_t num; uint64_t uid; uint64_t type; @@ -146,6 +156,7 @@ typedef struct { uint64_t flag_forced; MatroskaTrackVideo video; MatroskaTrackAudio audio; + MatroskaTrackOperation operation; EbmlList encodings; AVStream *stream; @@ -294,14 +305,14 @@ static EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,display_height) }, { MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_width) }, { MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo,pixel_height) }, - { MATROSKA_ID_VIDEOCOLORSPACE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,fourcc) }, + { MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo,color_space) }, + { MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo,stereo_mode) }, { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE }, { MATROSKA_ID_VIDEODISPLAYUNIT, EBML_NONE }, { MATROSKA_ID_VIDEOFLAGINTERLACED,EBML_NONE }, - { MATROSKA_ID_VIDEOSTEREOMODE, EBML_NONE }, { MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE }, { 0 } }; @@ -333,6 +344,22 @@ static EbmlSyntax matroska_track_encodings[] = { { 0 } }; +static EbmlSyntax matroska_track_plane[] = { + { MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) }, + { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) }, + { 0 } +}; + +static EbmlSyntax matroska_track_combine_planes[] = { + { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n=matroska_track_plane} }, + { 0 } +}; + +static EbmlSyntax matroska_track_operation[] = { + { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n=matroska_track_combine_planes} }, + { 0 } +}; + static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack,num) }, { MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack,name) }, @@ -347,6 +374,7 @@ static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, offsetof(MatroskaTrack,flag_forced), {.u=0} }, { MATROSKA_ID_TRACKVIDEO, EBML_NEST, 0, offsetof(MatroskaTrack,video), {.n=matroska_track_video} }, { MATROSKA_ID_TRACKAUDIO, EBML_NEST, 0, offsetof(MatroskaTrack,audio), {.n=matroska_track_audio} }, + { 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_TRACKFLAGENABLED, EBML_NONE }, { MATROSKA_ID_TRACKFLAGLACING, EBML_NONE }, @@ -490,7 +518,7 @@ static EbmlSyntax matroska_segments[] = { static EbmlSyntax matroska_blockgroup[] = { { MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) }, { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock,bin) }, - { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration), {.u=AV_NOPTS_VALUE} }, + { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock,duration) }, { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) }, { 1, EBML_UINT, 0, offsetof(MatroskaBlock,non_simple), {.u=1} }, { 0 } @@ -553,7 +581,7 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, AVIOContext *pb, * use it safely here to catch EOS. */ if (!(total = avio_r8(pb))) { /* we might encounter EOS here */ - if (!pb->eof_reached) { + if (!url_feof(pb)) { int64_t pos = avio_tell(pb); av_log(matroska->ctx, AV_LOG_ERROR, "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", @@ -977,7 +1005,10 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, pkt_data = newpktdata; zstream.avail_out = pkt_size - zstream.total_out; zstream.next_out = pkt_data + zstream.total_out; - result = inflate(&zstream, Z_NO_FLUSH); + if (pkt_data) { + result = inflate(&zstream, Z_NO_FLUSH); + } else + result = Z_MEM_ERROR; } while (result==Z_OK && pkt_size<10000000); pkt_size = zstream.total_out; inflateEnd(&zstream); @@ -1003,7 +1034,10 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size, pkt_data = newpktdata; bzstream.avail_out = pkt_size - bzstream.total_out_lo32; bzstream.next_out = pkt_data + bzstream.total_out_lo32; - result = BZ2_bzDecompress(&bzstream); + if (pkt_data) { + result = BZ2_bzDecompress(&bzstream); + } else + result = BZ_MEM_ERROR; } while (result==BZ_OK && pkt_size<10000000); pkt_size = bzstream.total_out_lo32; BZ2_bzDecompressEnd(&bzstream); @@ -1030,7 +1064,8 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska, char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size; for (; *ptr!=',' && ptr<end-1; ptr++); if (*ptr == ',') - layer = ++ptr; + ptr++; + layer = ptr; for (; *ptr!=',' && ptr<end-1; ptr++); if (*ptr == ',') { int64_t end_pts = pkt->pts + display_duration; @@ -1212,21 +1247,12 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) } } -static void matroska_parse_cues(MatroskaDemuxContext *matroska) { - EbmlList *seekhead_list = &matroska->seekhead; - MatroskaSeekhead *seekhead = seekhead_list->elem; +static void matroska_add_index_entries(MatroskaDemuxContext *matroska) { EbmlList *index_list; MatroskaIndex *index; int index_scale = 1; int i, j; - for (i = 0; i < seekhead_list->nb_elem; i++) - if (seekhead[i].id == MATROSKA_ID_CUES) - break; - assert(i <= seekhead_list->nb_elem); - - matroska_parse_seekhead_entry(matroska, i); - index_list = &matroska->index; index = index_list->elem; if (index_list->nb_elem @@ -1248,6 +1274,20 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska) { } } +static void matroska_parse_cues(MatroskaDemuxContext *matroska) { + EbmlList *seekhead_list = &matroska->seekhead; + MatroskaSeekhead *seekhead = seekhead_list->elem; + int i; + + for (i = 0; i < seekhead_list->nb_elem; i++) + if (seekhead[i].id == MATROSKA_ID_CUES) + break; + assert(i <= seekhead_list->nb_elem); + + matroska_parse_seekhead_entry(matroska, i); + matroska_add_index_entries(matroska); +} + static int matroska_aac_profile(char *codec_id) { static const char * const aac_profiles[] = { "MAIN", "LC", "SSR" }; @@ -1280,20 +1320,25 @@ static int matroska_read_header(AVFormatContext *s) uint64_t max_start = 0; Ebml ebml = { 0 }; AVStream *st; - int i, j, res; + int i, j, k, res; matroska->ctx = s; /* First read the EBML header. */ if (ebml_parse(matroska, ebml_syntax, &ebml) || ebml.version > EBML_VERSION || ebml.max_size > sizeof(uint64_t) - || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 2) { + || ebml.id_length > sizeof(uint32_t) || ebml.doctype_version > 3) { av_log(matroska->ctx, AV_LOG_ERROR, "EBML header using unsupported features\n" "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n", ebml.version, ebml.doctype, ebml.doctype_version); ebml_free(ebml_syntax, &ebml); return AVERROR_PATCHWELCOME; + } else if (ebml.doctype_version == 3) { + av_log(matroska->ctx, AV_LOG_WARNING, + "EBML header using unsupported features\n" + "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n", + ebml.version, ebml.doctype, ebml.doctype_version); } for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++) if (!strcmp(ebml.doctype, matroska_doctypes[i])) @@ -1319,11 +1364,12 @@ static int matroska_read_header(AVFormatContext *s) for (i=0; i < matroska->tracks.nb_elem; i++) { MatroskaTrack *track = &tracks[i]; enum CodecID codec_id = CODEC_ID_NONE; - EbmlList *encodings_list = &tracks->encodings; + EbmlList *encodings_list = &track->encodings; MatroskaTrackEncoding *encodings = encodings_list->elem; uint8_t *extradata = NULL; int extradata_size = 0; int extradata_offset = 0; + uint32_t fourcc = 0; AVIOContext b; /* Apply some sanity checks. */ @@ -1345,6 +1391,8 @@ static int matroska_read_header(AVFormatContext *s) track->video.display_width = track->video.pixel_width; if (!track->video.display_height) track->video.display_height = track->video.pixel_height; + if (track->video.color_space.size == 4) + fourcc = AV_RL32(track->video.color_space.data); } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { if (!track->audio.out_samplerate) track->audio.out_samplerate = track->audio.samplerate; @@ -1404,8 +1452,8 @@ static int matroska_read_header(AVFormatContext *s) && track->codec_priv.size >= 40 && track->codec_priv.data != NULL) { track->ms_compat = 1; - track->video.fourcc = AV_RL32(track->codec_priv.data + 16); - codec_id = ff_codec_get_id(ff_codec_bmp_tags, track->video.fourcc); + fourcc = AV_RL32(track->codec_priv.data + 16); + codec_id = ff_codec_get_id(ff_codec_bmp_tags, fourcc); extradata_offset = 40; } else if (!strcmp(track->codec_id, "A_MS/ACM") && track->codec_priv.size >= 14 @@ -1421,8 +1469,8 @@ static int matroska_read_header(AVFormatContext *s) } else if (!strcmp(track->codec_id, "V_QUICKTIME") && (track->codec_priv.size >= 86) && (track->codec_priv.data != NULL)) { - track->video.fourcc = AV_RL32(track->codec_priv.data); - codec_id=ff_codec_get_id(codec_movvideo_tags, track->video.fourcc); + fourcc = AV_RL32(track->codec_priv.data); + codec_id = ff_codec_get_id(codec_movvideo_tags, fourcc); } else if (codec_id == CODEC_ID_PCM_S16BE) { switch (track->audio.bitdepth) { case 8: codec_id = CODEC_ID_PCM_U8; break; @@ -1455,7 +1503,7 @@ static int matroska_read_header(AVFormatContext *s) extradata_size = 2; } else if (codec_id == CODEC_ID_TTA) { extradata_size = 30; - extradata = av_mallocz(extradata_size); + extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (extradata == NULL) return AVERROR(ENOMEM); ffio_init_context(&b, extradata, extradata_size, 1, @@ -1536,8 +1584,10 @@ static int matroska_read_header(AVFormatContext *s) } if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { + MatroskaTrackPlane *planes = track->operation.combine_planes.elem; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_tag = track->video.fourcc; + st->codec->codec_tag = fourcc; st->codec->width = track->video.pixel_width; st->codec->height = track->video.pixel_height; av_reduce(&st->sample_aspect_ratio.num, @@ -1549,6 +1599,25 @@ static int matroska_read_header(AVFormatContext *s) st->need_parsing = AVSTREAM_PARSE_HEADERS; if (track->default_duration) st->avg_frame_rate = av_d2q(1000000000.0/track->default_duration, INT_MAX); + + /* export stereo mode flag as metadata tag */ + if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREO_MODE_COUNT) + av_dict_set(&st->metadata, "stereo_mode", matroska_video_stereo_mode[track->video.stereo_mode], 0); + + /* if we have virtual track, mark the real tracks */ + for (j=0; j < track->operation.combine_planes.nb_elem; j++) { + char buf[32]; + if (planes[j].type >= MATROSKA_VIDEO_STEREO_PLANE_COUNT) + continue; + snprintf(buf, sizeof(buf), "%s_%d", + matroska_video_stereo_plane[planes[j].type], i); + for (k=0; k < matroska->tracks.nb_elem; k++) + if (planes[j].uid == tracks[k].uid) { + av_dict_set(&s->streams[k]->metadata, + "stereo_mode", buf, 0); + break; + } + } } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->sample_rate = track->audio.out_samplerate; @@ -1573,7 +1642,7 @@ static int matroska_read_header(AVFormatContext *s) av_dict_set(&st->metadata, "mimetype", attachements[j].mime, 0); st->codec->codec_id = CODEC_ID_NONE; st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; - st->codec->extradata = av_malloc(attachements[j].bin.size); + st->codec->extradata = av_malloc(attachements[j].bin.size + FF_INPUT_BUFFER_PADDING_SIZE); if(st->codec->extradata == NULL) break; st->codec->extradata_size = attachements[j].bin.size; @@ -1603,6 +1672,8 @@ static int matroska_read_header(AVFormatContext *s) max_start = chapters[i].start; } + matroska_add_index_entries(matroska); + matroska_convert_tags(s); return 0; @@ -1678,13 +1749,13 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (!track || !track->stream) { av_log(matroska->ctx, AV_LOG_INFO, "Invalid stream %"PRIu64" or size %u\n", num, size); - return AVERROR_INVALIDDATA; + return res; } else if (size <= 3) return 0; st = track->stream; if (st->discard >= AVDISCARD_ALL) return res; - if (duration == AV_NOPTS_VALUE) + if (!duration) duration = track->default_duration / matroska->time_scale; block_time = AV_RB16(data); @@ -1916,11 +1987,9 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) res = ebml_parse(matroska, matroska_clusters, &cluster); blocks_list = &cluster.blocks; blocks = blocks_list->elem; - for (i=0; i<blocks_list->nb_elem && !res; i++) + for (i=0; i<blocks_list->nb_elem; i++) if (blocks[i].bin.size > 0 && blocks[i].bin.data) { int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; - if (!blocks[i].non_simple) - blocks[i].duration = AV_NOPTS_VALUE; res=matroska_parse_block(matroska, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, @@ -1935,15 +2004,14 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) { MatroskaDemuxContext *matroska = s->priv_data; - int ret = 0; - while (!ret && matroska_deliver_packet(matroska, pkt)) { + while (matroska_deliver_packet(matroska, pkt)) { if (matroska->done) return AVERROR_EOF; - ret = matroska_parse_cluster(matroska); + matroska_parse_cluster(matroska); } - return ret; + return 0; } static int matroska_read_seek(AVFormatContext *s, int stream_index, diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index e93dd65dff..e74366fe95 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -2,20 +2,20 @@ * Matroska muxer * Copyright (c) 2007 David Conrad * - * 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 */ @@ -580,7 +580,10 @@ static int mkv_write_tracks(AVFormatContext *s) switch (codec->codec_type) { case AVMEDIA_TYPE_VIDEO: put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_VIDEO); - put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, av_q2d(codec->time_base)*1E9); + if(st->avg_frame_rate.num && st->avg_frame_rate.den && 1.0/av_q2d(st->avg_frame_rate) > av_q2d(codec->time_base)) + put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, 1E9/av_q2d(st->avg_frame_rate)); + else + put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, av_q2d(codec->time_base)*1E9); if (!native_id && ff_codec_get_tag(codec_movvideo_tags, codec->codec_id) && @@ -602,31 +605,38 @@ static int mkv_write_tracks(AVFormatContext *s) // XXX: interlace flag? put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width); put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELHEIGHT, codec->height); - if ((tag = av_dict_get(s->metadata, "stereo_mode", NULL, 0))) { - uint8_t stereo_fmt = atoi(tag->value); - int valid_fmt = 0; - - switch (mkv->mode) { - case MODE_WEBM: - if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM - || stereo_fmt == MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT) - valid_fmt = 1; - break; - case MODE_MATROSKAv2: - if (stereo_fmt <= MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_RL) - valid_fmt = 1; - break; - } - - if (valid_fmt) - put_ebml_uint (pb, MATROSKA_ID_VIDEOSTEREOMODE, stereo_fmt); + + if ((tag = av_dict_get(st->metadata, "stereo_mode", NULL, 0)) || + (tag = av_dict_get( s->metadata, "stereo_mode", NULL, 0))) { + // save stereo mode flag + uint64_t st_mode = MATROSKA_VIDEO_STEREO_MODE_COUNT; + + for (j=0; j<MATROSKA_VIDEO_STEREO_MODE_COUNT; j++) + if (!strcmp(tag->value, matroska_video_stereo_mode[j])){ + st_mode = j; + break; + } + + if ((mkv->mode == MODE_WEBM && st_mode > 3 && st_mode != 11) + || st_mode >= MATROSKA_VIDEO_STEREO_MODE_COUNT) { + av_log(s, AV_LOG_ERROR, + "The specified stereo mode is not valid.\n"); + return AVERROR(EINVAL); + } else + put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, st_mode); } + if (st->sample_aspect_ratio.num) { int d_width = codec->width*av_q2d(st->sample_aspect_ratio); put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width); put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height); put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, 3); } + + if (codec->codec_id == CODEC_ID_RAWVIDEO) { + uint32_t color_space = av_le2ne32(codec->codec_tag); + put_ebml_binary(pb, MATROSKA_ID_VIDEOCOLORSPACE, &color_space, sizeof(color_space)); + } end_ebml_master(pb, subinfo); break; @@ -766,7 +776,7 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme end_ebml_master(s->pb, targets); while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) - if (av_strcasecmp(t->key, "title")) + if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode")) mkv_write_simpletag(s->pb, t); end_ebml_master(s->pb, tag); @@ -1306,7 +1316,6 @@ AVOutputFormat ff_matroska_muxer = { .write_packet = mkv_write_packet, .write_trailer = mkv_write_trailer, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, - .codec_tag = (const AVCodecTag* const []){ff_codec_bmp_tags, ff_codec_wav_tags, 0}, .subtitle_codec = CODEC_ID_SSA, .query_codec = mkv_query_codec, }; @@ -1324,7 +1333,7 @@ AVOutputFormat ff_webm_muxer = { .write_header = mkv_write_header, .write_packet = mkv_write_packet, .write_trailer = mkv_write_trailer, - .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, + .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, }; #endif @@ -1345,6 +1354,5 @@ AVOutputFormat ff_matroska_audio_muxer = { .write_packet = mkv_write_packet, .write_trailer = mkv_write_trailer, .flags = AVFMT_GLOBALHEADER, - .codec_tag = (const AVCodecTag* const []){ff_codec_wav_tags, 0}, }; #endif diff --git a/libavformat/md5enc.c b/libavformat/md5enc.c index 4509c18e84..052061f039 100644 --- a/libavformat/md5enc.c +++ b/libavformat/md5enc.c @@ -2,20 +2,20 @@ * MD5 encoder (for codec/format testing) * Copyright (c) 2009 Reimar Döffinger, based on crcenc (c) 2002 Fabrice Bellard * - * 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 */ @@ -68,7 +68,6 @@ static int write_trailer(struct AVFormatContext *s) AVOutputFormat ff_md5_muxer = { .name = "md5", .long_name = NULL_IF_CONFIG_SMALL("MD5 testing format"), - .extensions = "", .priv_data_size = PRIVSIZE, .audio_codec = CODEC_ID_PCM_S16LE, .video_codec = CODEC_ID_RAWVIDEO, @@ -98,7 +97,6 @@ static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt) AVOutputFormat ff_framemd5_muxer = { .name = "framemd5", .long_name = NULL_IF_CONFIG_SMALL("Per-frame MD5 testing format"), - .extensions = "", .priv_data_size = PRIVSIZE, .audio_codec = CODEC_ID_PCM_S16LE, .video_codec = CODEC_ID_RAWVIDEO, diff --git a/libavformat/md5proto.c b/libavformat/md5proto.c index 796b4ea682..f7c8b78fee 100644 --- a/libavformat/md5proto.c +++ b/libavformat/md5proto.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2010 Mans Rullgard * - * 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/libavformat/metadata-example.c b/libavformat/metadata-example.c deleted file mode 100644 index 7bf77e7378..0000000000 --- a/libavformat/metadata-example.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2011 Reinhard Tartler - * - * 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. - */ - -/** - * @file - * @example libavformat/metadata-example.c - * Shows how the metadata API can be used in application programs. - */ - -#include <stdio.h> - -#include <libavformat/avformat.h> -#include <libavutil/dict.h> - -int main (int argc, char **argv) -{ - AVFormatContext *fmt_ctx = NULL; - AVDictionaryEntry *tag = NULL; - int ret; - - if (argc != 2) { - printf("usage: %s <input_file>\n" - "example program to demonstrate the use of the libavformat metadata API.\n" - "\n", argv[0]); - return 1; - } - - av_register_all(); - if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL))) - return ret; - - while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) - printf("%s=%s\n", tag->key, tag->value); - - avformat_free_context(fmt_ctx); - return 0; -} diff --git a/libavformat/metadata.c b/libavformat/metadata.c index 7f28314698..1660a604f1 100644 --- a/libavformat/metadata.c +++ b/libavformat/metadata.c @@ -1,20 +1,20 @@ /* * copyright (c) 2009 Michael Niedermayer * - * 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/libavformat/metadata.h b/libavformat/metadata.h index eee3ee4391..6586094e82 100644 --- a/libavformat/metadata.h +++ b/libavformat/metadata.h @@ -1,20 +1,20 @@ /* * copyright (c) 2009 Michael Niedermayer * - * 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/libavformat/microdvddec.c b/libavformat/microdvddec.c new file mode 100644 index 0000000000..b1b784c883 --- /dev/null +++ b/libavformat/microdvddec.c @@ -0,0 +1,129 @@ +/* + * MicroDVD subtitle demuxer + * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.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 "avformat.h" +#include "internal.h" +#include "libavutil/intreadwrite.h" + +#define MAX_LINESIZE 2048 + + +typedef struct { + uint8_t lines[3][MAX_LINESIZE]; + int64_t pos[3]; +} MicroDVDContext; + + +static int microdvd_probe(AVProbeData *p) +{ + unsigned char c, *ptr = p->buf; + int i; + + if (AV_RB24(ptr) == 0xEFBBBF) + ptr += 3; /* skip UTF-8 BOM */ + + for (i=0; i<3; i++) { + if (sscanf(ptr, "{%*d}{}%c", &c) != 1 && + sscanf(ptr, "{%*d}{%*d}%c", &c) != 1 && + sscanf(ptr, "{DEFAULT}{}%c", &c) != 1) + return 0; + ptr += strcspn(ptr, "\n") + 1; + } + return AVPROBE_SCORE_MAX; +} + +static int microdvd_read_header(AVFormatContext *s) +{ + AVRational pts_info = (AVRational){ 2997, 125 }; /* default: 23.976 fps */ + MicroDVDContext *microdvd = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + int i, frame; + double fps; + char c; + + if (!st) + return -1; + for (i=0; i<FF_ARRAY_ELEMS(microdvd->lines); i++) { + microdvd->pos[i] = avio_tell(s->pb); + ff_get_line(s->pb, microdvd->lines[i], sizeof(microdvd->lines[i])); + if ((sscanf(microdvd->lines[i], "{%d}{}%6lf", &frame, &fps) == 2 || + sscanf(microdvd->lines[i], "{%d}{%*d}%6lf", &frame, &fps) == 2) + && frame <= 1 && fps > 3 && fps < 100) + pts_info = av_d2q(fps, 100000); + if (sscanf(microdvd->lines[i], "{DEFAULT}{}%c", &c) == 1) { + st->codec->extradata = av_strdup(microdvd->lines[i] + 11); + st->codec->extradata_size = strlen(st->codec->extradata); + i--; + } + } + avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); + st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codec->codec_id = CODEC_ID_MICRODVD; + return 0; +} + +static int64_t get_pts(const char *buf) +{ + int frame; + char c; + + if (sscanf(buf, "{%d}{%c", &frame, &c) == 2) + return frame; + return AV_NOPTS_VALUE; +} + +static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + MicroDVDContext *microdvd = s->priv_data; + char buffer[MAX_LINESIZE]; + int64_t pos = avio_tell(s->pb); + int i, len = 0, res = AVERROR_EOF; + + for (i=0; i<FF_ARRAY_ELEMS(microdvd->lines); i++) { + if (microdvd->lines[i][0]) { + strcpy(buffer, microdvd->lines[i]); + pos = microdvd->pos[i]; + len = strlen(buffer); + microdvd->lines[i][0] = 0; + break; + } + } + if (!len) + len = ff_get_line(s->pb, buffer, sizeof(buffer)); + + if (buffer[0] && !(res = av_new_packet(pkt, len))) { + memcpy(pkt->data, buffer, len); + pkt->flags |= AV_PKT_FLAG_KEY; + pkt->pos = pos; + pkt->pts = pkt->dts = get_pts(buffer); + } + return res; +} + +AVInputFormat ff_microdvd_demuxer = { + .name = "microdvd", + .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"), + .priv_data_size = sizeof(MicroDVDContext), + .read_probe = microdvd_probe, + .read_header = microdvd_read_header, + .read_packet = microdvd_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/libavformat/microdvdenc.c b/libavformat/microdvdenc.c new file mode 100644 index 0000000000..b2abc547e6 --- /dev/null +++ b/libavformat/microdvdenc.c @@ -0,0 +1,51 @@ +/* + * MicroDVD subtitle muxer + * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.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 "avformat.h" +#include "rawenc.h" + +static int microdvd_write_header(struct AVFormatContext *s) +{ + AVCodecContext *avctx = s->streams[0]->codec; + + if (s->nb_streams != 1 || avctx->codec_id != CODEC_ID_MICRODVD) { + av_log(s, AV_LOG_ERROR, "Exactly one MicroDVD stream is needed.\n"); + return -1; + } + + if (avctx->extradata && avctx->extradata_size > 0) { + avio_write(s->pb, "{DEFAULT}{}", 11); + avio_write(s->pb, avctx->extradata, avctx->extradata_size); + avio_flush(s->pb); + } + return 0; +} + +AVOutputFormat ff_microdvd_muxer = { + .name = "microdvd", + .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"), + .mime_type = "text/x-microdvd", + .extensions = "sub", + .write_header = microdvd_write_header, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, + .subtitle_codec = CODEC_ID_MICRODVD, +}; diff --git a/libavformat/mkvtimestamp_v2.c b/libavformat/mkvtimestamp_v2.c new file mode 100644 index 0000000000..b04c655f7f --- /dev/null +++ b/libavformat/mkvtimestamp_v2.c @@ -0,0 +1,51 @@ +/* + * extract pts as timecode v2, as defined by mkvtoolnix + * Copyright (c) 2009 David Conrad + * + * 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 "avformat.h" +#include "internal.h" + +static int write_header(AVFormatContext *s) +{ + static const char *header = "# timecode format v2\n"; + avio_write(s->pb, header, strlen(header)); + avpriv_set_pts_info(s->streams[0], 64, 1, 1000); + return 0; +} + +static int write_packet(AVFormatContext *s, AVPacket *pkt) +{ + char buf[256]; + if (pkt->stream_index) + 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; +} + +AVOutputFormat ff_mkvtimestamp_v2_muxer = { + .name = "mkvtimestamp_v2", + .long_name = NULL_IF_CONFIG_SMALL("extract pts as timecode v2 format, as defined by mkvtoolnix"), + .audio_codec = CODEC_ID_NONE, + .video_codec = CODEC_ID_RAWVIDEO, + .write_header = write_header, + .write_packet = write_packet, +}; diff --git a/libavformat/mm.c b/libavformat/mm.c index d25c978ac4..91d22d09d8 100644 --- a/libavformat/mm.c +++ b/libavformat/mm.c @@ -2,20 +2,20 @@ * American Laser Games MM Format Demuxer * Copyright (c) 2006 Peter Ross * - * 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/libavformat/mmf.c b/libavformat/mmf.c index 4d34cf2ac4..cbbb7dfed7 100644 --- a/libavformat/mmf.c +++ b/libavformat/mmf.c @@ -2,20 +2,20 @@ * Yamaha SMAF format * Copyright (c) 2005 Vidar Madsen * - * 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" @@ -265,7 +265,7 @@ static int mmf_read_packet(AVFormatContext *s, MMFContext *mmf = s->priv_data; int ret, size; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); size = MAX_SIZE; diff --git a/libavformat/mms.c b/libavformat/mms.c index 192e7039af..46fbede90c 100644 --- a/libavformat/mms.c +++ b/libavformat/mms.c @@ -4,20 +4,20 @@ * Copyright (c) 2007 Björn Axelsson * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot 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 */ #include "mms.h" diff --git a/libavformat/mms.h b/libavformat/mms.h index 5235581645..cbfa79a838 100644 --- a/libavformat/mms.h +++ b/libavformat/mms.h @@ -2,20 +2,20 @@ * MMS protocol common definitions. * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot 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 */ #ifndef AVFORMAT_MMS_H diff --git a/libavformat/mmsh.c b/libavformat/mmsh.c index 5e9d0bc134..d6e398200f 100644 --- a/libavformat/mmsh.c +++ b/libavformat/mmsh.c @@ -2,20 +2,20 @@ * MMS protocol over HTTP * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot 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 */ @@ -56,6 +56,7 @@ typedef enum { typedef struct { MMSContext mms; + uint8_t location[1024]; int request_seq; ///< request packet sequence int chunk_seq; ///< data packet sequence } MMSHContext; @@ -210,10 +211,10 @@ static int get_http_header_data(MMSHContext *mmsh) } } -static int mmsh_open(URLContext *h, const char *uri, int flags) +static int mmsh_open_internal(URLContext *h, const char *uri, int flags, int timestamp, int64_t pos) { int i, port, err; - char httpname[256], path[256], host[128], location[1024]; + char httpname[256], path[256], host[128]; char *stream_selection = NULL; char headers[1024]; MMSHContext *mmsh = h->priv_data; @@ -221,10 +222,10 @@ static int mmsh_open(URLContext *h, const char *uri, int flags) mmsh->request_seq = h->is_streamed = 1; mms = &mmsh->mms; - av_strlcpy(location, uri, sizeof(location)); + av_strlcpy(mmsh->location, uri, sizeof(mmsh->location)); av_url_split(NULL, 0, NULL, 0, - host, sizeof(host), &port, path, sizeof(path), location); + host, sizeof(host), &port, path, sizeof(path), mmsh->location); if (port<0) port = 80; // default mmsh protocol port ff_url_join(httpname, sizeof(httpname), "http", NULL, host, port, "%s", path); @@ -241,7 +242,7 @@ static int mmsh_open(URLContext *h, const char *uri, int flags) "Pragma: no-cache,rate=1.000000,stream-time=0," "stream-offset=0:0,request-context=%u,max-duration=0\r\n" CLIENTGUID - "Connection: Close\r\n\r\n", + "Connection: Close\r\n", host, port, mmsh->request_seq++); av_opt_set(mms->mms_hd->priv_data, "headers", headers, 0); @@ -282,8 +283,9 @@ static int mmsh_open(URLContext *h, const char *uri, int flags) CLIENTGUID "Pragma: stream-switch-count=%d\r\n" "Pragma: stream-switch-entry=%s\r\n" - "Connection: Close\r\n\r\n", - host, port, mmsh->request_seq++, mms->stream_num, stream_selection); + "Pragma: no-cache,rate=1.000000,stream-time=%u" + "Connection: Close\r\n", + host, port, mmsh->request_seq++, mms->stream_num, stream_selection, timestamp); av_freep(&stream_selection); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "Build play request failed!\n"); @@ -312,6 +314,11 @@ fail: return err; } +static int mmsh_open(URLContext *h, const char *uri, int flags) +{ + return mmsh_open_internal(h, uri, flags, 0, 0); +} + static int handle_chunk_type(MMSHContext *mmsh) { MMSContext *mms = &mmsh->mms; @@ -358,11 +365,46 @@ static int mmsh_read(URLContext *h, uint8_t *buf, int size) return res; } +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; + int ret; + + ret= mmsh_open_internal(h, mmsh->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); + 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; +} + +static int64_t mmsh_seek(URLContext *h, int64_t pos, int whence) +{ + MMSHContext *mmsh = h->priv_data; + MMSContext *mms = &mmsh->mms; + + if(pos == 0 && whence == SEEK_CUR) + return mms->asf_header_read_size + mms->remaining_in_len + mmsh->chunk_seq * mms->asf_packet_len; + return AVERROR(ENOSYS); +} + URLProtocol ff_mmsh_protocol = { .name = "mmsh", .url_open = mmsh_open, .url_read = mmsh_read, + .url_seek = mmsh_seek, .url_close = mmsh_close, + .url_read_seek = mmsh_read_seek, .priv_data_size = sizeof(MMSHContext), .flags = URL_PROTOCOL_FLAG_NETWORK, }; diff --git a/libavformat/mmst.c b/libavformat/mmst.c index 93ad073869..e3515b656a 100644 --- a/libavformat/mmst.c +++ b/libavformat/mmst.c @@ -4,20 +4,20 @@ * Copyright (c) 2007 Björn Axelsson * Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot 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 */ @@ -152,7 +152,7 @@ static int send_command_packet(MMSTContext *mmst) return 0; } -static void mms_put_utf16(MMSContext *mms, uint8_t *src) +static void mms_put_utf16(MMSContext *mms, const uint8_t *src) { AVIOContext bic; int size = mms->write_out_ptr - mms->out_buffer; diff --git a/libavformat/mov.c b/libavformat/mov.c index b7d8a55933..c46a2e4f02 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -3,20 +3,20 @@ * Copyright (c) 2001 Fabrice Bellard * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ @@ -30,12 +30,14 @@ #include "libavutil/mathematics.h" #include "libavutil/avstring.h" #include "libavutil/dict.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" #include "riff.h" #include "isom.h" #include "libavcodec/get_bits.h" +#include "libavcodec/timecode.h" #include "id3v1.h" #include "mov_chan.h" @@ -68,10 +70,11 @@ static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb, { char buf[16]; - short current, total; + short current, total = 0; avio_rb16(pb); // unknown current = avio_rb16(pb); - total = avio_rb16(pb); + if (len >= 6) + total = avio_rb16(pb); if (!total) snprintf(buf, sizeof(buf), "%d", current); else @@ -181,6 +184,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) case MKTAG(0xa9,'w','r','t'): key = "composer"; break; case MKTAG( 'c','p','r','t'): case MKTAG(0xa9,'c','p','y'): key = "copyright"; break; + case MKTAG(0xa9,'g','r','p'): key = "grouping"; break; + case MKTAG(0xa9,'l','y','r'): key = "lyrics"; break; case MKTAG(0xa9,'c','m','t'): case MKTAG(0xa9,'i','n','f'): key = "comment"; break; case MKTAG(0xa9,'a','l','b'): key = "album"; break; @@ -305,25 +310,23 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (atom.size < 0) atom.size = INT64_MAX; - while (total_size + 8 < atom.size && !pb->eof_reached) { + while (total_size + 8 <= atom.size && !url_feof(pb)) { int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL; a.size = atom.size; a.type=0; if (atom.size >= 8) { a.size = avio_rb32(pb); a.type = avio_rl32(pb); + total_size += 8; + if (a.size == 1) { /* 64 bit extended size */ + a.size = avio_rb64(pb) - 8; + total_size += 8; + } } av_dlog(c->fc, "type: %08x '%.4s' parent:'%.4s' sz: %"PRId64" %"PRId64" %"PRId64"\n", a.type, (char*)&a.type, (char*)&atom.type, a.size, total_size, atom.size); - total_size += 8; - if (a.size == 1) { /* 64 bit extended size */ - a.size = avio_rb64(pb) - 8; - total_size += 8; - } if (a.size == 0) { - a.size = atom.size - total_size; - if (a.size <= 8) - break; + a.size = atom.size - total_size + 8; } a.size -= 8; if (a.size < 0) @@ -430,6 +433,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, 16); for (type = 0; type != -1 && avio_tell(pb) < next; ) { + if(url_feof(pb)) + return AVERROR_EOF; type = avio_rb16(pb); len = avio_rb16(pb); av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len); @@ -475,6 +480,8 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st; uint32_t type; uint32_t av_unused ctype; + int title_size; + char *title_str; if (c->fc->nb_streams < 1) // meta before first trak return 0; @@ -504,6 +511,17 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb); /* component flags */ avio_rb32(pb); /* component flags mask */ + title_size = atom.size - 24; + if (title_size > 0) { + title_str = av_malloc(title_size + 1); /* Add null terminator */ + if (!title_str) + return AVERROR(ENOMEM); + avio_read(pb, title_str, title_size); + title_str[title_size] = 0; + av_dict_set(&st->metadata, "handler_name", title_str, 0); + av_freep(&title_str); + } + return 0; } @@ -579,7 +597,7 @@ static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (atom.size < 16ULL + num_descr * 20ULL) return 0; - av_dlog(c->fc, "chan: size=%ld version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n", + av_dlog(c->fc, "chan: size=%" PRId64 " version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n", atom.size, version, flags, layout_tag, bitmap, num_descr); label_mask = 0; @@ -776,6 +794,9 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dlog(c->fc, "time scale = %i\n", c->time_scale); c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */ + // set the AVCodecContext duration because the duration of individual tracks + // may be inaccurate + c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale); avio_rb32(pb); /* preferred scale */ avio_rb16(pb); /* preferred volume */ @@ -791,7 +812,6 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb); /* selection duration */ avio_rb32(pb); /* current time */ avio_rb32(pb); /* next track ID */ - return 0; } @@ -828,7 +848,7 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; st = c->fc->streams[c->fc->nb_streams-1]; - little_endian = avio_rb16(pb); + little_endian = avio_rb16(pb) & 0xFF; av_dlog(c->fc, "enda %d\n", little_endian); if (little_endian == 1) { switch (st->codec->codec_id) { @@ -886,7 +906,8 @@ static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom) } /* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */ -static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom) +static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom, + enum CodecID codec_id) { AVStream *st; uint64_t size; @@ -895,6 +916,10 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (c->fc->nb_streams < 1) // will happen with jp2 files return 0; st= c->fc->streams[c->fc->nb_streams-1]; + + if (st->codec->codec_id != codec_id) + return 0; /* unexpected codec_id - don't mess with extradata */ + 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; @@ -910,6 +935,22 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +/* wrapper functions for reading ALAC/AVS/MJPEG/MJPEG2000 extradata atoms only for those codecs */ +static int mov_read_alac(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + return mov_read_extradata(c, pb, atom, CODEC_ID_ALAC); +} + +static int mov_read_avss(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + return mov_read_extradata(c, pb, atom, CODEC_ID_AVS); +} + +static int mov_read_jp2h(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + return mov_read_extradata(c, pb, atom, CODEC_ID_JPEG2000); +} + static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -1096,6 +1137,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) avio_rb32(pb); /* reserved */ avio_rb16(pb); /* reserved */ dref_id = avio_rb16(pb); + }else if (size <= 0){ + av_log(c->fc, AV_LOG_ERROR, "invalid size %d in stsd\n", size); + return -1; } if (st->codec->codec_tag && @@ -1184,7 +1228,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) (color_depth == 8)) { /* for palette traversal */ unsigned int color_start, color_count, color_end; - unsigned char r, g, b; + unsigned char a, r, g, b; if (color_greyscale) { int color_index, color_dec; @@ -1194,9 +1238,12 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) color_index = 255; color_dec = 256 / (color_count - 1); for (j = 0; j < color_count; j++) { + if (id == CODEC_ID_CINEPAK){ + r = g = b = color_count - 1 - color_index; + }else r = g = b = color_index; sc->palette[j] = - (r << 16) | (g << 8) | (b); + (0xFFU << 24) | (r << 16) | (g << 8) | (b); color_index -= color_dec; if (color_index < 0) color_index = 0; @@ -1217,7 +1264,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) g = color_table[j * 3 + 1]; b = color_table[j * 3 + 2]; sc->palette[j] = - (r << 16) | (g << 8) | (b); + (0xFFU << 24) | (r << 16) | (g << 8) | (b); } } else { /* load the palette from the file */ @@ -1227,10 +1274,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) if ((color_start <= 255) && (color_end <= 255)) { for (j = color_start; j <= color_end; j++) { - /* each R, G, or B component is 16 bits; - * only use the top 8 bits; skip alpha bytes - * up front */ - avio_r8(pb); + /* 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); @@ -1239,7 +1285,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) b = avio_r8(pb); avio_r8(pb); sc->palette[j] = - (r << 16) | (g << 8) | (b); + (a << 24 ) | (r << 16) | (g << 8) | (b); } } } @@ -1335,7 +1381,18 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) st->codec->width = sc->width; st->codec->height = sc->height; } else { - /* other codec type, just skip (rtp, mp4s, tmcd ...) */ + if (st->codec->codec_tag == MKTAG('t','m','c','d')) { + int val; + avio_rb32(pb); /* reserved */ + val = avio_rb32(pb); /* flags */ + if (val & 1) + st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE; + avio_rb32(pb); /* 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)); } /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ @@ -1403,6 +1460,12 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) st->codec->sample_rate = AV_RB32(st->codec->extradata+32); } break; + case CODEC_ID_AC3: + st->need_parsing = AVSTREAM_PARSE_FULL; + break; + case CODEC_ID_MPEG1VIDEO: + st->need_parsing = AVSTREAM_PARSE_FULL; + break; default: break; } @@ -1609,10 +1672,8 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_dlog(c->fc, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); - if (!entries) - return 0; if (entries >= UINT_MAX / sizeof(*sc->stts_data)) - return AVERROR(EINVAL); + return -1; sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data)); if (!sc->stts_data) @@ -1626,6 +1687,11 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sample_count=avio_rb32(pb); sample_duration = avio_rb32(pb); + /* sample_duration < 0 is invalid based on the spec */ + if (sample_duration < 0) { + av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d\n", sample_duration); + sample_duration = 1; + } sc->stts_data[i].count= sample_count; sc->stts_data[i].duration= sample_duration; @@ -1674,7 +1740,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->ctts_data[i].count = count; sc->ctts_data[i].duration= duration; - if (duration < 0) + if (duration < 0 && i+2<entries) sc->dts_shift = FFMAX(sc->dts_shift, -duration); } @@ -1696,12 +1762,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st) uint64_t stream_size = 0; /* adjust first dts according to edit list */ - if (sc->time_offset && mov->time_scale > 0) { - if (sc->time_offset < 0) - sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale); + if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) { + if (sc->empty_duration) + sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale); + sc->time_offset = sc->start_time - sc->empty_duration; current_dts = -sc->time_offset; - if (sc->ctts_data && sc->stts_data && sc->stts_data[0].duration && - sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) { + if (sc->ctts_data && sc->stts_data && + sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) { /* more than 16 frames delay, dts are likely wrong this happens with files created by iMovie */ sc->wrong_dts = 1; @@ -1788,7 +1855,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned count, chunk_count; chunk_samples = sc->stsc_data[i].count; - if (sc->samples_per_frame && chunk_samples % sc->samples_per_frame) { + if (i != sc->stsc_count - 1 && + sc->samples_per_frame && chunk_samples % sc->samples_per_frame) { av_log(mov->fc, AV_LOG_ERROR, "error unaligned chunk\n"); return; } @@ -1865,14 +1933,14 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } -static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref, - AVIOInterruptCB *int_cb) +static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref, + AVIOInterruptCB *int_cb, int use_absolute_path, AVFormatContext *fc) { /* try relative path, we do not try the absolute because it can leak information about our system to an attacker */ if (ref->nlvl_to > 0 && ref->nlvl_from > 0) { char filename[1024]; - char *src_path; + const char *src_path; int i, l; /* find a source dir */ @@ -1904,6 +1972,11 @@ static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref, if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL)) return 0; } + } else if (use_absolute_path) { + av_log(fc, AV_LOG_WARNING, "Using absolute path on user request, " + "this is a possible security issue\n"); + if (!avio_open2(pb, ref->path, AVIO_FLAG_READ, int_cb, NULL)) + return 0; } return AVERROR(ENOENT); @@ -1956,7 +2029,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { MOVDref *dref = &sc->drefs[sc->dref_id - 1]; - if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback) < 0) + if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback, + c->use_absolute_path, c->fc) < 0) av_log(c->fc, AV_LOG_ERROR, "stream %d, error opening alias: path='%s', dir='%s', " "filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n", @@ -2091,6 +2165,21 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->width = width >> 16; sc->height = height >> 16; + //Assign clockwise rotate values based on transform matrix so that + //we can compensate for iPhone orientation during capture. + + if (display_matrix[1][0] == -65536 && display_matrix[0][1] == 65536) { + av_dict_set(&st->metadata, "rotate", "90", 0); + } + + if (display_matrix[0][0] == -65536 && display_matrix[1][1] == -65536) { + av_dict_set(&st->metadata, "rotate", "180", 0); + } + + if (display_matrix[1][0] == 65536 && display_matrix[0][1] == -65536) { + av_dict_set(&st->metadata, "rotate", "270", 0); + } + // transform the display width/height according to the matrix // skip this if the display matrix is the default identity matrix // or if it is rotating the picture, ex iPhone 3GS @@ -2165,6 +2254,9 @@ static int mov_read_trex(MOVContext *c, AVIOContext *pb, MOVAtom atom) trex = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data)); if (!trex) return AVERROR(ENOMEM); + + 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 */ @@ -2342,7 +2434,7 @@ free_and_return: static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; - int i, edit_count, version; + int i, edit_count, version, edit_start_index = 0; if (c->fc->nb_streams < 1) return 0; @@ -2366,9 +2458,11 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) time = (int32_t)avio_rb32(pb); /* media time */ } avio_rb32(pb); /* Media rate */ - if (i == 0 && time >= -1) { - sc->time_offset = time != -1 ? time : -duration; - } + if (i == 0 && time == -1) { + sc->empty_duration = duration; + edit_start_index = 1; + } else if (i == edit_start_index && time >= 0) + sc->start_time = time; } if (edit_count > 1) @@ -2379,8 +2473,17 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_chan2(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + if (atom.size < 16) + return 0; + avio_skip(pb, 4); + ff_mov_read_chan(c->fc, atom.size - 4, c->fc->streams[0]->codec); + return 0; +} + static const MOVParseTableEntry mov_default_parse_table[] = { -{ MKTAG('a','v','s','s'), mov_read_extradata }, +{ MKTAG('a','v','s','s'), mov_read_avss }, { MKTAG('c','h','p','l'), mov_read_chpl }, { MKTAG('c','o','6','4'), mov_read_stco }, { MKTAG('c','t','t','s'), mov_read_ctts }, /* composition time to sample */ @@ -2394,7 +2497,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('g','l','b','l'), mov_read_glbl }, { MKTAG('h','d','l','r'), mov_read_hdlr }, { MKTAG('i','l','s','t'), mov_read_ilst }, -{ MKTAG('j','p','2','h'), mov_read_extradata }, +{ MKTAG('j','p','2','h'), mov_read_jp2h }, { MKTAG('m','d','a','t'), mov_read_mdat }, { MKTAG('m','d','h','d'), mov_read_mdhd }, { MKTAG('m','d','i','a'), mov_read_default }, @@ -2405,7 +2508,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('m','v','e','x'), mov_read_default }, { MKTAG('m','v','h','d'), mov_read_mvhd }, { MKTAG('S','M','I',' '), mov_read_smi }, /* Sorenson extension ??? */ -{ MKTAG('a','l','a','c'), mov_read_extradata }, /* alac specific atom */ +{ MKTAG('a','l','a','c'), mov_read_alac }, /* alac specific atom */ { MKTAG('a','v','c','C'), mov_read_glbl }, { MKTAG('p','a','s','p'), mov_read_pasp }, { MKTAG('s','t','b','l'), mov_read_default }, @@ -2540,7 +2643,7 @@ static void mov_read_chapters(AVFormatContext *s) if (len == 1 || len == 2) title[len] = 0; else - avio_get_str(sc->pb, len - 2, title + 2, title_len - 2); + avio_get_str(sc->pb, INT_MAX, title + 2, len - 1); } } @@ -2551,6 +2654,46 @@ finish: avio_seek(sc->pb, cur_pos, SEEK_SET); } +static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st, + uint32_t value) +{ + char buf[16]; + struct ff_timecode tc = { + .drop = st->codec->flags2 & CODEC_FLAG2_DROP_FRAME_TIMECODE, + .rate = (AVRational){st->codec->time_base.den, + st->codec->time_base.num}, + }; + + if (avpriv_check_timecode_rate(s, tc.rate, tc.drop) < 0) + return AVERROR(EINVAL); + av_dict_set(&st->metadata, "timecode", + avpriv_timecode_to_string(buf, &tc, value), 0); + return 0; +} + +static int mov_read_timecode_track(AVFormatContext *s, AVStream *st) +{ + MOVStreamContext *sc = st->priv_data; + int64_t cur_pos = avio_tell(sc->pb); + uint32_t value; + + if (!st->nb_index_entries) + return -1; + + avio_seek(sc->pb, st->index_entries->pos, SEEK_SET); + value = avio_rb32(s->pb); + + /* Assume Counter flag is set to 1 in tmcd track (even though it is likely + * not the case) and thus assume "frame number format" instead of QT one. + * No sample with tmcd track can be found with a QT timecode at the moment, + * despite what the tmcd track "suggests" (Counter flag set to 0 means QT + * format). */ + parse_timecode_in_framenum_format(s, st, value); + + avio_seek(sc->pb, cur_pos, SEEK_SET); + return 0; +} + static int mov_read_header(AVFormatContext *s) { MOVContext *mov = s->priv_data; @@ -2576,8 +2719,14 @@ static int mov_read_header(AVFormatContext *s) } av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); - if (pb->seekable && mov->chapter_track > 0) - mov_read_chapters(s); + if (pb->seekable) { + int i; + if (mov->chapter_track > 0) + mov_read_chapters(s); + for (i = 0; i < s->nb_streams; i++) + if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd")) + mov_read_timecode_track(s, s->streams[i]); + } if (mov->trex_data) { int i; @@ -2625,13 +2774,14 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) AVIndexEntry *sample; AVStream *st = NULL; int ret; + mov->fc = s; retry: sample = mov_find_next_sample(s, &st); if (!sample) { mov->found_mdat = 0; if (s->pb->seekable|| mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || - s->pb->eof_reached) + url_feof(s->pb)) return AVERROR_EOF; av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb)); goto retry; @@ -2662,7 +2812,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) } #if CONFIG_DV_DEMUXER if (mov->dv_demux && sc->dv_audio_container) { - avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); + avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos); av_free(pkt->data); pkt->size = 0; ret = avpriv_dv_get_packet(mov->dv_demux, pkt); @@ -2794,6 +2944,15 @@ static int mov_read_close(AVFormatContext *s) return 0; } +static const AVOption options[] = { + {"use_absolute_path", + "allow using absolute path when opening alias, this is a possible security issue", + offsetof(MOVContext, use_absolute_path), FF_OPT_TYPE_INT, {.dbl = 0}, + 0, 1, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM}, + {NULL} +}; +static const AVClass class = {"mov,mp4,m4a,3gp,3g2,mj2", av_default_item_name, options, LIBAVUTIL_VERSION_INT}; + AVInputFormat ff_mov_demuxer = { .name = "mov,mp4,m4a,3gp,3g2,mj2", .long_name = NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"), @@ -2803,4 +2962,5 @@ AVInputFormat ff_mov_demuxer = { .read_packet = mov_read_packet, .read_close = mov_read_close, .read_seek = mov_read_seek, + .priv_class = &class, }; diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 22e8d842f4..4574df3de9 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -4,20 +4,20 @@ * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org> * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ @@ -45,13 +45,14 @@ static const AVOption options[] = { { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.dbl = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 }, { "empty_moov", "Make the initial moov atom empty (not supported by QuickTime)", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.dbl = 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, {.dbl = 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, {.dbl = FF_MOV_FLAG_ISML}, 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, {.dbl = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, + { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.dbl = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.dbl = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, @@ -92,8 +93,10 @@ static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) } else ffio_wfourcc(pb, "stco"); avio_wb32(pb, 0); /* version & flags */ - avio_wb32(pb, track->entry); /* entry count */ + avio_wb32(pb, track->chunkCount); /* entry count */ for (i=0; i<track->entry; i++) { + if(!track->cluster[i].chunkNum) + continue; if(mode64 == 1) avio_wb64(pb, track->cluster[i].pos); else @@ -151,11 +154,11 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "stsc"); avio_wb32(pb, 0); // version & flags entryPos = avio_tell(pb); - avio_wb32(pb, track->entry); // entry count + avio_wb32(pb, track->chunkCount); // entry count for (i=0; i<track->entry; i++) { - if(oldval != track->cluster[i].samplesInChunk) + if(oldval != track->cluster[i].samplesInChunk && track->cluster[i].chunkNum) { - avio_wb32(pb, i+1); // first chunk + avio_wb32(pb, track->cluster[i].chunkNum); // first chunk avio_wb32(pb, track->cluster[i].samplesInChunk); // samples per chunk avio_wb32(pb, 0x1); // sample description index oldval = track->cluster[i].samplesInChunk; @@ -279,10 +282,20 @@ static void putDescr(AVIOContext *pb, int tag, unsigned int size) avio_w8(pb, size & 0x7F); } +static unsigned compute_avg_bitrate(MOVTrack *track) +{ + uint64_t size = 0; + int i; + for (i = 0; i < track->entry; i++) + size += track->cluster[i].size; + return size * 8 * track->timescale / track->trackDuration; +} + static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic { int64_t pos = avio_tell(pb); int decoderSpecificInfoLen = track->vosLen ? 5+track->vosLen : 0; + unsigned avg_bitrate; avio_wb32(pb, 0); // size ffio_wfourcc(pb, "esds"); @@ -314,11 +327,10 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic avio_w8(pb, track->enc->rc_buffer_size>>(3+16)); // Buffersize DB (24 bits) avio_wb16(pb, (track->enc->rc_buffer_size>>3)&0xFFFF); // Buffersize DB - avio_wb32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window) - if(track->enc->rc_max_rate != track->enc->rc_min_rate || track->enc->rc_min_rate==0) - avio_wb32(pb, 0); // vbr - else - avio_wb32(pb, track->enc->rc_max_rate); // avg bitrate + avg_bitrate = compute_avg_bitrate(track); + // maxbitrate (FIXME should be max rate in any 1 sec window) + avio_wb32(pb, FFMAX3(track->enc->bit_rate, track->enc->rc_max_rate, avg_bitrate)); + avio_wb32(pb, avg_bitrate); if (track->vosLen) { // DecoderSpecific info descriptor @@ -456,9 +468,15 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) uint32_t tag = track->tag; if (track->mode == MODE_MOV) { - if (mov_get_lpcm_flags(track->enc->codec_id)) - tag = AV_RL32("lpcm"); - version = 2; + if (track->timescale > UINT16_MAX) { + if (mov_get_lpcm_flags(track->enc->codec_id)) + tag = AV_RL32("lpcm"); + version = 2; + } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id) || + track->enc->codec_id == CODEC_ID_ADPCM_MS || + track->enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) { + version = 1; + } } avio_wb32(pb, 0); /* size */ @@ -485,18 +503,34 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track) avio_wb32(pb, av_get_bits_per_sample(track->enc->codec_id)); avio_wb32(pb, mov_get_lpcm_flags(track->enc->codec_id)); avio_wb32(pb, track->sampleSize); - avio_wb32(pb, track->audio_vbr ? track->enc->frame_size : 1); + avio_wb32(pb, track->enc->frame_size); } else { - /* reserved for mp4/3gp */ - avio_wb16(pb, 2); - avio_wb16(pb, 16); - avio_wb16(pb, 0); + if (track->mode == MODE_MOV) { + avio_wb16(pb, track->enc->channels); + if (track->enc->codec_id == CODEC_ID_PCM_U8 || + track->enc->codec_id == CODEC_ID_PCM_S8) + avio_wb16(pb, 8); /* bits per sample */ + else + avio_wb16(pb, 16); + avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */ + } else { /* reserved for mp4/3gp */ + avio_wb16(pb, 2); + avio_wb16(pb, 16); + avio_wb16(pb, 0); + } avio_wb16(pb, 0); /* packet size (= 0) */ avio_wb16(pb, track->enc->sample_rate); avio_wb16(pb, 0); /* Reserved */ } + if(version == 1) { /* SoundDescription V1 extended info */ + avio_wb32(pb, track->enc->frame_size); /* Samples per packet */ + avio_wb32(pb, track->sampleSize / track->enc->channels); /* Bytes per packet */ + avio_wb32(pb, track->sampleSize); /* Bytes per frame */ + avio_wb32(pb, 2); /* Bytes per sample */ + } + if(track->mode == MODE_MOV && (track->enc->codec_id == CODEC_ID_AAC || track->enc->codec_id == CODEC_ID_AC3 || @@ -1030,6 +1064,7 @@ static int mov_write_dref_tag(AVIOContext *pb) avio_wb32(pb, 1); /* entry count */ avio_wb32(pb, 0xc); /* size */ + //FIXME add the alis and rsrc atom ffio_wfourcc(pb, "url "); avio_wb32(pb, 1); /* version & flags */ @@ -1423,11 +1458,8 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov, avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "trak"); mov_write_tkhd_tag(pb, track, st); - if (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS || - (track->entry && track->cluster[0].dts)) { - if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) - mov_write_edts_tag(pb, track); // PSP Movies require edts box - } + if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) // EDTS with fragments is tricky as we dont know the duration when its written + mov_write_edts_tag(pb, track); // PSP Movies and several other cases require edts box if (track->tref_tag) mov_write_tref_tag(pb, track); mov_write_mdia_tag(pb, track); @@ -1785,32 +1817,32 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, if(ret < 0) return ret; - if (mov->mode & MODE_3GP) { - mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist"); - mov_write_3gp_udta_tag(pb_buf, s, "titl", "title"); - mov_write_3gp_udta_tag(pb_buf, s, "auth", "author"); - mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre"); - mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment"); - mov_write_3gp_udta_tag(pb_buf, s, "albm", "album"); - 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, "\251des", "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); - } + if (mov->mode & MODE_3GP) { + mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist"); + mov_write_3gp_udta_tag(pb_buf, s, "titl", "title"); + mov_write_3gp_udta_tag(pb_buf, s, "auth", "author"); + mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre"); + mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment"); + mov_write_3gp_udta_tag(pb_buf, s, "albm", "album"); + 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, "\251des", "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); + } - if (s->nb_chapters) - mov_write_chpl_tag(pb_buf, s); + if (s->nb_chapters) + mov_write_chpl_tag(pb_buf, s); if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) { avio_wb32(pb, size+8); @@ -1873,6 +1905,27 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s) return 0; } +static void build_chunks(MOVTrack *trk) +{ + int i; + MOVIentry *chunk= &trk->cluster[0]; + uint64_t chunkSize = chunk->size; + chunk->chunkNum= 1; + 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->samplesInChunk += trk->cluster[i].entries; + }else{ + trk->cluster[i].chunkNum = chunk->chunkNum+1; + chunk=&trk->cluster[i]; + chunkSize = chunk->size; + trk->chunkCount++; + } + } +} + static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) { @@ -1887,6 +1940,8 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov, mov->tracks[i].time = mov->time; mov->tracks[i].trackID = i+1; + + build_chunks(&mov->tracks[i]); } if (mov->chapter_track) @@ -2644,6 +2699,9 @@ static int mov_write_packet_internal(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n"); return -1; } + } else if (enc->codec_id == CODEC_ID_ADPCM_MS || + enc->codec_id == CODEC_ID_ADPCM_IMA_WAV) { + samplesInChunk = enc->frame_size; } else if (trk->sampleSize) samplesInChunk = size/trk->sampleSize; else @@ -2666,6 +2724,10 @@ static int mov_write_packet_internal(AVFormatContext *s, AVPacket *pkt) } else { size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size); } + } else if (enc->codec_id == 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); } @@ -2681,13 +2743,14 @@ static int mov_write_packet_internal(AVFormatContext *s, AVPacket *pkt) } if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) { - trk->cluster = av_realloc(trk->cluster, (trk->entry + MOV_INDEX_CLUSTER_SIZE) * sizeof(*trk->cluster)); + trk->cluster = av_realloc_f(trk->cluster, sizeof(*trk->cluster), (trk->entry + MOV_INDEX_CLUSTER_SIZE)); if (!trk->cluster) return -1; } trk->cluster[trk->entry].pos = avio_tell(pb) - size; trk->cluster[trk->entry].samplesInChunk = samplesInChunk; + trk->cluster[trk->entry].chunkNum = 0; trk->cluster[trk->entry].size = size; trk->cluster[trk->entry].entries = samplesInChunk; trk->cluster[trk->entry].dts = pkt->dts; @@ -2877,21 +2940,21 @@ static int mov_write_header(AVFormatContext *s) "or choose different container.\n"); }else if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO){ track->timescale = st->codec->sample_rate; - /* set sampleSize for PCM and ADPCM */ - if (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_ERROR, "track %d: codec frame size is not set\n", i); + goto error; + }else if(st->codec->codec_id == CODEC_ID_ADPCM_MS || + st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV){ if (!st->codec->block_align) { - av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set\n", i); + av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i); goto error; } track->sampleSize = st->codec->block_align; - } - /* set audio_vbr for compressed audio */ - if (av_get_bits_per_sample(st->codec->codec_id) < 8) { - if (!st->codec->frame_size && track->mode == MODE_MOV) { - av_log(s, AV_LOG_ERROR, "track %d: codec frame size is not set\n", i); - goto error; - } + }else if(st->codec->frame_size > 1){ /* assume compressed audio */ track->audio_vbr = 1; + }else{ + st->codec->frame_size = 1; + track->sampleSize = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels; } if (track->mode != MODE_MOV) { if (track->timescale > UINT16_MAX) { @@ -2934,6 +2997,11 @@ static int mov_write_header(AVFormatContext *s) mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF; } + if(mov->reserved_moov_size){ + mov->reserved_moov_pos= avio_tell(pb); + avio_skip(pb, mov->reserved_moov_size); + } + /* Set the FRAGMENT flag if any of the fragmentation methods are * enabled. */ if (mov->max_fragment_duration || mov->max_fragment_size || @@ -3004,9 +3072,21 @@ static int mov_write_trailer(AVFormatContext *s) ffio_wfourcc(pb, "mdat"); avio_wb64(pb, mov->mdat_size + 16); } - avio_seek(pb, moov_pos, SEEK_SET); + avio_seek(pb, mov->reserved_moov_size ? mov->reserved_moov_pos : moov_pos, SEEK_SET); mov_write_moov_tag(pb, mov, s); + if(mov->reserved_moov_size){ + int64_t size= mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos); + 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++) + avio_w8(pb, 0); + avio_seek(pb, moov_pos, SEEK_SET); + } } else { mov_flush_fragment(s); mov_write_mfra_tag(pb, mov); diff --git a/libavformat/movenc.h b/libavformat/movenc.h index 0b74a61d06..10181177c8 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -4,20 +4,20 @@ * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org> * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ @@ -35,7 +35,7 @@ #define MODE_MOV 0x02 #define MODE_3GP 0x04 #define MODE_PSP 0x08 // example working PSP command line: -// avconv -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4 +// ffmpeg -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4 #define MODE_3G2 0x10 #define MODE_IPOD 0x20 #define MODE_ISM 0x40 @@ -45,6 +45,7 @@ typedef struct MOVIentry { int64_t dts; unsigned int size; unsigned int samplesInChunk; + unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 0 unsigned int entries; int cts; #define MOV_SYNC_SAMPLE 0x0001 @@ -81,6 +82,7 @@ typedef struct MOVIndex { int64_t trackDuration; long sampleCount; long sampleSize; + long chunkCount; int hasKeyframes; #define MOV_TRACK_CTTS 0x0001 #define MOV_TRACK_STPS 0x0002 @@ -134,6 +136,9 @@ typedef struct MOVMuxContext { int flags; int rtp_flags; + int reserved_moov_size; + int64_t reserved_moov_pos; + int iods_skip; int iods_video_profile; int iods_audio_profile; diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c index 9f5e621a88..bb55f73053 100644 --- a/libavformat/movenchint.c +++ b/libavformat/movenchint.c @@ -2,20 +2,20 @@ * MOV, 3GP, MP4 muxer RTP hinting * Copyright (c) 2010 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/libavformat/mp3dec.c b/libavformat/mp3dec.c index 11f57ce1a9..8dfcea23bc 100644 --- a/libavformat/mp3dec.c +++ b/libavformat/mp3dec.c @@ -2,20 +2,20 @@ * MP3 demuxer * Copyright (c) 2003 Fabrice Bellard * - * 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 */ @@ -64,7 +64,7 @@ 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>500)return AVPROBE_SCORE_MAX/2; + else if(max_frames>200)return AVPROBE_SCORE_MAX/2; else if(max_frames>=4) return AVPROBE_SCORE_MAX/4; else if(max_frames>=1) return 1; else return 0; @@ -111,8 +111,8 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base) if(avio_rb16(s->pb) == 1) { /* skip delay and quality */ avio_skip(s->pb, 4); - frames = avio_rb32(s->pb); size = avio_rb32(s->pb); + frames = avio_rb32(s->pb); } } @@ -174,7 +174,9 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->stream_index = 0; if (ret <= 0) { - return AVERROR(EIO); + if(ret<0) + return ret; + return AVERROR_EOF; } if (ret > ID3v1_TAG_SIZE && diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index ce547ead38..8d82452689 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -2,20 +2,20 @@ * MP3 muxer * Copyright (c) 2003 Fabrice Bellard * - * 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 */ @@ -30,6 +30,10 @@ #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" static int id3v1_set_string(AVFormatContext *s, const char *key, @@ -50,11 +54,12 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf) buf[0] = 'T'; buf[1] = 'A'; buf[2] = 'G'; - count += id3v1_set_string(s, "TIT2", buf + 3, 30); //title - count += id3v1_set_string(s, "TPE1", buf + 33, 30); //author|artist - count += id3v1_set_string(s, "TALB", buf + 63, 30); //album - count += id3v1_set_string(s, "TDRL", buf + 93, 4); //date - count += id3v1_set_string(s, "comment", buf + 97, 30); + /* we knowingly overspecify each tag length by one byte to compensate for the mandatory null byte added by av_strlcpy */ + count += id3v1_set_string(s, "TIT2", buf + 3, 30 + 1); //title + count += id3v1_set_string(s, "TPE1", buf + 33, 30 + 1); //author|artist + count += id3v1_set_string(s, "TALB", buf + 63, 30 + 1); //album + count += id3v1_set_string(s, "TDRL", buf + 93, 4 + 1); //date + count += id3v1_set_string(s, "comment", buf + 97, 30 + 1); if ((tag = av_dict_get(s->metadata, "TRCK", NULL, 0))) { //track buf[125] = 0; buf[126] = atoi(tag->value); @@ -73,14 +78,23 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf) return count; } +#define VBR_NUM_BAGS 400 +#define VBR_TOC_SIZE 100 + typedef struct MP3Context { const AVClass *class; int id3v2_version; int write_id3v1; - int64_t nb_frames_offset; + int64_t frames_offset; + int32_t frames; + int32_t size; + uint32_t want; + uint32_t seen; + uint32_t pos; + uint64_t bag[VBR_NUM_BAGS]; } MP3Context; -static int mp3_write_trailer(struct AVFormatContext *s) +static int mp2_write_trailer(struct AVFormatContext *s) { uint8_t buf[ID3v1_TAG_SIZE]; MP3Context *mp3 = s->priv_data; @@ -91,8 +105,8 @@ static int mp3_write_trailer(struct AVFormatContext *s) } /* write number of frames */ - if (mp3 && mp3->nb_frames_offset) { - avio_seek(s->pb, mp3->nb_frames_offset, SEEK_SET); + if (mp3 && mp3->frames_offset) { + avio_seek(s->pb, mp3->frames_offset, SEEK_SET); avio_wb32(s->pb, s->streams[0]->nb_frames); avio_seek(s->pb, 0, SEEK_END); } @@ -111,7 +125,8 @@ AVOutputFormat ff_mp2_muxer = { .audio_codec = CODEC_ID_MP2, .video_codec = CODEC_ID_NONE, .write_packet = ff_raw_write_packet, - .write_trailer = mp3_write_trailer, + .write_trailer = mp2_write_trailer, + .flags = AVFMT_NOTIMESTAMPS, }; #endif @@ -132,16 +147,23 @@ static const AVClass mp3_muxer_class = { .version = LIBAVUTIL_VERSION_INT, }; -/* insert a dummy frame containing number of frames */ -static void mp3_write_xing(AVFormatContext *s) +static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; + +/* + * Write an empty XING header and initialize respective data. + */ +static int mp3_write_xing(AVFormatContext *s) { - AVCodecContext *codec = s->streams[0]->codec; + AVCodecContext *codec = s->streams[0]->codec; MP3Context *mp3 = s->priv_data; - int bitrate_idx = 1; // 32 kbps - int64_t xing_offset = (codec->channels == 2) ? 32 : 17; - int32_t header; - MPADecodeHeader mpah; - int srate_idx, i, channels; + int bitrate_idx; + int best_bitrate_idx; + int best_bitrate_error= INT_MAX; + int64_t xing_offset; + int32_t header, mask; + MPADecodeHeader c; + int srate_idx, i, channels; + int needed; for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) if (avpriv_mpa_freq_tab[i] == codec->sample_rate) { @@ -150,32 +172,125 @@ static void mp3_write_xing(AVFormatContext *s) } if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) { av_log(s, AV_LOG_ERROR, "Unsupported sample rate.\n"); - return; + return -1; } switch (codec->channels) { case 1: channels = MPA_MONO; break; case 2: channels = MPA_STEREO; break; - default: av_log(s, AV_LOG_ERROR, "Unsupported number of channels.\n"); return; + default: av_log(s, AV_LOG_ERROR, "Unsupported number of channels.\n"); return -1; } /* dummy MPEG audio header */ header = 0xff << 24; // sync header |= (0x7 << 5 | 0x3 << 3 | 0x1 << 1 | 0x1) << 16; // sync/mpeg-1/layer 3/no crc*/ - header |= (bitrate_idx << 4 | srate_idx << 2) << 8; + header |= (srate_idx << 2) << 8; header |= channels << 6; - avio_wb32(s->pb, header); - avpriv_mpegaudio_decode_header(&mpah, header); + for (bitrate_idx=1; bitrate_idx<15; bitrate_idx++) { + int error; + avpriv_mpegaudio_decode_header(&c, header | (bitrate_idx << (4+8))); + error= FFABS(c.bit_rate - codec->bit_rate); + if(error < best_bitrate_error){ + best_bitrate_error= error; + best_bitrate_idx = bitrate_idx; + } + } + for (bitrate_idx= best_bitrate_idx;; bitrate_idx++) { + if (15 == bitrate_idx) + return -1; + mask = bitrate_idx << (4+8); + header |= mask; + avpriv_mpegaudio_decode_header(&c, header); + xing_offset=xing_offtbl[c.lsf == 1][c.nb_channels == 1]; + needed = 4 // header + + xing_offset + + 4 // xing tag + + 4 // frames/size/toc flags + + 4 // frames + + 4 // size + + VBR_TOC_SIZE; // toc + + if (needed <= c.frame_size) + break; + header &= ~mask; + } + + avio_wb32(s->pb, header); ffio_fill(s->pb, 0, xing_offset); - ffio_wfourcc(s->pb, "Xing"); - avio_wb32(s->pb, 0x1); // only number of frames - mp3->nb_frames_offset = avio_tell(s->pb); - avio_wb32(s->pb, 0); + avio_wb32(s->pb, MKBETAG('X', 'i', 'n', 'g')); + avio_wb32(s->pb, 0x01 | 0x02 | 0x04); // frames/size/toc + + mp3->frames_offset = avio_tell(s->pb); + mp3->size = c.frame_size; + mp3->want=1; + mp3->seen=0; + mp3->pos=0; + + avio_wb32(s->pb, 0); // frames + avio_wb32(s->pb, 0); // size + + // toc + for (i = 0; i < VBR_TOC_SIZE; ++i) + avio_w8(s->pb, (uint8_t)(255 * i / VBR_TOC_SIZE)); + + ffio_fill(s->pb, 0, c.frame_size - needed); + avio_flush(s->pb); + + return 0; +} + +/* + * Add a frame to XING data. + * Following lame's "VbrTag.c". + */ +static void mp3_xing_add_frame(AVFormatContext *s, AVPacket *pkt) +{ + MP3Context *mp3 = s->priv_data; + int i; + + ++mp3->frames; + mp3->size += pkt->size; + + if (mp3->want == ++mp3->seen) { + mp3->bag[mp3->pos] = mp3->size; + + if (VBR_NUM_BAGS == ++mp3->pos) { + /* shrink table to half size by throwing away each second bag. */ + for (i = 1; i < VBR_NUM_BAGS; i += 2) + mp3->bag[i >> 1] = mp3->bag[i]; + + /* double wanted amount per bag. */ + mp3->want <<= 1; + /* adjust current position to half of table size. */ + mp3->pos >>= 1; + } + + mp3->seen = 0; + } +} + +static void mp3_fix_xing(AVFormatContext *s) +{ + MP3Context *mp3 = s->priv_data; + int i; + + avio_flush(s->pb); + avio_seek(s->pb, mp3->frames_offset, SEEK_SET); + avio_wb32(s->pb, mp3->frames); + avio_wb32(s->pb, mp3->size); + + avio_w8(s->pb, 0); // first toc entry has to be zero. + + for (i = 1; i < VBR_TOC_SIZE; ++i) { + int j = i * mp3->pos / VBR_TOC_SIZE; + int seek_point = 256LL * mp3->bag[j] / mp3->size; + avio_w8(s->pb, FFMIN(seek_point, 255)); + } - mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4; - ffio_fill(s->pb, 0, mpah.frame_size); + avio_flush(s->pb); + avio_seek(s->pb, 0, SEEK_END); } /** @@ -197,6 +312,56 @@ static int mp3_write_header(struct AVFormatContext *s) return 0; } +static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + if (! pkt || ! pkt->data || pkt->size < 4) + return ff_raw_write_packet(s, pkt); + else { + MP3Context *mp3 = s->priv_data; +#ifdef FILTER_VBR_HEADERS + MPADecodeHeader c; + int base; + + ff_mpegaudio_decode_header(&c, AV_RB32(pkt->data)); + + /* filter out XING and INFO headers. */ + base = 4 + xing_offtbl[c.lsf == 1][c.nb_channels == 1]; + + if (base + 4 <= pkt->size) { + uint32_t v = AV_RB32(pkt->data + base); + + if (MKBETAG('X','i','n','g') == v || MKBETAG('I','n','f','o') == v) + return 0; + } + + /* filter out VBRI headers. */ + base = 4 + 32; + + if (base + 4 <= pkt->size && MKBETAG('V','B','R','I') == AV_RB32(pkt->data + base)) + return 0; +#endif + + if (mp3->frames_offset) + mp3_xing_add_frame(s, pkt); + + return ff_raw_write_packet(s, pkt); + } +} + +static int mp3_write_trailer(AVFormatContext *s) +{ + MP3Context *mp3 = s->priv_data; + int ret=mp2_write_trailer(s); + + if (ret < 0) + return ret; + + if (mp3->frames_offset) + mp3_fix_xing(s); + + return 0; +} + AVOutputFormat ff_mp3_muxer = { .name = "mp3", .long_name = NULL_IF_CONFIG_SMALL("MPEG audio layer 3"), @@ -206,7 +371,7 @@ AVOutputFormat ff_mp3_muxer = { .audio_codec = CODEC_ID_MP3, .video_codec = CODEC_ID_NONE, .write_header = mp3_write_header, - .write_packet = ff_raw_write_packet, + .write_packet = mp3_write_packet, .write_trailer = mp3_write_trailer, .flags = AVFMT_NOTIMESTAMPS, .priv_class = &mp3_muxer_class, diff --git a/libavformat/mpc.c b/libavformat/mpc.c index 86e6f8e5b8..d929286ddd 100644 --- a/libavformat/mpc.c +++ b/libavformat/mpc.c @@ -2,20 +2,20 @@ * Musepack demuxer * Copyright (c) 2006 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 */ diff --git a/libavformat/mpc8.c b/libavformat/mpc8.c index 3c51ccd037..a711369414 100644 --- a/libavformat/mpc8.c +++ b/libavformat/mpc8.c @@ -2,20 +2,20 @@ * Musepack SV8 demuxer * Copyright (c) 2007 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 */ @@ -202,7 +202,7 @@ static int mpc8_read_header(AVFormatContext *s) return -1; } - while(!pb->eof_reached){ + while(!url_feof(pb)){ pos = avio_tell(pb); mpc8_get_chunk_header(pb, &tag, &size); if(tag == TAG_STREAMHDR) @@ -249,7 +249,7 @@ static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt) int tag; int64_t pos, size; - while(!s->pb->eof_reached){ + while(!url_feof(s->pb)){ pos = avio_tell(s->pb); mpc8_get_chunk_header(s->pb, &tag, &size); if (size < 0) @@ -275,7 +275,8 @@ static int mpc8_read_seek(AVFormatContext *s, int stream_index, int64_t timestam int index = av_index_search_timestamp(st, timestamp, flags); if(index < 0) return -1; - avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET); + if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0) + return -1; c->frame = st->index_entries[index].timestamp; return 0; } diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 6a26d6d292..be1c85d127 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -2,20 +2,20 @@ * MPEG1/2 demuxer * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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 */ @@ -74,6 +74,7 @@ static int mpegps_probe(AVProbeData *p) // and audio streams else if((code & 0xe0) == AUDIO_ID && pes) {audio++; i+=len;} else if(code == PRIVATE_STREAM_1 && pes) {priv1++; i+=len;} + else if(code == 0x1fd && pes) vid++; //VC1 else if((code & 0xf0) == VIDEO_ID && !pes) invalid++; else if((code & 0xe0) == AUDIO_ID && !pes) invalid++; @@ -81,7 +82,7 @@ static int mpegps_probe(AVProbeData *p) } } - if(vid+audio > invalid) /* invalid VDR files nd short PES streams */ + if(vid+audio > invalid+1) /* invalid VDR files nd short PES streams */ score= AVPROBE_SCORE_MAX/4; //av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d %d len:%d\n", sys, priv1, pspack,vid, audio, invalid, p->buf_size); @@ -109,6 +110,7 @@ static int mpegps_read_header(AVFormatContext *s) MpegDemuxContext *m = s->priv_data; const char *sofdec = "Sofdec"; int v, i = 0; + int64_t last_pos = avio_tell(s->pb); m->header_state = 0xff; s->ctx_flags |= AVFMTCTX_NOHEADER; @@ -116,12 +118,14 @@ static int mpegps_read_header(AVFormatContext *s) m->sofdec = -1; do { v = avio_r8(s->pb); - m->header_state = m->header_state << 8 | v; m->sofdec++; } while (v == sofdec[i] && i++ < 6); m->sofdec = (m->sofdec == 6) ? 1 : 0; + if (!m->sofdec) + avio_seek(s->pb, last_pos, SEEK_SET); + /* no need to do more */ return 0; } @@ -145,7 +149,7 @@ static int find_next_start_code(AVIOContext *pb, int *size_ptr, state = *header_state; n = *size_ptr; while (n > 0) { - if (pb->eof_reached) + if (url_feof(pb)) break; v = avio_r8(pb); n--; @@ -255,7 +259,7 @@ static int mpegps_read_pes_header(AVFormatContext *s, last_sync = avio_tell(s->pb); //printf("startcode=%x pos=0x%"PRIx64"\n", startcode, avio_tell(s->pb)); if (startcode < 0){ - if(s->pb->eof_reached) + if(url_feof(s->pb)) return AVERROR_EOF; //FIXME we should remember header_state return AVERROR(EAGAIN); @@ -423,6 +427,7 @@ static int mpegps_read_packet(AVFormatContext *s, MpegDemuxContext *m = s->priv_data; AVStream *st; int len, startcode, i, es_type, ret; + int request_probe= 0; enum CodecID codec_id = CODEC_ID_NONE; enum AVMediaType type; int64_t pts, dts, dummy_pos; //dummy_pos is needed for the index building to work @@ -481,7 +486,7 @@ static int mpegps_read_packet(AVFormatContext *s, if(!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1)) codec_id = CODEC_ID_CAVS; else - codec_id = CODEC_ID_PROBE; + request_probe= 1; type = AVMEDIA_TYPE_VIDEO; } else if (startcode >= 0x1c0 && startcode <= 0x1df) { type = AVMEDIA_TYPE_AUDIO; @@ -537,6 +542,7 @@ static int mpegps_read_packet(AVFormatContext *s, st->id = startcode; st->codec->codec_type = type; st->codec->codec_id = codec_id; + st->request_probe = request_probe; if (codec_id != CODEC_ID_PCM_S16BE) st->need_parsing = AVSTREAM_PARSE_FULL; found: diff --git a/libavformat/mpeg.h b/libavformat/mpeg.h index 75dddf346b..ca019c9eb2 100644 --- a/libavformat/mpeg.h +++ b/libavformat/mpeg.h @@ -2,20 +2,20 @@ * MPEG1/2 muxer and demuxer common defines * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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/libavformat/mpegenc.c b/libavformat/mpegenc.c index 852b3f13c9..098e076016 100644 --- a/libavformat/mpegenc.c +++ b/libavformat/mpegenc.c @@ -2,20 +2,20 @@ * MPEG1/2 muxer * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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 */ @@ -923,7 +923,7 @@ static int flush_packet(AVFormatContext *ctx, int stream_index, /* output data */ assert(payload_size - stuffing_size <= av_fifo_size(stream->fifo)); - av_fifo_generic_read(stream->fifo, ctx->pb, payload_size - stuffing_size, &avio_write); + av_fifo_generic_read(stream->fifo, ctx->pb, payload_size - stuffing_size, (void*)avio_write); stream->bytes_to_iframe -= payload_size - stuffing_size; }else{ payload_size= @@ -1042,7 +1042,7 @@ retry: StreamInfo *stream = st->priv_data; const int avail_data= av_fifo_size(stream->fifo); const int space= stream->max_buffer_size - stream->buffer_index; - int rel_space= 1024*space / stream->max_buffer_size; + int rel_space= 1024LL*space / stream->max_buffer_size; PacketDesc *next_pkt= stream->premux_packet; /* for subtitle, a single PES packet must be generated, diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index b105d8c108..81649c7cb6 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2,20 +2,20 @@ * MPEG2 transport stream (aka DVB) demuxer * Copyright (c) 2002-2003 Fabrice Bellard * - * 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 */ @@ -27,6 +27,7 @@ #include "libavutil/dict.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" +#include "libavutil/avassert.h" #include "libavcodec/bytestream.h" #include "libavcodec/get_bits.h" #include "avformat.h" @@ -227,6 +228,17 @@ static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned i p->pids[p->nb_pids++] = pid; } +static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid) +{ + int i; + for(i=0; i<s->nb_programs; i++) { + if(s->programs[i]->id == programid) { + s->programs[i]->pcr_pid = pid; + break; + } + } +} + /** * @brief discard_pid() decides if the pid is to be discarded according * to caller's programs selection @@ -387,7 +399,7 @@ static int analyze(const uint8_t *buf, int size, int packet_size, int *index){ memset(stat, 0, packet_size*sizeof(int)); for(x=i=0; i<size-3; i++){ - if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30)){ + if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && buf[i+3] != 0x47){ stat[x]++; if(stat[x] > best_score){ best_score= stat[x]; @@ -521,7 +533,9 @@ static const StreamType ISO_types[] = { { 0x04, AVMEDIA_TYPE_AUDIO, CODEC_ID_MP3 }, { 0x0f, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC }, { 0x10, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG4 }, - { 0x11, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC_LATM }, /* LATM syntax */ + /* Makito encoder sets stream type 0x11 for AAC, + * so auto-detect LOAS/LATM instead of hardcoding it. */ +// { 0x11, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC_LATM }, /* LATM syntax */ { 0x1b, AVMEDIA_TYPE_VIDEO, CODEC_ID_H264 }, { 0xd1, AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC }, { 0xea, AVMEDIA_TYPE_VIDEO, CODEC_ID_VC1 }, @@ -534,6 +548,10 @@ static const StreamType HDMV_types[] = { { 0x82, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, { 0x83, AVMEDIA_TYPE_AUDIO, CODEC_ID_TRUEHD }, { 0x84, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, + { 0x85, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS HD */ + { 0x86, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS HD MASTER*/ + { 0xa1, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */ + { 0xa2, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS Express Secondary Audio */ { 0x90, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_HDMV_PGS_SUBTITLE }, { 0 }, }; @@ -549,6 +567,10 @@ static const StreamType REGD_types[] = { { MKTAG('d','r','a','c'), AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC }, { MKTAG('A','C','-','3'), AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 }, { MKTAG('B','S','S','D'), AVMEDIA_TYPE_AUDIO, CODEC_ID_S302M }, + { MKTAG('D','T','S','1'), AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, + { MKTAG('D','T','S','2'), AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, + { MKTAG('D','T','S','3'), AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, + { MKTAG('V','C','-','1'), AVMEDIA_TYPE_VIDEO, CODEC_ID_VC1 }, { 0 }, }; @@ -569,6 +591,7 @@ static void mpegts_find_stream_type(AVStream *st, if (stream_type == types->stream_type) { st->codec->codec_type = types->codec_type; st->codec->codec_id = types->codec_id; + st->request_probe = 0; return; } } @@ -577,6 +600,8 @@ static void mpegts_find_stream_type(AVStream *st, static int mpegts_set_stream_info(AVStream *st, PESContext *pes, uint32_t stream_type, uint32_t prog_reg_desc) { + int old_codec_type= st->codec->codec_type; + int old_codec_id = st->codec->codec_id; avpriv_set_pts_info(st, 33, 1, 90000); st->priv_data = pes; st->codec->codec_type = AVMEDIA_TYPE_DATA; @@ -592,7 +617,8 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes, st->codec->codec_tag = pes->stream_type; mpegts_find_stream_type(st, pes->stream_type, ISO_types); - if (prog_reg_desc == AV_RL32("HDMV") && + if ((prog_reg_desc == AV_RL32("HDMV") || + prog_reg_desc == AV_RL32("HDPR")) && st->codec->codec_id == CODEC_ID_NONE) { mpegts_find_stream_type(st, pes->stream_type, HDMV_types); if (pes->stream_type == 0x83) { @@ -622,6 +648,10 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes, } if (st->codec->codec_id == CODEC_ID_NONE) mpegts_find_stream_type(st, pes->stream_type, MISC_types); + if (st->codec->codec_id == CODEC_ID_NONE){ + st->codec->codec_id = old_codec_id; + st->codec->codec_type= old_codec_type; + } return 0; } @@ -809,10 +839,10 @@ static int mpegts_push_data(MpegTSFilter *filter, code != 0x1ff && code != 0x1f2 && /* program_stream_directory, DSMCC_stream */ code != 0x1f8) { /* ITU-T Rec. H.222.1 type E stream */ pes->state = MPEGTS_PESHEADER; - if (pes->st->codec->codec_id == CODEC_ID_NONE) { + if (pes->st->codec->codec_id == CODEC_ID_NONE && !pes->st->request_probe) { av_dlog(pes->stream, "pid=%x stream_type=%x probing\n", pes->pid, pes->stream_type); - pes->st->codec->codec_id = CODEC_ID_PROBE; + pes->st->request_probe= 1; } } else { pes->state = MPEGTS_PAYLOAD; @@ -1282,15 +1312,17 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type break; case 0x1F: /* FMC descriptor */ get16(pp, desc_end); - if (mp4_descr_count > 0 && st->codec->codec_id == CODEC_ID_AAC_LATM && + if (mp4_descr_count > 0 && (st->codec->codec_id == CODEC_ID_AAC_LATM || st->request_probe>0) && mp4_descr->dec_config_descr_len && mp4_descr->es_id == pid) { AVIOContext pb; ffio_init_context(&pb, mp4_descr->dec_config_descr, mp4_descr->dec_config_descr_len, 0, NULL, NULL, NULL, NULL); ff_mp4_read_dec_config_descr(fc, st, &pb); if (st->codec->codec_id == CODEC_ID_AAC && - st->codec->extradata_size > 0) - st->need_parsing = 0; + st->codec->extradata_size > 0){ + st->request_probe= st->need_parsing = 0; + st->codec->codec_type= AVMEDIA_TYPE_AUDIO; + } } break; case 0x56: /* DVB teletext descriptor */ @@ -1353,6 +1385,9 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type stream_type == STREAM_TYPE_PRIVATE_DATA) mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types); break; + case 0x52: /* stream identifier descriptor */ + st->stream_identifier = 1 + get8(pp, desc_end); + break; default: break; } @@ -1394,6 +1429,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (pcr_pid < 0) return; add_pid_to_pmt(ts, h->id, pcr_pid); + set_pcr_pid(ts->stream, h->id, pcr_pid); av_dlog(ts->stream, "pcr_pid=0x%x\n", pcr_pid); @@ -1429,7 +1465,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len // stop parsing after pmt, we found header if (!ts->stream->nb_streams) - ts->stop_parse = 1; + ts->stop_parse = 2; for(;;) { st = 0; @@ -1507,6 +1543,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len SectionHeader h1, *h = &h1; const uint8_t *p, *p_end; int sid, pmt_pid; + AVProgram *program; av_dlog(ts->stream, "PAT:\n"); hex_dump_debug(ts->stream, (uint8_t *)section, section_len); @@ -1518,6 +1555,8 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (h->tid != PAT_TID) return; + ts->stream->ts_id = h->id; + clear_programs(ts); for(;;) { sid = get16(&p, p_end); @@ -1532,7 +1571,9 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (sid == 0x0000) { /* NIT info */ } else { - av_new_program(ts->stream, sid); + 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); @@ -1660,7 +1701,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) tss->last_cc = cc; if (!cc_ok) { - av_log(ts->stream, AV_LOG_WARNING, + av_log(ts->stream, AV_LOG_DEBUG, "Continuity check failed for pid %d expected %d got %d\n", pid, expected_cc, cc); if(tss->type == MPEGTS_PES) { @@ -1729,7 +1770,7 @@ static int mpegts_resync(AVFormatContext *s) for(i = 0;i < MAX_RESYNC_SIZE; i++) { c = avio_r8(pb); - if (pb->eof_reached) + if (url_feof(pb)) return -1; if (c == 0x47) { avio_seek(pb, -1, SEEK_CUR); @@ -1795,11 +1836,15 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) ts->stop_parse = 0; packet_num = 0; for(;;) { - if (ts->stop_parse>0) - break; packet_num++; - if (nb_packets != 0 && packet_num >= nb_packets) + if (nb_packets != 0 && packet_num >= nb_packets || + ts->stop_parse > 1) { + ret = AVERROR(EAGAIN); + break; + } + if (ts->stop_parse > 0) break; + ret = read_packet(s, packet, ts->raw_packet_size); if (ret != 0) break; @@ -1874,18 +1919,20 @@ static int mpegts_read_header(AVFormatContext *s) { MpegTSContext *ts = s->priv_data; AVIOContext *pb = s->pb; - uint8_t buf[5*1024]; + uint8_t buf[8*1024]; int len; int64_t pos; - /* read the first 1024 bytes to get packet size */ + /* read the first 8192 bytes to get packet size */ pos = avio_tell(pb); len = avio_read(pb, buf, sizeof(buf)); if (len != sizeof(buf)) goto fail; ts->raw_packet_size = get_packet_size(buf, sizeof(buf)); - if (ts->raw_packet_size <= 0) - goto fail; + if (ts->raw_packet_size <= 0) { + av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n"); + ts->raw_packet_size = TS_PACKET_SIZE; + } ts->stream = s; ts->auto_guess = 0; @@ -1893,8 +1940,11 @@ static int mpegts_read_header(AVFormatContext *s) /* normal demux */ /* first do a scan to get all the services */ - if (pb->seekable && avio_seek(pb, pos, SEEK_SET) < 0) - av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n"); + /* 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"); mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); @@ -2054,36 +2104,58 @@ static 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; - const int find_next= 1; pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47; - if (find_next) { - for(;;) { - avio_seek(s->pb, pos, SEEK_SET); - if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) + 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) { + if (mpegts_resync(s) < 0) return AV_NOPTS_VALUE; - if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) && - parse_pcr(×tamp, &pcr_l, buf) == 0) { - break; - } - pos += ts->raw_packet_size; + pos = avio_tell(s->pb); + continue; } - } else { - for(;;) { - pos -= ts->raw_packet_size; - if (pos < 0) - return AV_NOPTS_VALUE; - avio_seek(s->pb, pos, SEEK_SET); - if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) - return AV_NOPTS_VALUE; - if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) && - parse_pcr(×tamp, &pcr_l, buf) == 0) { - break; + if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) && + parse_pcr(×tamp, &pcr_l, buf) == 0) { + *ppos = pos; + return timestamp; + } + pos += ts->raw_packet_size; + } + + return AV_NOPTS_VALUE; +} + +static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index, + int64_t *ppos, int64_t pos_limit) +{ + 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; + ff_read_frame_flush(s); + if (avio_seek(s->pb, pos, SEEK_SET) < 0) + return AV_NOPTS_VALUE; + while(pos < pos_limit) { + int ret; + AVPacket pkt; + av_init_packet(&pkt); + ret= av_read_frame(s, &pkt); + if(ret < 0) + return AV_NOPTS_VALUE; + av_free_packet(&pkt); + 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){ + *ppos= pkt.pos; + return pkt.dts; } } + pos = pkt.pos; } - *ppos = pos; - return timestamp; + return AV_NOPTS_VALUE; } #ifdef USE_SYNCPOINT_SEARCH @@ -2170,31 +2242,6 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, in return ret; } -#else - -static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){ - MpegTSContext *ts = s->priv_data; - uint8_t buf[TS_PACKET_SIZE]; - int64_t pos; - - if (ff_seek_frame_binary(s, stream_index, target_ts, flags) < 0) - return -1; - - pos= avio_tell(s->pb); - - for(;;) { - avio_seek(s->pb, pos, SEEK_SET); - if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) - return -1; -// pid = AV_RB16(buf + 1) & 0x1fff; - if(buf[1] & 0x40) break; - pos += ts->raw_packet_size; - } - avio_seek(s->pb, pos, SEEK_SET); - - return 0; -} - #endif /**************************************************************/ @@ -2211,6 +2258,9 @@ MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s) ts->raw_packet_size = TS_PACKET_SIZE; ts->stream = s; ts->auto_guess = 1; + mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); + mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1); + return ts; } @@ -2223,10 +2273,8 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, len1 = len; ts->pkt = pkt; - ts->stop_parse = 0; for(;;) { - if (ts->stop_parse>0) - break; + ts->stop_parse = 0; if (len < TS_PACKET_SIZE) return -1; if (buf[0] != 0x47) { @@ -2236,6 +2284,8 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, handle_packet(ts, buf); buf += TS_PACKET_SIZE; len -= TS_PACKET_SIZE; + if (ts->stop_parse == 1) + break; } } return len1 - len; @@ -2258,8 +2308,7 @@ AVInputFormat ff_mpegts_demuxer = { .read_header = mpegts_read_header, .read_packet = mpegts_read_packet, .read_close = mpegts_read_close, - .read_seek = read_seek, - .read_timestamp = mpegts_get_pcr, + .read_timestamp = mpegts_get_dts, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, #ifdef USE_SYNCPOINT_SEARCH .read_seek2 = read_seek2, @@ -2273,8 +2322,7 @@ AVInputFormat ff_mpegtsraw_demuxer = { .read_header = mpegts_read_header, .read_packet = mpegts_raw_read_packet, .read_close = mpegts_read_close, - .read_seek = read_seek, - .read_timestamp = mpegts_get_pcr, + .read_timestamp = mpegts_get_dts, .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT, #ifdef USE_SYNCPOINT_SEARCH .read_seek2 = read_seek2, diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h index e38f2e09a3..edec79ce2f 100644 --- a/libavformat/mpegts.h +++ b/libavformat/mpegts.h @@ -2,20 +2,20 @@ * MPEG2 transport stream defines * Copyright (c) 2003 Fabrice Bellard * - * 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/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index c05f7f690e..526545f697 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -2,20 +2,20 @@ * MPEG2 transport stream (aka DVB) muxer * Copyright (c) 2003 Fabrice Bellard * - * 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 */ @@ -24,6 +24,7 @@ #include "libavutil/dict.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" +#include "libavutil/avassert.h" #include "libavcodec/mpegvideo.h" #include "avformat.h" #include "internal.h" @@ -76,6 +77,7 @@ typedef struct MpegTSWrite { int pmt_start_pid; int start_pid; + int m2ts_mode; } MpegTSWrite; /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */ @@ -90,9 +92,12 @@ static const AVOption options[] = { { "mpegts_service_id", "Set service_id field.", offsetof(MpegTSWrite, service_id), AV_OPT_TYPE_INT, {.dbl = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM}, { "mpegts_pmt_start_pid", "Set the first pid of the PMT.", - offsetof(MpegTSWrite, pmt_start_pid), AV_OPT_TYPE_INT, {.dbl = 0x1000 }, 0x1000, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM}, + offsetof(MpegTSWrite, pmt_start_pid), AV_OPT_TYPE_INT, {.dbl = 0x1000 }, 0x0010, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM}, { "mpegts_start_pid", "Set the first pid.", offsetof(MpegTSWrite, start_pid), AV_OPT_TYPE_INT, {.dbl = 0x0100 }, 0x0100, 0x0f00, AV_OPT_FLAG_ENCODING_PARAM}, + {"mpegts_m2ts_mode", "Enable m2ts mode.", + offsetof(MpegTSWrite, m2ts_mode), AV_OPT_TYPE_INT, {.dbl = -1 }, + -1,1, AV_OPT_FLAG_ENCODING_PARAM}, { "muxrate", NULL, offsetof(MpegTSWrite, mux_rate), AV_OPT_TYPE_INT, {1}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, { "pes_payload_size", "Minimum PES packet payload in bytes", offsetof(MpegTSWrite, pes_payload_size), AV_OPT_TYPE_INT, {DEFAULT_PES_PAYLOAD_SIZE}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, @@ -174,7 +179,7 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id, tot_len = 3 + 5 + len + 4; /* check if not too big */ if (tot_len > 1024) - return -1; + return AVERROR_INVALIDDATA; q = section; *q++ = tid; @@ -192,7 +197,7 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id, /*********************************************/ /* mpegts writer */ -#define DEFAULT_PROVIDER_NAME "Libav" +#define DEFAULT_PROVIDER_NAME "FFmpeg" #define DEFAULT_SERVICE_NAME "Service01" /* we retransmit the SI info at this rate */ @@ -291,6 +296,12 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) /* write optional descriptors here */ switch(st->codec->codec_type) { case AVMEDIA_TYPE_AUDIO: + if(st->codec->codec_id==CODEC_ID_EAC3){ + *q++=0x7a; // EAC3 descriptor see A038 DVB SI + *q++=1; // 1 byte, all flags sets to 0 + *q++=0; // omit all fields... + } + if (lang) { char *p; char *next = lang->value; @@ -438,9 +449,28 @@ static MpegTSService *mpegts_add_service(MpegTSWrite *ts, return service; } +static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb) +{ + return av_rescale(avio_tell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) + + ts->first_pcr; +} + +static void mpegts_prefix_m2ts_header(AVFormatContext *s) +{ + MpegTSWrite *ts = s->priv_data; + if (ts->m2ts_mode) { + int64_t pcr = get_pcr(s->priv_data, s->pb); + uint32_t tp_extra_header = pcr % 0x3fffffff; + tp_extra_header = AV_RB32(&tp_extra_header); + avio_write(s->pb, (unsigned char *) &tp_extra_header, + sizeof(tp_extra_header)); + } +} + static void section_write_packet(MpegTSSection *s, const uint8_t *packet) { AVFormatContext *ctx = s->opaque; + mpegts_prefix_m2ts_header(ctx); avio_write(ctx->pb, packet, TS_PACKET_SIZE); } @@ -592,6 +622,14 @@ static int mpegts_write_header(AVFormatContext *s) service->pcr_packet_period, ts->sdt_packet_period, ts->pat_packet_period); + if (ts->m2ts_mode == -1) { + if (av_match_ext(s->filename, "m2ts")) { + ts->m2ts_mode = 1; + } else { + ts->m2ts_mode = 0; + } + } + avio_flush(s->pb); return 0; @@ -608,7 +646,7 @@ static int mpegts_write_header(AVFormatContext *s) } av_freep(&st->priv_data); } - return -1; + return AVERROR(EINVAL); } /* send SDT, PAT and PMT tables regulary */ @@ -630,12 +668,6 @@ static void retransmit_si_info(AVFormatContext *s) } } -static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb) -{ - return av_rescale(avio_tell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) + - ts->first_pcr; -} - static int write_pcr_bits(uint8_t *buf, int64_t pcr) { int64_t pcr_low = pcr % 300, pcr_high = pcr / 300; @@ -662,6 +694,7 @@ static void mpegts_insert_null_packet(AVFormatContext *s) *q++ = 0xff; *q++ = 0x10; memset(q, 0x0FF, TS_PACKET_SIZE - (q - buf)); + mpegts_prefix_m2ts_header(s); avio_write(s->pb, buf, TS_PACKET_SIZE); } @@ -687,6 +720,7 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st) /* stuffing bytes */ memset(q, 0xFF, TS_PACKET_SIZE - (q - buf)); + mpegts_prefix_m2ts_header(s); avio_write(s->pb, buf, TS_PACKET_SIZE); } @@ -923,6 +957,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, memcpy(buf + TS_PACKET_SIZE - len, payload, len); payload += len; payload_size -= len; + mpegts_prefix_m2ts_header(s); avio_write(s->pb, buf, TS_PACKET_SIZE); } avio_flush(s->pb); @@ -946,7 +981,7 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) if (ts_st->first_pts_check && pts == AV_NOPTS_VALUE) { av_log(s, AV_LOG_ERROR, "first pts value must set\n"); - return -1; + return AVERROR_INVALIDDATA; } ts_st->first_pts_check = 0; @@ -956,8 +991,8 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) { av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, " - "no startcode found, use -vbsf h264_mp4toannexb\n"); - return -1; + "no startcode found, use the h264_mp4toannexb bitstream filter\n"); + return AVERROR_INVALIDDATA; } do { @@ -969,7 +1004,7 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) if ((state & 0x1f) != 9) { // AUD NAL data = av_malloc(pkt->size+6); if (!data) - return -1; + return AVERROR(ENOMEM); memcpy(data+6, pkt->data, pkt->size); AV_WB32(data, 0x00000001); data[4] = 0x09; @@ -979,18 +1014,18 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) } } else if (st->codec->codec_id == CODEC_ID_AAC) { if (pkt->size < 2) - return -1; + return AVERROR_INVALIDDATA; if ((AV_RB16(pkt->data) & 0xfff0) != 0xfff0) { ADTSContext *adts = ts_st->adts; int new_size, err; if (!adts) { - av_log(s, AV_LOG_ERROR, "aac bitstream not in adts format " + av_log(s, AV_LOG_ERROR, "AAC bitstream not in ADTS format " "and extradata missing\n"); - return -1; + return AVERROR_INVALIDDATA; } new_size = ADTS_HEADER_SIZE+adts->pce_size+pkt->size; if ((unsigned)new_size >= INT_MAX) - return -1; + return AVERROR_INVALIDDATA; data = av_malloc(new_size); if (!data) return AVERROR(ENOMEM); @@ -1010,28 +1045,21 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) } } - if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) { + if (ts_st->payload_size && ts_st->payload_size + size > ts->pes_payload_size) { + mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size, + ts_st->payload_pts, ts_st->payload_dts, + ts_st->payload_flags & AV_PKT_FLAG_KEY); + ts_st->payload_size = 0; + } + + if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO || size > ts->pes_payload_size) { + av_assert0(!ts_st->payload_size); // for video and subtitle, write a single pes packet mpegts_write_pes(s, st, buf, size, pts, dts, pkt->flags & AV_PKT_FLAG_KEY); av_free(data); return 0; } - if (ts_st->payload_size + size > ts->pes_payload_size) { - if (ts_st->payload_size) { - mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size, - ts_st->payload_pts, ts_st->payload_dts, - ts_st->payload_flags & AV_PKT_FLAG_KEY); - ts_st->payload_size = 0; - } - if (size > ts->pes_payload_size) { - mpegts_write_pes(s, st, buf, size, pts, dts, - pkt->flags & AV_PKT_FLAG_KEY); - av_free(data); - return 0; - } - } - if (!ts_st->payload_size) { ts_st->payload_pts = pts; ts_st->payload_dts = dts; @@ -1083,7 +1111,7 @@ AVOutputFormat ff_mpegts_muxer = { .name = "mpegts", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"), .mime_type = "video/x-mpegts", - .extensions = "ts,m2t", + .extensions = "ts,m2t,m2ts,mts", .priv_data_size = sizeof(MpegTSWrite), .audio_codec = CODEC_ID_MP2, .video_codec = CODEC_ID_MPEG2VIDEO, diff --git a/libavformat/mpegvideodec.c b/libavformat/mpegvideodec.c index 9fea117632..11e4bd70e8 100644 --- a/libavformat/mpegvideodec.c +++ b/libavformat/mpegvideodec.c @@ -3,20 +3,20 @@ * Copyright (c) 2002-2003 Fabrice Bellard * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> * - * 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 */ @@ -34,7 +34,7 @@ static int mpegvideo_probe(AVProbeData *p) { uint32_t code= -1; - int pic=0, seq=0, slice=0, pspack=0, pes=0; + int pic=0, seq=0, slice=0, pspack=0, vpes=0, apes=0; int i; for(i=0; i<p->buf_size; i++){ @@ -43,15 +43,16 @@ static int mpegvideo_probe(AVProbeData *p) switch(code){ case SEQ_START_CODE: seq++; break; case PICTURE_START_CODE: pic++; break; - case SLICE_START_CODE: slice++; break; case PACK_START_CODE: pspack++; break; } - if ((code & 0x1f0) == VIDEO_ID) pes++; - else if((code & 0x1e0) == AUDIO_ID) pes++; + if (code >= SLICE_START_CODE && code <= 0x1af) slice++; + if ((code & 0x1f0) == VIDEO_ID) vpes++; + else if((code & 0x1e0) == AUDIO_ID) apes++; } } - if(seq && seq*9<=pic*10 && pic*9<=slice*10 && !pspack && !pes) - return pic>1 ? AVPROBE_SCORE_MAX/2+1 : AVPROBE_SCORE_MAX/4; // +1 for .mpg + if(seq && seq*9<=pic*10 && pic*9<=slice*10 && !pspack && !apes) + if(vpes) return AVPROBE_SCORE_MAX/8; + else return pic>1 ? AVPROBE_SCORE_MAX/2+1 : AVPROBE_SCORE_MAX/4; // +1 for .mpg return 0; } diff --git a/libavformat/mpjpeg.c b/libavformat/mpjpeg.c index 79cc272e27..46a98b3d44 100644 --- a/libavformat/mpjpeg.c +++ b/libavformat/mpjpeg.c @@ -2,27 +2,27 @@ * Multipart JPEG format * Copyright (c) 2000, 2001, 2002, 2003 Fabrice Bellard * - * 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" /* Multipart JPEG */ -#define BOUNDARY_TAG "avserver" +#define BOUNDARY_TAG "ffserver" static int mpjpeg_write_header(AVFormatContext *s) { diff --git a/libavformat/msnwc_tcp.c b/libavformat/msnwc_tcp.c index 9c0c3c79f4..f8a631e311 100644 --- a/libavformat/msnwc_tcp.c +++ b/libavformat/msnwc_tcp.c @@ -1,20 +1,20 @@ /* * Copyright (C) 2008 Ramiro Polla * - * 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 */ @@ -89,9 +89,9 @@ static int msnwc_tcp_read_header(AVFormatContext *ctx) /* Some files start with "connected\r\n\r\n". * So skip until we find the first byte of struct size */ - while(avio_r8(pb) != HEADER_SIZE && !pb->eof_reached); + while(avio_r8(pb) != HEADER_SIZE && !url_feof(pb)); - if(pb->eof_reached) { + if(url_feof(pb)) { av_log(ctx, AV_LOG_ERROR, "Could not find valid start."); return -1; } diff --git a/libavformat/mtv.c b/libavformat/mtv.c index 2af9c2dd56..19b7793bae 100644 --- a/libavformat/mtv.c +++ b/libavformat/mtv.c @@ -2,20 +2,20 @@ * mtv demuxer * Copyright (c) 2006 Reynaldo H. Verdejo Pinochet * - * 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 */ @@ -96,13 +96,19 @@ static int mtv_read_header(AVFormatContext *s) /* Calculate width and height if missing from header */ - if(!mtv->img_width) + if(mtv->img_bpp>>3){ + if(!mtv->img_width && mtv->img_height) mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3) / mtv->img_height; - if(!mtv->img_height) + if(!mtv->img_height && mtv->img_width) 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"); + return AVERROR(EINVAL); + } avio_skip(pb, 4); audio_subsegments = avio_rl16(pb); @@ -192,7 +198,7 @@ static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) * just swap bytes as they come */ - for(i=0;i<mtv->img_segment_size/2;i++) + for(i=0;i<ret/2;i++) *((uint16_t *)pkt->data+i) = av_bswap16(*((uint16_t *)pkt->data+i)); #endif pkt->stream_index = 0; diff --git a/libavformat/mvi.c b/libavformat/mvi.c index 6e937b2acd..a5a69ac19a 100644 --- a/libavformat/mvi.c +++ b/libavformat/mvi.c @@ -2,20 +2,20 @@ * Motion Pixels MVI Demuxer * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net) * - * 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/libavformat/mxf.c b/libavformat/mxf.c index e4d9fbd542..b39a9b64cc 100644 --- a/libavformat/mxf.c +++ b/libavformat/mxf.c @@ -2,20 +2,20 @@ * MXF * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot 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 */ diff --git a/libavformat/mxf.h b/libavformat/mxf.h index beb66281ab..4f5d4c0d95 100644 --- a/libavformat/mxf.h +++ b/libavformat/mxf.h @@ -2,20 +2,20 @@ * MXF * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot 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 */ #ifndef AVFORMAT_MXF_H diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 96b662f431..c9278692a3 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -2,20 +2,20 @@ * MXF demuxer. * Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot 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 */ @@ -59,7 +59,7 @@ typedef enum { } MXFPartitionType; typedef enum { - OP1a, + OP1a = 1, OP1b, OP1c, OP2a, @@ -69,7 +69,7 @@ typedef enum { OP3b, OP3c, OPAtom, - OPSonyOpt, /* FATE sample, violates the spec in places */ + OPSONYOpt, /* FATE sample, violates the spec in places */ } MXFOP; typedef struct { @@ -207,6 +207,7 @@ typedef struct { int current_edit_unit; int nb_index_tables; MXFIndexTable *index_tables; + int edit_units_per_packet; ///< how many edit units to read at a time (PCM, OPAtom) } MXFContext; enum MXFWrappingScheme { @@ -256,7 +257,7 @@ static int64_t klv_decode_ber_length(AVIOContext *pb) static int mxf_read_sync(AVIOContext *pb, const uint8_t *key, unsigned size) { int i, b; - for (i = 0; i < size && !pb->eof_reached; i++) { + for (i = 0; i < size && !url_feof(pb); i++) { b = avio_r8(pb); if (b == key[0]) i = 0; @@ -410,6 +411,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size MXFPartition *partition, *tmp_part; UID op; uint64_t footer_partition; + uint32_t nb_essence_containers; if (mxf->partitions_count+1 >= UINT_MAX / sizeof(*mxf->partitions)) return AVERROR(ENOMEM); @@ -464,6 +466,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size avio_skip(pb, 8); partition->body_sid = avio_rb32(pb); avio_read(pb, op, sizeof(UID)); + nb_essence_containers = avio_rb32(pb); /* some files don'thave FooterPartition set in every partition */ if (footer_partition) { @@ -484,6 +487,13 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size partition->previous_partition, footer_partition, partition->index_sid, partition->body_sid); + /* sanity check PreviousPartition if set */ + if (partition->previous_partition && + mxf->run_in + partition->previous_partition >= klv_offset) { + av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition points to this partition or forward\n"); + return AVERROR_INVALIDDATA; + } + if (op[12] == 1 && op[13] == 1) mxf->op = OP1a; else if (op[12] == 1 && op[13] == 2) mxf->op = OP1b; else if (op[12] == 1 && op[13] == 3) mxf->op = OP1c; @@ -493,9 +503,19 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size else if (op[12] == 3 && op[13] == 1) mxf->op = OP3a; else if (op[12] == 3 && op[13] == 2) mxf->op = OP3b; else if (op[12] == 3 && op[13] == 3) mxf->op = OP3c; - else if (op[12] == 0x10) mxf->op = OPAtom; - else if (op[12] == 64&& op[13] == 1) mxf->op = OPSonyOpt; - else { + else if (op[12] == 64&& op[13] == 1) mxf->op = OPSONYOpt; + else if (op[12] == 0x10) { + /* SMPTE 390m: "There shall be exactly one essence container" + * 2011_DCPTEST_24FPS.V.mxf violates this and is frame wrapped, hence why we assume OP1a */ + if (nb_essence_containers != 1) { + /* only nag once */ + if (!mxf->op) + av_log(mxf->fc, AV_LOG_WARNING, "\"OPAtom\" with %u ECs - assuming OP1a\n", nb_essence_containers); + + mxf->op = OP1a; + } else + mxf->op = OPAtom; + } else { av_log(mxf->fc, AV_LOG_ERROR, "unknown operational pattern: %02xh %02xh - guessing OP1a\n", op[12], op[13]); mxf->op = OP1a; } @@ -503,7 +523,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size if (partition->kag_size <= 0 || partition->kag_size > (1 << 20)) { av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %i - guessing ", partition->kag_size); - if (mxf->op == OPSonyOpt) + if (mxf->op == OPSONYOpt) partition->kag_size = 512; else partition->kag_size = 1; @@ -672,29 +692,12 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg int i, length; segment->nb_index_entries = avio_rb32(pb); - if (!segment->nb_index_entries) - return 0; - else if (segment->nb_index_entries < 0 || - segment->nb_index_entries > - (INT_MAX >> av_log2(sizeof(*segment->stream_offset_entries)))) - return AVERROR(ENOMEM); - length = avio_rb32(pb); - segment->temporal_offset_entries = av_mallocz(segment->nb_index_entries * - sizeof(*segment->temporal_offset_entries)); - segment->flag_entries = av_mallocz(segment->nb_index_entries * - sizeof(*segment->flag_entries)); - segment->stream_offset_entries = av_mallocz(segment->nb_index_entries * - sizeof(*segment->stream_offset_entries)); - - if (!segment->flag_entries || !segment->stream_offset_entries || - !segment->temporal_offset_entries) { - av_freep(&segment->flag_entries); - av_freep(&segment->stream_offset_entries); - av_freep(&segment->temporal_offset_entries); + if (!(segment->temporal_offset_entries=av_calloc(segment->nb_index_entries, sizeof(*segment->temporal_offset_entries))) || + !(segment->flag_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->flag_entries))) || + !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries)))) return AVERROR(ENOMEM); - } for (i = 0; i < segment->nb_index_entries; i++) { segment->temporal_offset_entries[i] = avio_r8(pb); @@ -890,9 +893,8 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment if (mxf->metadata_sets[i]->type == IndexTableSegment) nb_segments++; - *sorted_segments = av_mallocz(nb_segments * sizeof(**sorted_segments)); - unsorted_segments = av_mallocz(nb_segments * sizeof(*unsorted_segments)); - if (!sorted_segments || !unsorted_segments) { + if (!(unsorted_segments = av_calloc(nb_segments, sizeof(*unsorted_segments))) || + !(*sorted_segments = av_calloc(nb_segments, sizeof(**sorted_segments)))) { av_freep(sorted_segments); av_free(unsorted_segments); return AVERROR(ENOMEM); @@ -1048,8 +1050,10 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta for (i = 0; i < index_table->nb_segments; i++) { MXFIndexTableSegment *s = index_table->segments[i]; - if (!s->nb_index_entries) + if (!s->nb_index_entries) { + index_table->nb_ptses = 0; return 0; /* no TemporalOffsets */ + } index_table->nb_ptses += s->index_duration; } @@ -1058,14 +1062,8 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta if (index_table->nb_ptses <= 0) return 0; - if (index_table->nb_ptses > INT_MAX >> av_log2(sizeof(AVIndexEntry)) + 1) - return AVERROR(ENOMEM); - - index_table->ptses = av_mallocz(index_table->nb_ptses * - sizeof(int64_t)); - index_table->fake_index = av_mallocz(index_table->nb_ptses * - sizeof(AVIndexEntry)); - if (!index_table->ptses || !index_table->fake_index) { + if (!(index_table->ptses = av_calloc(index_table->nb_ptses, sizeof(int64_t))) || + !(index_table->fake_index = av_calloc(index_table->nb_ptses, sizeof(AVIndexEntry)))) { av_freep(&index_table->ptses); return AVERROR(ENOMEM); } @@ -1105,14 +1103,25 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta for (i = x = 0; i < index_table->nb_segments; i++) { MXFIndexTableSegment *s = index_table->segments[i]; int index_delta = 1; + int n = s->nb_index_entries; - if (s->nb_index_entries == 2 * s->index_duration + 1) + if (s->nb_index_entries == 2 * s->index_duration + 1) { index_delta = 2; /* Avid index */ - for (j = 0; j < s->nb_index_entries; j += index_delta, x++) { + /* ignore the last entry - it's the size of the essence container */ + n--; + } + + for (j = 0; j < n; j += index_delta, x++) { int offset = s->temporal_offset_entries[j] / index_delta; int index = x + offset; + if (x >= index_table->nb_ptses) { + av_log(mxf->fc, AV_LOG_ERROR, "x >= nb_ptses - IndexEntryCount %i < IndexDuration %"PRId64"?\n", + s->nb_index_entries, s->index_duration); + break; + } + index_table->fake_index[x].timestamp = x; index_table->fake_index[x].flags = !(s->flag_entries[j] & 0x30) ? AVINDEX_KEYFRAME : 0; @@ -1159,9 +1168,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) } } - if (mxf->nb_index_tables > INT_MAX >> av_log2(sizeof(MXFIndexTable)) + 1 || - !(mxf->index_tables = av_mallocz(mxf->nb_index_tables * - sizeof(MXFIndexTable)))) { + if (!(mxf->index_tables = av_calloc(mxf->nb_index_tables, sizeof(MXFIndexTable)))) { av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n"); ret = AVERROR(ENOMEM); goto finish_decoding_index; @@ -1180,12 +1187,8 @@ static int mxf_compute_index_tables(MXFContext *mxf) for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { MXFIndexTable *t = &mxf->index_tables[j]; - if (t->nb_segments > - (INT_MAX >> av_log2(sizeof(MXFIndexTableSegment *))) || - !(t->segments = av_mallocz(t->nb_segments * - sizeof(MXFIndexTableSegment*)))) { - av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment" - " pointer array\n"); + if (!(t->segments = av_calloc(t->nb_segments, sizeof(MXFIndexTableSegment*)))) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment pointer array\n"); ret = AVERROR(ENOMEM); goto finish_decoding_index; } @@ -1304,7 +1307,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) break; } } - if (!source_track) + if (!source_track || !component) continue; if (!(source_track->sequence = mxf_resolve_strong_ref(mxf, &source_track->sequence_ref, Sequence))) { @@ -1398,6 +1401,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->codec_id = container_ul->id; st->codec->channels = descriptor->channels; st->codec->bits_per_coded_sample = descriptor->bits_per_sample; + if (descriptor->sample_rate.den > 0) st->codec->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den; /* TODO: implement CODEC_ID_RAWAUDIO */ if (st->codec->codec_id == CODEC_ID_PCM_S16LE) { @@ -1464,7 +1468,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (!ctx) return AVERROR(ENOMEM); - while (avio_tell(pb) + 4 < klv_end) { + while (avio_tell(pb) + 4 < klv_end && !url_feof(pb)) { int ret; int tag = avio_rb16(pb); int size = avio_rb16(pb); /* KLV specified by 0x53 */ @@ -1492,6 +1496,13 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0) return ret; + /* accept the 64k local set limit being exceeded (Avid) + * don't accept it extending past the end of the KLV though (zzuf5.mxf) */ + if (avio_tell(pb) > klv_end) { + av_log(mxf->fc, AV_LOG_ERROR, "local tag %#04x extends past end of local set @ %#"PRIx64"\n", + tag, klv->offset); + return AVERROR_INVALIDDATA; + } else if (avio_tell(pb) <= next) /* only seek forward, else this can loop for a long time */ avio_seek(pb, next, SEEK_SET); } if (ctx_size) ctx->type = type; @@ -1528,11 +1539,6 @@ static int mxf_parse_handle_essence(MXFContext *mxf) AVIOContext *pb = mxf->fc->pb; int64_t ret; - if (!mxf->current_partition) { - av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to PartitionPack\n"); - return AVERROR_INVALIDDATA; - } - if (mxf->parsing_backward) { return mxf_seek_to_previous_partition(mxf); } else { @@ -1575,8 +1581,7 @@ static int mxf_parse_handle_partition_or_eof(MXFContext *mxf) } /** - * Figure out the proper offset and length of the essence container - * in each partition + * Figures out the proper offset and length of the essence container in each partition */ static void mxf_compute_essence_containers(MXFContext *mxf) { @@ -1616,36 +1621,36 @@ static int64_t round_to_kag(int64_t position, int kag_size) return ret == position ? ret : ret + kag_size; } -static inline void compute_partition_essence_offset(AVFormatContext *s, - MXFContext *mxf, - KLVPacket *klv) +static int is_pcm(enum CodecID codec_id) { - MXFPartition *cur_part = mxf->current_partition; - /* for OP1a we compute essence_offset - * for OPAtom we point essence_offset after the KL - * (usually op1a_essence_offset + 20 or 25) - * TODO: for OP1a we could eliminate this entire if statement, always - * stopping parsing at op1a_essence_offset - * for OPAtom we still need the actual essence_offset though - * (the KL's length can vary) - */ - int64_t op1a_essence_offset = - round_to_kag(cur_part->this_partition + cur_part->pack_length, - cur_part->kag_size) + - round_to_kag(cur_part->header_byte_count, cur_part->kag_size) + - round_to_kag(cur_part->index_byte_count, cur_part->kag_size); - - if (mxf->op == OPAtom) { - /* point essence_offset to the actual data - * OPAtom has all the essence in one big KLV - */ - cur_part->essence_offset = avio_tell(s->pb); - cur_part->essence_length = klv->length; - } else { - /* NOTE: op1a_essence_offset may be less than to klv.offset - * (C0023S01.mxf) */ - cur_part->essence_offset = op1a_essence_offset; - } + /* we only care about "normal" PCM codecs until we get samples */ + return codec_id >= CODEC_ID_PCM_S16LE && codec_id < CODEC_ID_PCM_S24DAUD; +} + +/** + * Deals with the case where for some audio atoms EditUnitByteCount is very small (2, 4..). + * In those cases we should read more than one sample per call to mxf_read_packet(). + */ +static void mxf_handle_small_eubc(AVFormatContext *s) +{ + MXFContext *mxf = s->priv_data; + + /* assuming non-OPAtom == frame wrapped + * no sane writer would wrap 2 byte PCM packets with 20 byte headers.. */ + if (mxf->op != OPAtom) + return; + + /* expect PCM with exactly one index table segment and a small (< 32) EUBC */ + if (s->nb_streams != 1 || s->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO || + !is_pcm(s->streams[0]->codec->codec_id) || mxf->nb_index_tables != 1 || + mxf->index_tables[0].nb_segments != 1 || + mxf->index_tables[0].segments[0]->edit_unit_byte_count >= 32) + return; + + /* arbitrarily default to 48 kHz PAL audio frame size */ + /* TODO: we could compute this from the ratio between the audio and video edit rates + * for 48 kHz NTSC we could use the 1802-1802-1802-1802-1801 pattern */ + mxf->edit_units_per_packet = 1920; } static int mxf_read_header(AVFormatContext *s) @@ -1656,6 +1661,7 @@ static int mxf_read_header(AVFormatContext *s) int ret; mxf->last_forward_tell = INT64_MAX; + mxf->edit_units_per_packet = 1; if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) { av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n"); @@ -1665,7 +1671,7 @@ static int mxf_read_header(AVFormatContext *s) mxf->fc = s; mxf->run_in = avio_tell(s->pb); - while (!s->pb->eof_reached) { + while (!url_feof(s->pb)) { const MXFMetadataReadTableEntry *metadata; if (klv_read_packet(&klv, s->pb) < 0) { @@ -1682,8 +1688,34 @@ static int mxf_read_header(AVFormatContext *s) IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) || IS_KLV_KEY(klv.key, mxf_system_item_key)) { + + if (!mxf->current_partition) { + av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n"); + return AVERROR_INVALIDDATA; + } + if (!mxf->current_partition->essence_offset) { - compute_partition_essence_offset(s, mxf, &klv); + /* for OP1a we compute essence_offset + * for OPAtom we point essence_offset after the KL (usually op1a_essence_offset + 20 or 25) + * TODO: for OP1a we could eliminate this entire if statement, always stopping parsing at op1a_essence_offset + * for OPAtom we still need the actual essence_offset though (the KL's length can vary) + */ + int64_t op1a_essence_offset = + round_to_kag(mxf->current_partition->this_partition + + mxf->current_partition->pack_length, mxf->current_partition->kag_size) + + round_to_kag(mxf->current_partition->header_byte_count, mxf->current_partition->kag_size) + + round_to_kag(mxf->current_partition->index_byte_count, mxf->current_partition->kag_size); + + if (mxf->op == OPAtom) { + /* point essence_offset to the actual data + * OPAtom has all the essence in one big KLV + */ + mxf->current_partition->essence_offset = avio_tell(s->pb); + mxf->current_partition->essence_length = klv.length; + } else { + /* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf) */ + mxf->current_partition->essence_offset = op1a_essence_offset; + } } if (!essence_offset) @@ -1708,6 +1740,14 @@ static int mxf_read_header(AVFormatContext *s) } else { uint64_t next = avio_tell(s->pb) + klv.length; res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset); + + /* only seek forward, else this can loop for a long time */ + if (avio_tell(s->pb) > next) { + av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n", + klv.offset); + return AVERROR_INVALIDDATA; + } + avio_seek(s->pb, next, SEEK_SET); } if (res < 0) { @@ -1746,6 +1786,8 @@ static int mxf_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } + mxf_handle_small_eubc(s); + return 0; } @@ -1754,21 +1796,33 @@ static int mxf_read_header(AVFormatContext *s) */ static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) { - int64_t next_ofs; + int64_t last_ofs = -1, next_ofs; MXFIndexTable *t = &mxf->index_tables[0]; + /* this is called from the OP1a demuxing logic, which means there may be no index tables */ + if (mxf->nb_index_tables <= 0) + return; + /* find mxf->current_edit_unit so that the next edit unit starts ahead of pkt->pos */ - for (;;) { + while (mxf->current_edit_unit >= 0) { if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) break; + if (next_ofs <= last_ofs) { + /* large next_ofs didn't change or current_edit_unit wrapped around + * this fixes the infinite loop on zzuf3.mxf */ + av_log(mxf->fc, AV_LOG_ERROR, "next_ofs didn't change. not deriving packet timestamps\n"); + return; + } + if (next_ofs > pkt->pos) break; + last_ofs = next_ofs; mxf->current_edit_unit++; } - if (mxf->current_edit_unit >= t->nb_ptses) + if (mxf->current_edit_unit < 0 || mxf->current_edit_unit >= t->nb_ptses) return; pkt->dts = mxf->current_edit_unit + t->first_dts; @@ -1779,16 +1833,17 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; - while (!s->pb->eof_reached) { + while (!url_feof(s->pb)) { + 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)) { - int res = mxf_decrypt_triplet(s, pkt, &klv); - if (res < 0) { + ret = mxf_decrypt_triplet(s, pkt, &klv); + if (ret < 0) { av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return -1; + return AVERROR_INVALIDDATA; } return 0; } @@ -1805,10 +1860,10 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) { if (mxf_get_d10_aes3_packet(s->pb, s->streams[index], pkt, klv.length) < 0) { av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); - return -1; + return AVERROR_INVALIDDATA; } } else { - int ret = av_get_packet(s->pb, pkt, klv.length); + ret = av_get_packet(s->pb, pkt, klv.length); if (ret < 0) return ret; } @@ -1833,23 +1888,27 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) int64_t ret64, pos, next_pos; AVStream *st; MXFIndexTable *t; + int edit_units; if (mxf->op != OPAtom) return mxf_read_packet_old(s, pkt); /* OPAtom - clip wrapped demuxing */ + /* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */ st = s->streams[0]; t = &mxf->index_tables[0]; if (mxf->current_edit_unit >= st->duration) return AVERROR_EOF; + edit_units = FFMIN(mxf->edit_units_per_packet, st->duration - mxf->current_edit_unit); + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0) return ret; /* compute size by finding the next edit unit or the end of the essence container * not pretty, but it works */ - if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_pos, 0)) < 0 && + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + edit_units, NULL, &next_pos, 0)) < 0 && (next_pos = mxf_essence_container_end(mxf, t->body_sid)) <= 0) { av_log(s, AV_LOG_ERROR, "unable to compute the size of the last packet\n"); return AVERROR_INVALIDDATA; @@ -1873,12 +1932,11 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) } pkt->stream_index = 0; - mxf->current_edit_unit++; + mxf->current_edit_unit += edit_units; return 0; } - static int mxf_read_close(AVFormatContext *s) { MXFContext *mxf = s->priv_data; diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 597a4f7d72..6e0061304d 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -3,20 +3,20 @@ * Copyright (c) 2008 GUCAS, Zhentan Feng <spyfeng at gmail dot com> * Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ @@ -35,8 +35,10 @@ #include <math.h> #include <time.h> +#include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavcodec/bytestream.h" +#include "libavcodec/timecode.h" #include "audiointerleave.h" #include "avformat.h" #include "internal.h" @@ -171,6 +173,7 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { }; typedef struct MXFContext { + AVClass *av_class; int64_t footer_partition_offset; int essence_container_count; AVRational time_base; @@ -184,10 +187,9 @@ typedef struct MXFContext { unsigned body_partitions_count; int last_key_index; ///< index of last key frame uint64_t duration; + struct ff_timecode tc; AVStream *timecode_track; int timecode_base; ///< rounded time code base (25 or 30) - int timecode_start; ///< frame number computed from mpeg-2 gop header timecode - int timecode_drop_frame; ///< time code use drop frame method frop mpeg-2 essence gop header int edit_unit_byte_count; ///< fixed edit unit byte count uint64_t body_offset; uint32_t instance_number; @@ -500,7 +502,7 @@ static void mxf_write_identification(AVFormatContext *s) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; - const char *company = "Libav"; + const char *company = "FFmpeg"; const char *product = "OP1a Muxer"; const char *version; int length; @@ -665,7 +667,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum // Start Time Code mxf_write_local_tag(pb, 8, 0x1501); - avio_wb64(pb, mxf->timecode_start); + avio_wb64(pb, mxf->tc.start); // Rounded Time Code Base mxf_write_local_tag(pb, 2, 0x1502); @@ -673,7 +675,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum // Drop Frame mxf_write_local_tag(pb, 1, 0x1503); - avio_w8(pb, mxf->timecode_drop_frame); + avio_w8(pb, mxf->tc.drop); } static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) @@ -1313,7 +1315,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt, MXFIndexEntry *e) { MXFStreamContext *sc = st->priv_data; - MXFContext *mxf = s->priv_data; uint32_t c = -1; int i; @@ -1333,21 +1334,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, if (e->flags & 0x40) // sequence header present e->flags |= 0x80; // random access } - if (!mxf->header_written) { - unsigned hours = (pkt->data[i+1]>>2) & 0x1f; - unsigned minutes = ((pkt->data[i+1] & 0x03) << 4) | (pkt->data[i+2]>>4); - unsigned seconds = ((pkt->data[i+2] & 0x07) << 3) | (pkt->data[i+3]>>5); - unsigned frames = ((pkt->data[i+3] & 0x1f) << 1) | (pkt->data[i+4]>>7); - mxf->timecode_drop_frame = !!(pkt->data[i+1] & 0x80); - mxf->timecode_start = (hours*3600 + minutes*60 + seconds) * - mxf->timecode_base + frames; - if (mxf->timecode_drop_frame) { - unsigned tminutes = 60 * hours + minutes; - mxf->timecode_start -= 2 * (tminutes - tminutes / 10); - } - av_log(s, AV_LOG_DEBUG, "frame %d %d:%d:%d%c%d\n", mxf->timecode_start, - hours, minutes, seconds, mxf->timecode_drop_frame ? ';':':', frames); - } } else if (c == 0x1b3) { // seq e->flags |= 0x40; switch ((pkt->data[i+4]>>4) & 0xf) { @@ -1443,6 +1429,12 @@ static int mxf_write_header(AVFormatContext *s) return -1; } avpriv_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den); + if (mxf->tc.str) { + mxf->tc.rate.num = mxf->time_base.den; + mxf->tc.rate.den = mxf->time_base.num; + if (avpriv_init_smpte_timecode(s, &mxf->tc) < 0) + return -1; + } if (s->oformat == &ff_mxf_d10_muxer) { if (st->codec->bit_rate == 50000000) if (mxf->time_base.den == 25) sc->index = 3; @@ -1545,24 +1537,6 @@ static int mxf_write_header(AVFormatContext *s) static const uint8_t system_metadata_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x03,0x01,0x04,0x01,0x01,0x00 }; static const uint8_t system_metadata_package_set_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x43,0x01,0x01,0x0D,0x01,0x03,0x01,0x04,0x01,0x02,0x01 }; -static uint32_t ff_framenum_to_12m_time_code(unsigned frame, int drop, int fps) -{ - return (0 << 31) | // color frame flag - (drop << 30) | // drop frame flag - ( ((frame % fps) / 10) << 28) | // tens of frames - ( ((frame % fps) % 10) << 24) | // units of frames - (0 << 23) | // field phase (NTSC), b0 (PAL) - ((((frame / fps) % 60) / 10) << 20) | // tens of seconds - ((((frame / fps) % 60) % 10) << 16) | // units of seconds - (0 << 15) | // b0 (NTSC), b2 (PAL) - ((((frame / (fps * 60)) % 60) / 10) << 12) | // tens of minutes - ((((frame / (fps * 60)) % 60) % 10) << 8) | // units of minutes - (0 << 7) | // b1 - (0 << 6) | // b2 (NTSC), field phase (PAL) - ((((frame / (fps * 3600) % 24)) / 10) << 4) | // tens of hours - ( (frame / (fps * 3600) % 24)) % 10; // units of hours -} - static void mxf_write_system_item(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -1570,7 +1544,7 @@ static void mxf_write_system_item(AVFormatContext *s) unsigned frame; uint32_t time_code; - frame = mxf->timecode_start + mxf->last_indexed_edit_unit + mxf->edit_units_count; + frame = mxf->tc.start + mxf->last_indexed_edit_unit + mxf->edit_units_count; // write system metadata pack avio_write(pb, system_metadata_pack_key, 16); @@ -1591,7 +1565,11 @@ static void mxf_write_system_item(AVFormatContext *s) avio_wb64(pb, 0); // creation date/time stamp avio_w8(pb, 0x81); // SMPTE 12M time code - time_code = ff_framenum_to_12m_time_code(frame, mxf->timecode_drop_frame, mxf->timecode_base); + time_code = frame; + if (mxf->tc.drop) + time_code = avpriv_framenum_to_drop_timecode(time_code); + time_code = avpriv_framenum_to_smpte_timecode(time_code, mxf->timecode_base, + mxf->tc.drop); avio_wb32(pb, time_code); avio_wb32(pb, 0); // binary group data avio_wb64(pb, 0); @@ -1888,6 +1866,26 @@ static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int mxf_interleave_get_packet, mxf_compare_timestamps); } +static const AVClass mxf_class = { + .class_name = "mxf", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = (const AVOption[]){ + {TIMECODE_OPT(MXFContext, AV_OPT_FLAG_ENCODING_PARAM)}, + {NULL} + }, +}; + +static const AVClass mxf_d10_class = { + .class_name = "mxf_d10", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = (const AVOption[]){ + {TIMECODE_OPT(MXFContext, AV_OPT_FLAG_ENCODING_PARAM)}, + {NULL} + }, +}; + AVOutputFormat ff_mxf_muxer = { .name = "mxf", .long_name = NULL_IF_CONFIG_SMALL("Material eXchange Format"), @@ -1901,6 +1899,7 @@ AVOutputFormat ff_mxf_muxer = { .write_trailer = mxf_write_footer, .flags = AVFMT_NOTIMESTAMPS, .interleave_packet = mxf_interleave, + .priv_class = &mxf_class, }; AVOutputFormat ff_mxf_d10_muxer = { @@ -1915,4 +1914,5 @@ AVOutputFormat ff_mxf_d10_muxer = { .write_trailer = mxf_write_footer, .flags = AVFMT_NOTIMESTAMPS, .interleave_packet = mxf_interleave, + .priv_class = &mxf_d10_class, }; diff --git a/libavformat/mxg.c b/libavformat/mxg.c index 3f8c3e339e..32ca2750cb 100644 --- a/libavformat/mxg.c +++ b/libavformat/mxg.c @@ -2,20 +2,20 @@ * MxPEG clip file demuxer * Copyright (c) 2010 Anatoly Nenashev * - * 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 */ @@ -104,7 +104,7 @@ static int mxg_update_cache(AVFormatContext *s, unsigned int cache_size) /* reallocate internal buffer */ if (current_pos > current_pos + cache_size) return AVERROR(ENOMEM); - if (mxg->soi_ptr) soi_pos = mxg->soi_ptr - mxg->buffer; + soi_pos = mxg->soi_ptr - mxg->buffer; mxg->buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size, current_pos + cache_size + FF_INPUT_BUFFER_PADDING_SIZE); @@ -131,7 +131,7 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) uint8_t *startmarker_ptr, *end, *search_end, marker; MXGContext *mxg = s->priv_data; - while (!s->pb->eof_reached && !s->pb->error){ + while (!url_feof(s->pb) && !s->pb->error){ if (mxg->cache_size <= OVERREAD_SIZE) { /* update internal buffer */ ret = mxg_update_cache(s, DEFAULT_PACKET_SIZE + OVERREAD_SIZE); diff --git a/libavformat/ncdec.c b/libavformat/ncdec.c index 44e227ad8f..9a46b808e7 100644 --- a/libavformat/ncdec.c +++ b/libavformat/ncdec.c @@ -3,20 +3,20 @@ * Copyright (c) 2009 Nicolas Martin (martinic at iro dot umontreal dot ca) * Edouard Auvinet * - * 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 */ @@ -67,7 +67,7 @@ static int nc_read_packet(AVFormatContext *s, AVPacket *pkt) uint32_t state=-1; while (state != NC_VIDEO_FLAG) { - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); state = (state<<8) + avio_r8(s->pb); } diff --git a/libavformat/network.c b/libavformat/network.c index bfc34c72a7..9beaaaf350 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avutil.h" #include "network.h" #include "libavcodec/internal.h" diff --git a/libavformat/network.h b/libavformat/network.h index 72d01d2986..9f7b78202e 100644 --- a/libavformat/network.h +++ b/libavformat/network.h @@ -1,20 +1,20 @@ /* - * 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 */ diff --git a/libavformat/nsvdec.c b/libavformat/nsvdec.c index b5bc87aa8c..50fbca98c2 100644 --- a/libavformat/nsvdec.c +++ b/libavformat/nsvdec.c @@ -1,21 +1,21 @@ /* * NSV demuxer - * Copyright (c) 2004 The Libav Project + * Copyright (c) 2004 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 */ @@ -24,6 +24,7 @@ #include "internal.h" #include "riff.h" #include "libavutil/dict.h" +#include "libavutil/intreadwrite.h" //#define DEBUG_DUMP_INDEX // XXX dumbdriving-271.nsv breaks with it commented!! #define CHECK_SUBSEQUENT_NSVS @@ -72,11 +73,7 @@ * so the header seems to not be mandatory. (for streaming). * * index slice duration check (excepts nsvtrailer.nsv): - * for f in [^n]*.nsv; do - * DUR="$(avconv -i "$f" 2> /dev/null | grep 'NSVf duration' | cut -d ' ' -f 4)" - * IC="$(avconv -i "$f" 2> /dev/null | grep 'INDEX ENTRIES' | cut -d ' ' -f 2)" - * echo "duration $DUR, slite time $(($DUR/$IC))" - * done + * for f in [^n]*.nsv; do DUR="$(ffmpeg -i "$f" 2>/dev/null | grep 'NSVf duration' | cut -d ' ' -f 4)"; IC="$(ffmpeg -i "$f" 2>/dev/null | grep 'INDEX ENTRIES' | cut -d ' ' -f 2)"; echo "duration $DUR, slite time $(($DUR/$IC))"; done */ /* @@ -195,6 +192,7 @@ static const AVCodecTag nsv_codec_video_tags[] = { { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') }, { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') }, { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') }, + { CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, /* { CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') }, { CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') }, @@ -208,6 +206,7 @@ static const AVCodecTag nsv_codec_audio_tags[] = { { CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') }, { CODEC_ID_AAC, MKTAG('A', 'A', 'C', ' ') }, { CODEC_ID_AAC, MKTAG('A', 'A', 'C', 'P') }, + { CODEC_ID_AAC, MKTAG('V', 'L', 'B', ' ') }, { CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', ' ') }, { CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') }, { CODEC_ID_NONE, 0 }, @@ -236,7 +235,7 @@ static int nsv_resync(AVFormatContext *s) //nsv->state = NSV_UNSYNC; for (i = 0; i < NSV_MAX_RESYNC; i++) { - if (pb->eof_reached) { + if (url_feof(pb)) { av_dlog(s, "NSV EOF\n"); nsv->state = NSV_UNSYNC; return -1; @@ -303,7 +302,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s) table_entries_used = avio_rl32(pb); av_dlog(s, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n", strings_size, table_entries, table_entries_used); - if (pb->eof_reached) + if (url_feof(pb)) return -1; av_dlog(s, "NSV got header; filepos %"PRId64"\n", avio_tell(pb)); @@ -315,6 +314,8 @@ static int nsv_parse_NSVf_header(AVFormatContext *s) char quote; p = strings = av_mallocz(strings_size + 1); + if (!p) + return AVERROR(ENOMEM); endp = strings + strings_size; avio_read(pb, strings, strings_size); while (p < endp) { @@ -338,7 +339,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s) } av_free(strings); } - if (pb->eof_reached) + if (url_feof(pb)) return -1; av_dlog(s, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb)); @@ -385,7 +386,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s) avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */ - if (pb->eof_reached) + if (url_feof(pb)) return -1; nsv->state = NSV_HAS_READ_NSVF; return 0; @@ -563,7 +564,7 @@ static int nsv_read_chunk(AVFormatContext *s, int fill_header) return 0; //-1; /* hey! eat what you've in your plate first! */ null_chunk_retry: - if (pb->eof_reached) + if (url_feof(pb)) return -1; for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++) @@ -597,7 +598,7 @@ null_chunk_retry: vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t); /* that's becoming braindead */ } - if (pb->eof_reached) + if (url_feof(pb)) return -1; if (!vsize && !asize) { nsv->state = NSV_UNSYNC; @@ -605,12 +606,12 @@ null_chunk_retry: } /* map back streams to v,a */ - if (s->streams[0]) + if (s->nb_streams > 0) st[s->streams[0]->id] = s->streams[0]; - if (s->streams[1]) + if (s->nb_streams > 1) st[s->streams[1]->id] = s->streams[1]; - if (vsize/* && st[NSV_ST_VIDEO]*/) { + if (vsize && st[NSV_ST_VIDEO]) { nst = st[NSV_ST_VIDEO]->priv_data; pkt = &nsv->ahead[NSV_ST_VIDEO]; av_get_packet(pb, pkt, vsize); @@ -623,7 +624,7 @@ null_chunk_retry: if(st[NSV_ST_VIDEO]) ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++; - if (asize/*st[NSV_ST_AUDIO]*/) { + if (asize && st[NSV_ST_AUDIO]) { nst = st[NSV_ST_AUDIO]->priv_data; pkt = &nsv->ahead[NSV_ST_AUDIO]; /* read raw audio specific header on the first audio chunk... */ @@ -709,7 +710,9 @@ static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp if(index < 0) return -1; - avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET); + if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0) + return -1; + nst->frame_offset = st->index_entries[index].timestamp; nsv->state = NSV_UNSYNC; return 0; @@ -745,10 +748,8 @@ static int nsv_read_close(AVFormatContext *s) static int nsv_probe(AVProbeData *p) { - int i; - int score; - int vsize, asize, auxcount; - score = 0; + int i, score = 0; + av_dlog(NULL, "nsv_probe(), buf_size %d\n", p->buf_size); /* check file header */ /* streamed files might not have any header */ @@ -760,19 +761,14 @@ static int nsv_probe(AVProbeData *p) /* seems the servers don't bother starting clean chunks... */ /* sometimes even the first header is at 9KB or something :^) */ for (i = 1; i < p->buf_size - 3; i++) { - if (p->buf[i+0] == 'N' && p->buf[i+1] == 'S' && - p->buf[i+2] == 'V' && p->buf[i+3] == 's') { - score = AVPROBE_SCORE_MAX/5; + if (AV_RL32(p->buf + i) == AV_RL32("NSVs")) { /* Get the chunk size and check if at the end we are getting 0xBEEF */ - auxcount = p->buf[i+19]; - vsize = p->buf[i+20] | p->buf[i+21] << 8; - asize = p->buf[i+22] | p->buf[i+23] << 8; - vsize = (vsize << 4) | (auxcount >> 4); - if ((asize + vsize + i + 23) < p->buf_size - 2) { - if (p->buf[i+23+asize+vsize+1] == 0xEF && - p->buf[i+23+asize+vsize+2] == 0xBE) - return AVPROBE_SCORE_MAX-20; - } + int vsize = AV_RL24(p->buf+i+19) >> 4; + int asize = AV_RL16(p->buf+i+22); + int offset = i + 23 + asize + vsize + 1; + if (offset <= p->buf_size - 2 && AV_RL16(p->buf + offset) == 0xBEEF) + return 4*AVPROBE_SCORE_MAX/5; + score = AVPROBE_SCORE_MAX/5; } } /* so we'll have more luck on extension... */ diff --git a/libavformat/nullenc.c b/libavformat/nullenc.c index 9849f460f0..9edbf20fc8 100644 --- a/libavformat/nullenc.c +++ b/libavformat/nullenc.c @@ -2,20 +2,20 @@ * RAW null muxer * Copyright (c) 2002 Fabrice Bellard * - * 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/libavformat/nut.c b/libavformat/nut.c index ac62d4ff4c..0a44811c57 100644 --- a/libavformat/nut.c +++ b/libavformat/nut.c @@ -2,20 +2,20 @@ * nut * Copyright (c) 2004-2007 Michael Niedermayer * - * 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/libavformat/nut.h b/libavformat/nut.h index 419b123bee..033bc0898e 100644 --- a/libavformat/nut.h +++ b/libavformat/nut.h @@ -2,20 +2,20 @@ * "NUT" Container Format (de)muxer * Copyright (c) 2006 Michael Niedermayer * - * 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/libavformat/nutdec.c b/libavformat/nutdec.c index 8d1b17ddc9..810632de50 100644 --- a/libavformat/nutdec.c +++ b/libavformat/nutdec.c @@ -3,20 +3,20 @@ * Copyright (c) 2004-2006 Michael Niedermayer * Copyright (c) 2003 Alex Beregszaszi * - * 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 */ @@ -119,7 +119,7 @@ static uint64_t find_any_startcode(AVIOContext *bc, int64_t pos){ if(pos >= 0) avio_seek(bc, pos, SEEK_SET); //note, this may fail if the stream is not seekable, but that should not matter, as in this case we simply start where we currently are - while(!bc->eof_reached){ + while(!url_feof(bc)){ state= (state<<8) | avio_r8(bc); if((state>>56) != 'N') continue; @@ -786,7 +786,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) pos-=8; }else{ frame_code = avio_r8(bc); - if(bc->eof_reached) + if(url_feof(bc)) return -1; if(frame_code == 'N'){ tmp= frame_code; diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c index ae1c2f194c..c753fc25ba 100644 --- a/libavformat/nutenc.c +++ b/libavformat/nutenc.c @@ -2,20 +2,20 @@ * nut muxer * Copyright (c) 2004-2007 Michael Niedermayer * - * 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 */ @@ -177,6 +177,7 @@ static void build_frame_code(AVFormatContext *s){ } key_frame= intra_only; +#if 1 if(is_audio){ int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate); int pts; @@ -200,6 +201,7 @@ static void build_frame_code(AVFormatContext *s){ ft->pts_delta=1; start2++; } +#endif if(codec->has_b_frames){ pred_count=5; @@ -586,11 +588,10 @@ static int nut_write_header(AVFormatContext *s){ nut->avf= s; nut->stream = av_mallocz(sizeof(StreamContext)*s->nb_streams); - if (s->nb_chapters) - nut->chapter = av_mallocz(sizeof(ChapterContext)*s->nb_chapters); + nut->chapter = av_mallocz(sizeof(ChapterContext)*s->nb_chapters); nut->time_base= av_mallocz(sizeof(AVRational )*(s->nb_streams + s->nb_chapters)); - if (!nut->stream || (s->nb_chapters && !nut->chapter) || !nut->time_base) { + if (!nut->stream || !nut->chapter || !nut->time_base) { av_freep(&nut->stream); av_freep(&nut->chapter); av_freep(&nut->time_base); diff --git a/libavformat/nuv.c b/libavformat/nuv.c index 86be778e4c..7c96f05217 100644 --- a/libavformat/nuv.c +++ b/libavformat/nuv.c @@ -2,20 +2,20 @@ * NuppelVideo demuxer. * Copyright (c) 2006 Reimar Doeffinger * - * 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 */ @@ -62,7 +62,7 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst, nuv_frametype frametype; if (!vst && !myth) return 1; // no codec data needed - while (!pb->eof_reached) { + while (!url_feof(pb)) { int size, subtype; frametype = avio_r8(pb); switch (frametype) { @@ -197,7 +197,7 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { uint8_t hdr[HDRSIZE]; nuv_frametype frametype; int ret, size; - while (!pb->eof_reached) { + while (!url_feof(pb)) { int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0; uint64_t pos = avio_tell(pb); ret = avio_read(pb, hdr, HDRSIZE); @@ -220,10 +220,9 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { ret = av_new_packet(pkt, copyhdrsize + size); if (ret < 0) return ret; - // HACK: we have no idea if it is a keyframe, - // but if we mark none seeking will not work at all. - pkt->flags |= AV_PKT_FLAG_KEY; + pkt->pos = pos; + pkt->flags |= hdr[2] == 0 ? AV_PKT_FLAG_KEY : 0; pkt->pts = AV_RL32(&hdr[4]); pkt->stream_index = ctx->v_id; memcpy(pkt->data, hdr, copyhdrsize); @@ -259,6 +258,81 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { return AVERROR(EIO); } +/** + * \brief looks for the string RTjjjjjjjjjj in the stream too resync reading + * \return 1 if the syncword is found 0 otherwise. + */ +static int nuv_resync(AVFormatContext *s, int64_t pos_limit) { + AVIOContext *pb = s->pb; + uint32_t tag = 0; + while(!url_feof(pb) && avio_tell(pb) < pos_limit) { + tag = (tag << 8) | avio_r8(pb); + if (tag == MKBETAG('R','T','j','j') && + (tag = avio_rb32(pb)) == MKBETAG('j','j','j','j') && + (tag = avio_rb32(pb)) == MKBETAG('j','j','j','j')) + return 1; + } + return 0; +} + +/** + * \brief attempts to read a timestamp from stream at the given stream position + * \return timestamp if successfull and AV_NOPTS_VALUE if failure + */ +static int64_t nuv_read_dts(AVFormatContext *s, int stream_index, + int64_t *ppos, int64_t pos_limit) +{ + NUVContext *ctx = s->priv_data; + AVIOContext *pb = s->pb; + uint8_t hdr[HDRSIZE]; + nuv_frametype frametype; + int size, key, idx; + int64_t pos, dts; + + if (avio_seek(pb, *ppos, SEEK_SET) < 0) + return AV_NOPTS_VALUE; + + if (!nuv_resync(s, pos_limit)) + return AV_NOPTS_VALUE; + + while (!url_feof(pb) && avio_tell(pb) < pos_limit) { + if (avio_read(pb, hdr, HDRSIZE) < HDRSIZE) + return AV_NOPTS_VALUE; + frametype = hdr[0]; + size = PKTSIZE(AV_RL32(&hdr[8])); + switch (frametype) { + case NUV_SEEKP: + break; + case NUV_AUDIO: + case NUV_VIDEO: + if (frametype == NUV_VIDEO) { + idx = ctx->v_id; + key = hdr[2] == 0; + } else { + idx = ctx->a_id; + key = 1; + } + if (stream_index == idx) { + + pos = avio_tell(s->pb) - HDRSIZE; + dts = AV_RL32(&hdr[4]); + + // TODO - add general support in av_gen_search, so it adds positions after reading timestamps + av_add_index_entry(s->streams[stream_index], pos, dts, size + HDRSIZE, 0, + key ? AVINDEX_KEYFRAME : 0); + + *ppos = pos; + return dts; + } + default: + avio_skip(pb, size); + break; + } + } + return AV_NOPTS_VALUE; +} + + AVInputFormat ff_nuv_demuxer = { .name = "nuv", .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo format"), @@ -266,5 +340,6 @@ AVInputFormat ff_nuv_demuxer = { .read_probe = nuv_probe, .read_header = nuv_header, .read_packet = nuv_packet, + .read_timestamp = nuv_read_dts, .flags = AVFMT_GENERIC_INDEX, }; diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 79aa98f83d..3a1abc085f 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -28,7 +28,6 @@ DEALINGS IN THE SOFTWARE. */ - #include <stdio.h> #include "oggdec.h" #include "avformat.h" @@ -225,7 +224,7 @@ static int ogg_read_page(AVFormatContext *s, int *str) break; c = avio_r8(bc); - if (bc->eof_reached) + if (url_feof(bc)) return AVERROR_EOF; sync[sp++ & 3] = c; }while (i++ < MAX_PAGE_SIZE); @@ -373,8 +372,6 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize, } }while (!complete); - av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n", - idx, os->psize, os->pstart); if (os->granule == -1) av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos); @@ -424,6 +421,8 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize, *fpos = os->sync_pos; os->pstart += os->psize; os->psize = 0; + if(os->pstart == os->bufpos) + os->bufpos = os->pstart = 0; os->sync_pos = os->page_pos; } @@ -463,6 +462,7 @@ static int ogg_get_length(AVFormatContext *s) struct ogg *ogg = s->priv_data; int i; int64_t size, end; + int streams_left=0; if(!s->pb->seekable) return 0; @@ -484,13 +484,37 @@ static int ogg_get_length(AVFormatContext *s) ogg->streams[i].codec) { s->streams[i]->duration = ogg_gptopts (s, i, ogg->streams[i].granule, NULL); - if (s->streams[i]->start_time != AV_NOPTS_VALUE) + if (s->streams[i]->start_time != AV_NOPTS_VALUE){ s->streams[i]->duration -= s->streams[i]->start_time; + streams_left-= (ogg->streams[i].got_start==-1); + ogg->streams[i].got_start= 1; + }else if(!ogg->streams[i].got_start){ + ogg->streams[i].got_start= -1; + streams_left++; + } } } ogg_restore (s, 0); + ogg_save (s); + avio_seek (s->pb, 0, SEEK_SET); + while (!ogg_read_page (s, &i)){ + if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && + ogg->streams[i].codec) { + if(s->streams[i]->duration && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start){ + int64_t start= ogg_gptopts (s, i, ogg->streams[i].granule, NULL); + if(av_rescale_q(start, s->streams[i]->time_base, AV_TIME_BASE_Q) > AV_TIME_BASE) + s->streams[i]->duration -= start; + ogg->streams[i].got_start= 1; + streams_left--; + } + if(streams_left<=0) + break; + } + } + ogg_restore (s, 0); + return 0; } diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h index 184a628622..7f5452f2b0 100644 --- a/libavformat/oggdec.h +++ b/libavformat/oggdec.h @@ -75,6 +75,7 @@ struct ogg_stream { int incomplete; ///< whether we're expecting a continuation in the next page int page_end; ///< current packet is the last one completed in the page int keyframe_seek; + int got_start; void *private; }; diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index 33aba87039..ac6eb8737d 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -2,24 +2,25 @@ * Ogg muxer * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr> * - * 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/crc.h" +#include "libavutil/opt.h" #include "libavutil/mathematics.h" #include "libavutil/random_seed.h" #include "libavcodec/xiph.h" @@ -63,9 +64,26 @@ typedef struct OGGPageList { } OGGPageList; typedef struct { + const AVClass *class; OGGPageList *page_list; + int pref_size; ///< preferred page size (0 => fill all segments) } OGGContext; + +static const AVOption options[] = { + { "oggpagesize", "Set preferred Ogg page size.", + offsetof(OGGContext, pref_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, MAX_PAGE_SIZE, AV_OPT_FLAG_ENCODING_PARAM}, + { NULL }, +}; + +static const AVClass ogg_muxer_class = { + "Ogg muxer", + av_default_item_name, + options, + LIBAVUTIL_VERSION_INT, +}; + + static void ogg_update_checksum(AVFormatContext *s, AVIOContext *pb, int64_t crc_offset) { int64_t pos = avio_tell(pb); @@ -175,6 +193,7 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, uint8_t *data, unsigned size, int64_t granule) { OGGStreamContext *oggstream = st->priv_data; + OGGContext *ogg = s->priv_data; int total_segments = size / 255 + 1; uint8_t *p = data; int i, segments, len, flush = 0; @@ -210,8 +229,9 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, if (i == total_segments) page->granule = granule; - if (page->segments_count == 255) { - ogg_buffer_page(s, oggstream); + if(page->segments_count == 255 || + (ogg->pref_size > 0 && page->size >= ogg->pref_size)) { + ogg_buffer_page(s, oggstream); } } @@ -224,7 +244,7 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact, int *header_len, AVDictionary **m, int framing_bit) { - const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT; + const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; int size; uint8_t *p, *p0; unsigned int count; @@ -496,9 +516,11 @@ static int ogg_write_trailer(AVFormatContext *s) OGGStreamContext *oggstream = st->priv_data; if (st->codec->codec_id == CODEC_ID_FLAC || st->codec->codec_id == CODEC_ID_SPEEX) { - av_free(oggstream->header[0]); - av_free(oggstream->header[1]); + av_freep(&oggstream->header[0]); + av_freep(&oggstream->header[1]); } + else + av_freep(&oggstream->header[1]); av_freep(&st->priv_data); } return 0; @@ -515,4 +537,5 @@ AVOutputFormat ff_ogg_muxer = { .write_header = ogg_write_header, .write_packet = ogg_write_packet, .write_trailer = ogg_write_trailer, + .priv_class = &ogg_muxer_class, }; diff --git a/libavformat/oggparsecelt.c b/libavformat/oggparsecelt.c index 5f07de40cb..fc5891b091 100644 --- a/libavformat/oggparsecelt.c +++ b/libavformat/oggparsecelt.c @@ -1,21 +1,21 @@ /* - * Xiph CELT / Opus parser for Ogg + * Xiph CELT parser for Ogg * Copyright (c) 2011 Nicolas George * - * 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 */ @@ -62,18 +62,18 @@ static int celt_header(AVFormatContext *s, int idx) overlap = AV_RL32(p + 48); /* unused bytes per packet field skipped */ extra_headers = AV_RL32(p + 56); - av_free(os->private); - av_free(st->codec->extradata); st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_CELT; 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); diff --git a/libavformat/oggparsedirac.c b/libavformat/oggparsedirac.c index 8d3a802223..abcf4fb15c 100644 --- a/libavformat/oggparsedirac.c +++ b/libavformat/oggparsedirac.c @@ -1,20 +1,20 @@ /* * Copyright (C) 2008 David Conrad * - * 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/libavformat/oggparseflac.c b/libavformat/oggparseflac.c index b1d18ed12d..015a376755 100644 --- a/libavformat/oggparseflac.c +++ b/libavformat/oggparseflac.c @@ -1,20 +1,20 @@ /* * Copyright (C) 2005 Matthieu CASTET * - * 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/libavformat/oggparseskeleton.c b/libavformat/oggparseskeleton.c index 62dd14ded1..8ae753b8ca 100644 --- a/libavformat/oggparseskeleton.c +++ b/libavformat/oggparseskeleton.c @@ -1,20 +1,20 @@ /* * Copyright (C) 2010 David Conrad * - * 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/libavformat/oma.c b/libavformat/oma.c index 930991cf00..30e86f10bb 100644 --- a/libavformat/oma.c +++ b/libavformat/oma.c @@ -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 */ @@ -31,3 +31,4 @@ const AVCodecTag ff_oma_codec_tags[] = { { CODEC_ID_PCM_S16BE, OMA_CODECID_LPCM }, { 0 }, }; + diff --git a/libavformat/omadec.c b/libavformat/omadec.c index 3bff790a56..5a1660b89f 100644 --- a/libavformat/omadec.c +++ b/libavformat/omadec.c @@ -5,20 +5,20 @@ * 2008 Benjamin Larsson * 2011 David Goldwich * - * 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 */ @@ -140,7 +140,7 @@ 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, const uint8_t *n_val) +static int nprobe(AVFormatContext *s, uint8_t *enc_header, int size, const uint8_t *n_val) { OMAContext *oc = s->priv_data; uint32_t pos, taglen, datalen; @@ -159,6 +159,9 @@ static int nprobe(AVFormatContext *s, uint8_t *enc_header, const uint8_t *n_val) taglen = AV_RB32(&enc_header[pos+32]); datalen = AV_RB32(&enc_header[pos+36]) >> 4; + if(taglen + (((uint64_t)datalen)<<4) + 44 > size) + return -1; + pos += 44 + taglen; av_des_init(&av_des, n_val, 192, 1); @@ -229,14 +232,14 @@ static int decrypt_init(AVFormatContext *s, ID3v2ExtraMeta *em, uint8_t *header) } if (!memcmp(oc->r_val, (const uint8_t[8]){0}, 8) || rprobe(s, gdata, oc->r_val) < 0 && - nprobe(s, gdata, oc->n_val) < 0) { + nprobe(s, gdata, geob->datasize, oc->n_val) < 0) { int i; for (i = 0; i < sizeof(leaf_table); i += 2) { uint8_t buf[16]; 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, oc->n_val)) + if (!rprobe(s, gdata, oc->r_val) || !nprobe(s, gdata, geob->datasize, oc->n_val)) break; } if (i >= sizeof(leaf_table)) { diff --git a/libavformat/options.c b/libavformat/options.c index dcc3d60995..490c765666 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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" @@ -90,6 +90,9 @@ static const AVOption options[]={ {"noparse", "disable AVParsers, this needs nofillin too", 0, AV_OPT_TYPE_CONST, {.dbl = AVFMT_FLAG_NOPARSE }, INT_MIN, INT_MAX, D, "fflags"}, {"igndts", "ignore dts", 0, AV_OPT_TYPE_CONST, {.dbl = AVFMT_FLAG_IGNDTS }, INT_MIN, INT_MAX, D, "fflags"}, {"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.dbl = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"}, +{"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.dbl = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"}, +{"keepside", "dont merge side data", 0, AV_OPT_TYPE_CONST, {.dbl = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, +{"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.dbl = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, {"analyzeduration", "how many microseconds are analyzed to estimate duration", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.dbl = 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, {.dbl = 1<<20 }, 0, INT_MAX, D}, @@ -98,6 +101,9 @@ static const AVOption options[]={ {"ts", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_FDEBUG_TS }, INT_MIN, INT_MAX, E|D, "fdebug"}, {"max_delay", "maximum muxing or demuxing delay in microseconds", OFFSET(max_delay), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, 0, INT_MAX, E|D}, {"fpsprobesize", "number of frames used to probe fps", OFFSET(fps_probe_size), AV_OPT_TYPE_INT, {.dbl = -1}, -1, INT_MAX-1, D}, +{"audio_preload", "microseconds by which audio packets should be interleaved earlier", OFFSET(audio_preload), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX-1, E}, +{"chunk_duration", "microseconds for each chunk", OFFSET(max_chunk_duration), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX-1, E}, +{"chunk_size", "size in bytes for each chunk", OFFSET(max_chunk_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX-1, E}, /* this is a crutch for avconv, since it cannot deal with identically named options in different contexts. * to be removed when avconv is fixed */ {"f_err_detect", "set error detection flags (deprecated; use err_detect, save via avconv)", OFFSET(error_recognition), AV_OPT_TYPE_FLAGS, {.dbl = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, D, "err_detect"}, @@ -106,6 +112,9 @@ static const AVOption options[]={ {"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.dbl = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, D, "err_detect"}, {"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.dbl = AV_EF_BUFFER }, INT_MIN, INT_MAX, D, "err_detect"}, {"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.dbl = 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, {.dbl = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"}, +{"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.dbl = 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, {.dbl = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, D, "err_detect"}, {NULL}, }; diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 889a005eeb..467053e196 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -3,20 +3,20 @@ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * copyright (c) 2002 Francois Revol * - * 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/libavformat/os_support.h b/libavformat/os_support.h index 20c6d73738..fca5b2a813 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -2,20 +2,20 @@ * various OS-feature replacement utilities * copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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/libavformat/output-example.c b/libavformat/output-example.c deleted file mode 100644 index a1702cd01a..0000000000 --- a/libavformat/output-example.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2003 Fabrice Bellard - * - * 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. - */ - -/** - * @file - * libavformat API example. - * - * @example libavformat/output-example.c - * Output a media file in any supported libavformat format. - * The default codecs are used. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include "libavutil/mathematics.h" -#include "libavformat/avformat.h" -#include "libswscale/swscale.h" - -#undef exit - -/* 5 seconds stream duration */ -#define STREAM_DURATION 5.0 -#define STREAM_FRAME_RATE 25 /* 25 images/s */ -#define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE)) -#define STREAM_PIX_FMT PIX_FMT_YUV420P /* default pix_fmt */ - -static int sws_flags = SWS_BICUBIC; - -/**************************************************************/ -/* audio output */ - -static float t, tincr, tincr2; -static int16_t *samples; -static uint8_t *audio_outbuf; -static int audio_outbuf_size; -static int audio_input_frame_size; - -/* - * add an audio output stream - */ -static AVStream *add_audio_stream(AVFormatContext *oc, enum CodecID codec_id) -{ - AVCodecContext *c; - AVStream *st; - - st = av_new_stream(oc, 1); - if (!st) { - fprintf(stderr, "Could not alloc stream\n"); - exit(1); - } - - c = st->codec; - c->codec_id = codec_id; - c->codec_type = AVMEDIA_TYPE_AUDIO; - - /* put sample parameters */ - c->sample_fmt = AV_SAMPLE_FMT_S16; - c->bit_rate = 64000; - c->sample_rate = 44100; - c->channels = 2; - - // some formats want stream headers to be separate - if(oc->oformat->flags & AVFMT_GLOBALHEADER) - c->flags |= CODEC_FLAG_GLOBAL_HEADER; - - return st; -} - -static void open_audio(AVFormatContext *oc, AVStream *st) -{ - AVCodecContext *c; - AVCodec *codec; - - c = st->codec; - - /* find the audio encoder */ - codec = avcodec_find_encoder(c->codec_id); - if (!codec) { - fprintf(stderr, "codec not found\n"); - exit(1); - } - - /* open it */ - if (avcodec_open(c, codec) < 0) { - fprintf(stderr, "could not open codec\n"); - exit(1); - } - - /* init signal generator */ - t = 0; - tincr = 2 * M_PI * 110.0 / c->sample_rate; - /* increment frequency by 110 Hz per second */ - tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate; - - audio_outbuf_size = 10000; - audio_outbuf = av_malloc(audio_outbuf_size); - - /* ugly hack for PCM codecs (will be removed ASAP with new PCM - support to compute the input frame size in samples */ - if (c->frame_size <= 1) { - audio_input_frame_size = audio_outbuf_size / c->channels; - switch(st->codec->codec_id) { - case CODEC_ID_PCM_S16LE: - case CODEC_ID_PCM_S16BE: - case CODEC_ID_PCM_U16LE: - case CODEC_ID_PCM_U16BE: - audio_input_frame_size >>= 1; - break; - default: - break; - } - } else { - audio_input_frame_size = c->frame_size; - } - samples = av_malloc(audio_input_frame_size * 2 * c->channels); -} - -/* prepare a 16 bit dummy audio frame of 'frame_size' samples and - 'nb_channels' channels */ -static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels) -{ - int j, i, v; - int16_t *q; - - q = samples; - for(j=0;j<frame_size;j++) { - v = (int)(sin(t) * 10000); - for(i = 0; i < nb_channels; i++) - *q++ = v; - t += tincr; - tincr += tincr2; - } -} - -static void write_audio_frame(AVFormatContext *oc, AVStream *st) -{ - AVCodecContext *c; - AVPacket pkt; - av_init_packet(&pkt); - - c = st->codec; - - get_audio_frame(samples, audio_input_frame_size, c->channels); - - pkt.size= avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples); - - if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) - pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base); - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.stream_index= st->index; - pkt.data= audio_outbuf; - - /* write the compressed frame in the media file */ - if (av_interleaved_write_frame(oc, &pkt) != 0) { - fprintf(stderr, "Error while writing audio frame\n"); - exit(1); - } -} - -static void close_audio(AVFormatContext *oc, AVStream *st) -{ - avcodec_close(st->codec); - - av_free(samples); - av_free(audio_outbuf); -} - -/**************************************************************/ -/* video output */ - -static AVFrame *picture, *tmp_picture; -static uint8_t *video_outbuf; -static int frame_count, video_outbuf_size; - -/* add a video output stream */ -static AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id) -{ - AVCodecContext *c; - AVStream *st; - - st = avformat_new_stream(oc, NULL); - if (!st) { - fprintf(stderr, "Could not alloc stream\n"); - exit(1); - } - - c = st->codec; - c->codec_id = codec_id; - c->codec_type = AVMEDIA_TYPE_VIDEO; - - /* put sample parameters */ - c->bit_rate = 400000; - /* resolution must be a multiple of two */ - c->width = 352; - c->height = 288; - /* time base: this is the fundamental unit of time (in seconds) in terms - of which frame timestamps are represented. for fixed-fps content, - timebase should be 1/framerate and timestamp increments should be - identically 1. */ - c->time_base.den = STREAM_FRAME_RATE; - c->time_base.num = 1; - c->gop_size = 12; /* emit one intra frame every twelve frames at most */ - c->pix_fmt = STREAM_PIX_FMT; - if (c->codec_id == CODEC_ID_MPEG2VIDEO) { - /* just for testing, we also add B frames */ - c->max_b_frames = 2; - } - if (c->codec_id == CODEC_ID_MPEG1VIDEO){ - /* Needed to avoid using macroblocks in which some coeffs overflow. - This does not happen with normal video, it just happens here as - the motion of the chroma plane does not match the luma plane. */ - c->mb_decision=2; - } - // some formats want stream headers to be separate - if(oc->oformat->flags & AVFMT_GLOBALHEADER) - c->flags |= CODEC_FLAG_GLOBAL_HEADER; - - return st; -} - -static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height) -{ - AVFrame *picture; - uint8_t *picture_buf; - int size; - - picture = avcodec_alloc_frame(); - if (!picture) - return NULL; - size = avpicture_get_size(pix_fmt, width, height); - picture_buf = av_malloc(size); - if (!picture_buf) { - av_free(picture); - return NULL; - } - avpicture_fill((AVPicture *)picture, picture_buf, - pix_fmt, width, height); - return picture; -} - -static void open_video(AVFormatContext *oc, AVStream *st) -{ - AVCodec *codec; - AVCodecContext *c; - - c = st->codec; - - /* find the video encoder */ - codec = avcodec_find_encoder(c->codec_id); - if (!codec) { - fprintf(stderr, "codec not found\n"); - exit(1); - } - - /* open the codec */ - if (avcodec_open(c, codec) < 0) { - fprintf(stderr, "could not open codec\n"); - exit(1); - } - - video_outbuf = NULL; - if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { - /* allocate output buffer */ - /* XXX: API change will be done */ - /* buffers passed into lav* can be allocated any way you prefer, - as long as they're aligned enough for the architecture, and - they're freed appropriately (such as using av_free for buffers - allocated with av_malloc) */ - video_outbuf_size = 200000; - video_outbuf = av_malloc(video_outbuf_size); - } - - /* allocate the encoded raw picture */ - picture = alloc_picture(c->pix_fmt, c->width, c->height); - if (!picture) { - fprintf(stderr, "Could not allocate picture\n"); - exit(1); - } - - /* if the output format is not YUV420P, then a temporary YUV420P - picture is needed too. It is then converted to the required - output format */ - tmp_picture = NULL; - if (c->pix_fmt != PIX_FMT_YUV420P) { - tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height); - if (!tmp_picture) { - fprintf(stderr, "Could not allocate temporary picture\n"); - exit(1); - } - } -} - -/* prepare a dummy image */ -static void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height) -{ - int x, y, i; - - i = frame_index; - - /* Y */ - for(y=0;y<height;y++) { - for(x=0;x<width;x++) { - pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3; - } - } - - /* Cb and Cr */ - for(y=0;y<height/2;y++) { - for(x=0;x<width/2;x++) { - pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2; - pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5; - } - } -} - -static void write_video_frame(AVFormatContext *oc, AVStream *st) -{ - int out_size, ret; - AVCodecContext *c; - static struct SwsContext *img_convert_ctx; - - c = st->codec; - - if (frame_count >= STREAM_NB_FRAMES) { - /* no more frame to compress. The codec has a latency of a few - frames if using B frames, so we get the last frames by - passing the same picture again */ - } else { - if (c->pix_fmt != PIX_FMT_YUV420P) { - /* as we only generate a YUV420P picture, we must convert it - to the codec pixel format if needed */ - if (img_convert_ctx == NULL) { - img_convert_ctx = sws_getContext(c->width, c->height, - PIX_FMT_YUV420P, - c->width, c->height, - c->pix_fmt, - sws_flags, NULL, NULL, NULL); - if (img_convert_ctx == NULL) { - fprintf(stderr, "Cannot initialize the conversion context\n"); - exit(1); - } - } - fill_yuv_image(tmp_picture, frame_count, c->width, c->height); - sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize, - 0, c->height, picture->data, picture->linesize); - } else { - fill_yuv_image(picture, frame_count, c->width, c->height); - } - } - - - if (oc->oformat->flags & AVFMT_RAWPICTURE) { - /* raw video case. The API will change slightly in the near - futur for that */ - AVPacket pkt; - av_init_packet(&pkt); - - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.stream_index= st->index; - pkt.data= (uint8_t *)picture; - pkt.size= sizeof(AVPicture); - - ret = av_interleaved_write_frame(oc, &pkt); - } else { - /* encode the image */ - out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture); - /* if zero size, it means the image was buffered */ - if (out_size > 0) { - AVPacket pkt; - av_init_packet(&pkt); - - if (c->coded_frame->pts != AV_NOPTS_VALUE) - pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base); - if(c->coded_frame->key_frame) - pkt.flags |= AV_PKT_FLAG_KEY; - pkt.stream_index= st->index; - pkt.data= video_outbuf; - pkt.size= out_size; - - /* write the compressed frame in the media file */ - ret = av_interleaved_write_frame(oc, &pkt); - } else { - ret = 0; - } - } - if (ret != 0) { - fprintf(stderr, "Error while writing video frame\n"); - exit(1); - } - frame_count++; -} - -static void close_video(AVFormatContext *oc, AVStream *st) -{ - avcodec_close(st->codec); - av_free(picture->data[0]); - av_free(picture); - if (tmp_picture) { - av_free(tmp_picture->data[0]); - av_free(tmp_picture); - } - av_free(video_outbuf); -} - -/**************************************************************/ -/* media file output */ - -int main(int argc, char **argv) -{ - const char *filename; - AVOutputFormat *fmt; - AVFormatContext *oc; - AVStream *audio_st, *video_st; - double audio_pts, video_pts; - int i; - - /* initialize libavcodec, and register all codecs and formats */ - av_register_all(); - - if (argc != 2) { - printf("usage: %s output_file\n" - "API example program to output a media file with libavformat.\n" - "The output format is automatically guessed according to the file extension.\n" - "Raw images can also be output by using '%%d' in the filename\n" - "\n", argv[0]); - return 1; - } - - filename = argv[1]; - - /* auto detect the output format from the name. default is - mpeg. */ - fmt = av_guess_format(NULL, filename, NULL); - if (!fmt) { - printf("Could not deduce output format from file extension: using MPEG.\n"); - fmt = av_guess_format("mpeg", NULL, NULL); - } - if (!fmt) { - fprintf(stderr, "Could not find suitable output format\n"); - return 1; - } - - /* allocate the output media context */ - oc = avformat_alloc_context(); - if (!oc) { - fprintf(stderr, "Memory error\n"); - return 1; - } - oc->oformat = fmt; - snprintf(oc->filename, sizeof(oc->filename), "%s", filename); - - /* add the audio and video streams using the default format codecs - and initialize the codecs */ - video_st = NULL; - audio_st = NULL; - if (fmt->video_codec != CODEC_ID_NONE) { - video_st = add_video_stream(oc, fmt->video_codec); - } - if (fmt->audio_codec != CODEC_ID_NONE) { - audio_st = add_audio_stream(oc, fmt->audio_codec); - } - - /* set the output parameters (must be done even if no - parameters). */ - if (av_set_parameters(oc, NULL) < 0) { - fprintf(stderr, "Invalid output format parameters\n"); - return 1; - } - - av_dump_format(oc, 0, filename, 1); - - /* now that all the parameters are set, we can open the audio and - video codecs and allocate the necessary encode buffers */ - if (video_st) - open_video(oc, video_st); - if (audio_st) - open_audio(oc, audio_st); - - /* open the output file, if needed */ - if (!(fmt->flags & AVFMT_NOFILE)) { - if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) { - fprintf(stderr, "Could not open '%s'\n", filename); - return 1; - } - } - - /* write the stream header, if any */ - av_write_header(oc); - - for(;;) { - /* compute current audio and video time */ - if (audio_st) - audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den; - else - audio_pts = 0.0; - - if (video_st) - video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den; - else - video_pts = 0.0; - - if ((!audio_st || audio_pts >= STREAM_DURATION) && - (!video_st || video_pts >= STREAM_DURATION)) - break; - - /* write interleaved audio and video frames */ - if (!video_st || (video_st && audio_st && audio_pts < video_pts)) { - write_audio_frame(oc, audio_st); - } else { - write_video_frame(oc, video_st); - } - } - - /* write the trailer, if any. the trailer must be written - * before you close the CodecContexts open when you wrote the - * header; otherwise write_trailer may try to use memory that - * was freed on av_codec_close() */ - av_write_trailer(oc); - - /* close each codec */ - if (video_st) - close_video(oc, video_st); - if (audio_st) - close_audio(oc, audio_st); - - /* free the streams */ - for(i = 0; i < oc->nb_streams; i++) { - av_freep(&oc->streams[i]->codec); - av_freep(&oc->streams[i]); - } - - if (!(fmt->flags & AVFMT_NOFILE)) { - /* close the output file */ - avio_close(oc->pb); - } - - /* free the stream */ - av_free(oc); - - return 0; -} diff --git a/libavformat/pcm.c b/libavformat/pcm.c index 7d5fed5601..d66be59ccb 100644 --- a/libavformat/pcm.c +++ b/libavformat/pcm.c @@ -2,20 +2,20 @@ * PCM common functions * Copyright (c) 2003 Fabrice Bellard * - * 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/libavformat/pcm.h b/libavformat/pcm.h index 228df1394b..7c0b7d70aa 100644 --- a/libavformat/pcm.h +++ b/libavformat/pcm.h @@ -2,20 +2,20 @@ * PCM common functions * Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/pcmdec.c b/libavformat/pcmdec.c index b61fb33764..542ee17749 100644 --- a/libavformat/pcmdec.c +++ b/libavformat/pcmdec.c @@ -2,20 +2,20 @@ * RAW PCM demuxers * Copyright (c) 2002 Fabrice Bellard * - * 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/libavformat/pcmenc.c b/libavformat/pcmenc.c index 553df1f877..12e64b0fb8 100644 --- a/libavformat/pcmenc.c +++ b/libavformat/pcmenc.c @@ -2,20 +2,20 @@ * RAW PCM muxers * Copyright (c) 2002 Fabrice Bellard * - * 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/libavformat/pmpdec.c b/libavformat/pmpdec.c index 9df39be0a1..4ef8ca3437 100644 --- a/libavformat/pmpdec.c +++ b/libavformat/pmpdec.c @@ -1,21 +1,21 @@ /* - * PMP demuxer + * PMP demuxer. * Copyright (c) 2011 Reimar Döffinger * - * 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,18 +23,18 @@ #include "avformat.h" #include "internal.h" -typedef struct PMPContext { - int cur_stream; - int num_streams; - int audio_packets; - int current_packet; +typedef struct { + int cur_stream; + int num_streams; + int audio_packets; + int current_packet; uint32_t *packet_sizes; - int packet_sizes_alloc; + int packet_sizes_alloc; } PMPContext; -static int pmp_probe(AVProbeData *p) -{ - if (!memcmp(p->buf, "pmpm\1\0\0\0", 8)) +static int pmp_probe(AVProbeData *p) { + if (AV_RN32(p->buf) == AV_RN32("pmpm") && + AV_RL32(p->buf + 4) == 1) return AVPROBE_SCORE_MAX; return 0; } @@ -65,7 +65,7 @@ static int pmp_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Unsupported video format\n"); break; } - index_cnt = avio_rl32(pb); + index_cnt = avio_rl32(pb); vst->codec->width = avio_rl32(pb); vst->codec->height = avio_rl32(pb); @@ -73,14 +73,14 @@ static int pmp_header(AVFormatContext *s) tb_den = avio_rl32(pb); avpriv_set_pts_info(vst, 32, tb_num, tb_den); vst->nb_frames = index_cnt; - vst->duration = index_cnt; + vst->duration = index_cnt; switch (avio_rl32(pb)) { case 0: audio_codec_id = CODEC_ID_MP3; break; case 1: - av_log(s, AV_LOG_WARNING, "AAC is not yet correctly supported\n"); + av_log(s, AV_LOG_ERROR, "AAC not yet correctly supported\n"); audio_codec_id = CODEC_ID_AAC; break; default: @@ -89,21 +89,21 @@ static int pmp_header(AVFormatContext *s) } pmp->num_streams = avio_rl16(pb) + 1; avio_skip(pb, 10); - srate = avio_rl32(pb); + srate = avio_rl32(pb); channels = avio_rl32(pb) + 1; for (i = 1; i < pmp->num_streams; i++) { AVStream *ast = avformat_new_stream(s, NULL); if (!ast) return AVERROR(ENOMEM); - ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - ast->codec->codec_id = audio_codec_id; - ast->codec->channels = channels; + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; + ast->codec->codec_id = audio_codec_id; + ast->codec->channels = channels; ast->codec->sample_rate = srate; avpriv_set_pts_info(ast, 32, 1, srate); } - pos = avio_tell(pb) + 4 * index_cnt; + pos = avio_tell(pb) + 4*index_cnt; for (i = 0; i < index_cnt; i++) { - int size = avio_rl32(pb); + int size = avio_rl32(pb); int flags = size & 1 ? AVINDEX_KEYFRAME : 0; size >>= 1; av_add_index_entry(vst, pos, i, size, 0, flags); @@ -119,7 +119,7 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt) int ret = 0; int i; - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR_EOF; if (pmp->cur_stream == 0) { int num_packets; @@ -138,7 +138,7 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt) pmp->packet_sizes[i] = avio_rl32(pb); } ret = av_get_packet(pb, pkt, pmp->packet_sizes[pmp->current_packet]); - if (ret > 0) { + if (ret >= 0) { ret = 0; // FIXME: this is a hack that should be removed once // compute_pkt_fields() can handle timestamps properly @@ -146,14 +146,13 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt) pkt->dts = s->streams[0]->cur_dts++; pkt->stream_index = pmp->cur_stream; } - pmp->current_packet++; - if (pmp->current_packet == 1 || pmp->current_packet > pmp->audio_packets) + if (pmp->current_packet % pmp->audio_packets == 0) pmp->cur_stream = (pmp->cur_stream + 1) % pmp->num_streams; - + pmp->current_packet++; return ret; } -static int pmp_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags) +static int pmp_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags) { PMPContext *pmp = s->priv_data; pmp->cur_stream = 0; diff --git a/libavformat/psxstr.c b/libavformat/psxstr.c index 988d1f095e..d657197d6f 100644 --- a/libavformat/psxstr.c +++ b/libavformat/psxstr.c @@ -2,20 +2,20 @@ * Sony Playstation (PSX) STR File Demuxer * Copyright (c) 2003 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 */ @@ -69,6 +69,8 @@ static const char sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf static int str_probe(AVProbeData *p) { uint8_t *sector= p->buf; + uint8_t *end= sector + p->buf_size; + int aud=0, vid=0; if (p->buf_size < RAW_CD_SECTOR_SIZE) return 0; @@ -80,20 +82,52 @@ static int str_probe(AVProbeData *p) sector += RIFF_HEADER_SIZE; } - /* look for CD sync header (00, 0xFF x 10, 00) */ - if (memcmp(sector,sync_header,sizeof(sync_header))) - return 0; + while (end - sector >= RAW_CD_SECTOR_SIZE) { + /* look for CD sync header (00, 0xFF x 10, 00) */ + if (memcmp(sector,sync_header,sizeof(sync_header))) + return 0; - if(sector[0x11] >= 32) - return 0; - if( (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_VIDEO - && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_AUDIO - && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_DATA) - return 0; + if (sector[0x11] >= 32) + return 0; + + switch (sector[0x12] & CDXA_TYPE_MASK) { + case CDXA_TYPE_DATA: + case CDXA_TYPE_VIDEO: { + int current_sector = AV_RL16(§or[0x1C]); + int sector_count = AV_RL16(§or[0x1E]); + int frame_size = AV_RL32(§or[0x24]); + + if(!( frame_size>=0 + && current_sector < sector_count + && sector_count*VIDEO_DATA_CHUNK_SIZE >=frame_size)){ + return 0; + } + /*st->codec->width = AV_RL16(§or[0x28]); + st->codec->height = AV_RL16(§or[0x2A]);*/ + +// if (current_sector == sector_count-1) { + vid++; +// } + + } + break; + case CDXA_TYPE_AUDIO: + if(sector[0x13]&0x2A) + return 0; + aud++; + break; + default: + if(sector[0x12] & CDXA_TYPE_MASK) + return 0; + } + sector += RAW_CD_SECTOR_SIZE; + } /* MPEG files (like those ripped from VCDs) can also look like this; * only return half certainty */ - return 50; + if(vid+aud > 3) return 50; + else if(vid+aud) return 1; + else return 0; } static int str_read_header(AVFormatContext *s) @@ -240,7 +274,7 @@ static int str_read_packet(AVFormatContext *s, break; } - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); } } diff --git a/libavformat/pva.c b/libavformat/pva.c index 21373a5367..199f7bc651 100644 --- a/libavformat/pva.c +++ b/libavformat/pva.c @@ -2,20 +2,20 @@ * TechnoTrend PVA (.pva) demuxer * Copyright (c) 2007, 2008 Ivo van Poorten * - * 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 */ @@ -32,13 +32,26 @@ typedef struct { int continue_pes; } PVAContext; +static int pva_check(uint8_t *p) { + int length = AV_RB16(p + 6); + if (AV_RB16(p) != PVA_MAGIC || !p[2] || p[2] > 2 || p[4] != 0x55 || + (p[5] & 0xe0) || length > PVA_MAX_PAYLOAD_LENGTH) + return -1; + return length + 8; +} + static int pva_probe(AVProbeData * pd) { unsigned char *buf = pd->buf; + int len = pva_check(buf); - if (AV_RB16(buf) == PVA_MAGIC && buf[2] && buf[2] < 3 && buf[4] == 0x55) + if (len < 0) + return 0; + + if (pd->buf_size >= len + 8 && + pva_check(buf + len) >= 0) return AVPROBE_SCORE_MAX / 2; - return 0; + return AVPROBE_SCORE_MAX / 4; } static int pva_read_header(AVFormatContext *s) { diff --git a/libavformat/qcp.c b/libavformat/qcp.c index 6545a1cdfd..929fce48e9 100644 --- a/libavformat/qcp.c +++ b/libavformat/qcp.c @@ -2,20 +2,20 @@ * QCP format (.qcp) demuxer * Copyright (c) 2009 Kenan Gillet * - * 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 */ @@ -139,7 +139,7 @@ static int qcp_read_packet(AVFormatContext *s, AVPacket *pkt) QCPContext *c = s->priv_data; unsigned int chunk_size, tag; - while(!pb->eof_reached) { + while(!url_feof(pb)) { if (c->data_size) { int pkt_size, ret, mode = avio_r8(pb); diff --git a/libavformat/qtpalette.h b/libavformat/qtpalette.h index ecc85d3408..7d6802f73c 100644 --- a/libavformat/qtpalette.h +++ b/libavformat/qtpalette.h @@ -3,20 +3,20 @@ * Automatically generated from a utility derived from XAnim: * http://xanim.va.pubnix.com/home.html * - * 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/libavformat/r3d.c b/libavformat/r3d.c index 7f0e8de0e4..1e0e73ea6b 100644 --- a/libavformat/r3d.c +++ b/libavformat/r3d.c @@ -2,20 +2,20 @@ * R3D REDCODE demuxer * Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot 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 */ @@ -366,7 +366,8 @@ static int r3d_seek(AVFormatContext *s, int stream_index, int64_t sample_time, i frame_num, sample_time); if (frame_num < r3d->video_offsets_count) { - avio_seek(s->pb, r3d->video_offsets_count, SEEK_SET); + if (avio_seek(s->pb, r3d->video_offsets_count, SEEK_SET) < 0) + return -1; } else { av_log(s, AV_LOG_ERROR, "could not seek to frame %d\n", frame_num); return -1; diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c index 9400a0bd32..f7c0de8c25 100644 --- a/libavformat/rawdec.c +++ b/libavformat/rawdec.c @@ -3,20 +3,20 @@ * Copyright (c) 2001 Fabrice Bellard * Copyright (c) 2005 Alex Beregszaszi * - * 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 */ @@ -57,6 +57,12 @@ int ff_raw_read_header(AVFormatContext *s) if (s1 && s1->sample_rate) st->codec->sample_rate = s1->sample_rate; + if (st->codec->sample_rate <= 0) { + av_log(s, AV_LOG_WARNING, "Invalid sample rate %d specified using default of 44100\n", + st->codec->sample_rate); + st->codec->sample_rate= 44100; + } + if (s1 && s1->channels) st->codec->channels = s1->channels; @@ -116,7 +122,7 @@ int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt) av_free_packet(pkt); return ret; } - pkt->size = ret; + av_shrink_packet(pkt, ret); return ret; } @@ -158,7 +164,7 @@ int ff_raw_video_read_header(AVFormatContext *s) goto fail; } - st->r_frame_rate = st->avg_frame_rate = framerate; + st->codec->time_base = (AVRational){framerate.den, framerate.num}; avpriv_set_pts_info(st, 64, 1, 1200000); fail: @@ -199,7 +205,7 @@ AVInputFormat ff_latm_demuxer = { #endif #if CONFIG_MJPEG_DEMUXER -FF_DEF_RAWVIDEO_DEMUXER(mjpeg, "raw MJPEG video", NULL, "mjpg,mjpeg", CODEC_ID_MJPEG) +FF_DEF_RAWVIDEO_DEMUXER(mjpeg, "raw MJPEG video", NULL, "mjpg,mjpeg,mpo", CODEC_ID_MJPEG) #endif #if CONFIG_MLP_DEMUXER diff --git a/libavformat/rawdec.h b/libavformat/rawdec.h index cfb1689cd9..844a28824d 100644 --- a/libavformat/rawdec.h +++ b/libavformat/rawdec.h @@ -2,20 +2,20 @@ * RAW demuxers * Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/rawenc.c b/libavformat/rawenc.c index 6e9f4b78ec..4c1ede4928 100644 --- a/libavformat/rawenc.c +++ b/libavformat/rawenc.c @@ -3,20 +3,20 @@ * Copyright (c) 2001 Fabrice Bellard * Copyright (c) 2005 Alex Beregszaszi * - * 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 */ @@ -120,6 +120,19 @@ AVOutputFormat ff_g722_muxer = { }; #endif +#if CONFIG_G723_1_MUXER +AVOutputFormat ff_g723_1_muxer = { + .name = "g723_1", + .long_name = NULL_IF_CONFIG_SMALL("raw G.723.1"), + .mime_type = "audio/g723", + .extensions = "tco,rco", + .audio_codec = CODEC_ID_G723_1, + .video_codec = CODEC_ID_NONE, + .write_packet = ff_raw_write_packet, + .flags= AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_H261_MUXER AVOutputFormat ff_h261_muxer = { .name = "h261", diff --git a/libavformat/rawenc.h b/libavformat/rawenc.h index daa5489da8..b5523090b8 100644 --- a/libavformat/rawenc.h +++ b/libavformat/rawenc.h @@ -2,20 +2,20 @@ * RAW muxers * Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/rawvideodec.c b/libavformat/rawvideodec.c index 6ca17d5253..8bd0dc92f0 100644 --- a/libavformat/rawvideodec.c +++ b/libavformat/rawvideodec.c @@ -2,20 +2,20 @@ * RAW video demuxer * Copyright (c) 2001 Fabrice Bellard * - * 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/libavformat/rdt.c b/libavformat/rdt.c index 207fc92542..d153028ac4 100644 --- a/libavformat/rdt.c +++ b/libavformat/rdt.c @@ -2,20 +2,20 @@ * Realmedia RTSP protocol (RDT) support. * Copyright (c) 2007 Ronald S. Bultje * - * 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/libavformat/rdt.h b/libavformat/rdt.h index a393299415..c2ec94b8b4 100644 --- a/libavformat/rdt.h +++ b/libavformat/rdt.h @@ -2,20 +2,20 @@ * Realmedia RTSP (RDT) definitions * Copyright (c) 2007 Ronald S. Bultje <rbultje@ronald.bitfreak.net> * - * 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/libavformat/riff.c b/libavformat/riff.c index 99a8033732..4efd1ad756 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -2,20 +2,20 @@ * RIFF codec tags * Copyright (c) 2000 Fabrice Bellard * - * 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 */ @@ -36,6 +36,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, { CODEC_ID_H264, MKTAG('D', 'A', 'V', 'C') }, { CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') }, + { CODEC_ID_H264, MKTAG('Q', '2', '6', '4') }, /* QNAP surveillance system */ { CODEC_ID_H263, MKTAG('H', '2', '6', '3') }, { CODEC_ID_H263, MKTAG('X', '2', '6', '3') }, { CODEC_ID_H263, MKTAG('T', '2', '6', '3') }, @@ -88,6 +89,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_MPEG4, MKTAG('S', 'I', 'P', 'P') }, /* Samsung SHR-6040 */ { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'X') }, { CODEC_ID_MPEG4, MKTAG('D', 'r', 'e', 'X') }, + { CODEC_ID_MPEG4, MKTAG('Q', 'M', 'P', '4') }, /* QNAP Systems */ { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') }, { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') }, { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') }, @@ -133,6 +135,8 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_MPEG2VIDEO, MKTAG('E', 'M', '2', 'V') }, { CODEC_ID_MPEG2VIDEO, MKTAG('M', '7', '0', '1') }, /* Matrox MPEG2 intra-only */ { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', 'v') }, + { CODEC_ID_MPEG1VIDEO, MKTAG('B', 'W', '1', '0') }, + { CODEC_ID_MPEG1VIDEO, MKTAG('X', 'M', 'P', 'G') }, /* Xing MPEG intra only */ { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') }, { CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') }, { CODEC_ID_MJPEG, MKTAG('d', 'm', 'b', '1') }, @@ -197,7 +201,9 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_R10K, MKTAG('R', '1', '0', 'k') }, { CODEC_ID_R210, MKTAG('r', '2', '1', '0') }, { CODEC_ID_V210, MKTAG('v', '2', '1', '0') }, + { CODEC_ID_V308, MKTAG('v', '3', '0', '8') }, { CODEC_ID_V410, MKTAG('v', '4', '1', '0') }, + { CODEC_ID_YUV4, MKTAG('y', 'u', 'v', '4') }, { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') }, { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') }, { CODEC_ID_INDEO4, MKTAG('I', 'V', '4', '1') }, @@ -234,6 +240,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') }, { CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') }, { CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') }, + { CODEC_ID_FLV1, MKTAG('S', '2', '6', '3') }, { CODEC_ID_FLASHSV, MKTAG('F', 'S', 'V', '1') }, { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') }, { CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') }, @@ -277,12 +284,18 @@ const AVCodecTag ff_codec_bmp_tags[] = { { CODEC_ID_DPX, MKTAG('d', 'p', 'x', ' ') }, { CODEC_ID_KGV1, MKTAG('K', 'G', 'V', '1') }, { CODEC_ID_LAGARITH, MKTAG('L', 'A', 'G', 'S') }, + { CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') }, + { CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') }, + { CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') }, + { CODEC_ID_AMV, MKTAG('A', 'M', 'V', 'F') }, { CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'A') }, { CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'G') }, { CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '0') }, { CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') }, { CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, + { CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, + { CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') }, { CODEC_ID_NONE, 0 } }; @@ -302,6 +315,7 @@ const AVCodecTag ff_codec_wav_tags[] = { { CODEC_ID_ADPCM_YAMAHA, 0x0020 }, { CODEC_ID_TRUESPEECH, 0x0022 }, { CODEC_ID_GSM_MS, 0x0031 }, + { CODEC_ID_AMR_NB, 0x0038 }, /* rogue format number */ { CODEC_ID_ADPCM_G726, 0x0045 }, { CODEC_ID_MP2, 0x0050 }, { CODEC_ID_MP3, 0x0055 }, @@ -327,6 +341,8 @@ const AVCodecTag ff_codec_wav_tags[] = { { CODEC_ID_AAC_LATM, 0x1602 }, { CODEC_ID_AC3, 0x2000 }, { CODEC_ID_DTS, 0x2001 }, + { CODEC_ID_SONIC, 0x2048 }, + { CODEC_ID_SONIC_LS, 0x2048 }, { CODEC_ID_PCM_MULAW, 0x6c75 }, { CODEC_ID_AAC, 0x706d }, { CODEC_ID_AAC, 0x4143 }, @@ -343,6 +359,14 @@ const AVCodecTag ff_codec_wav_tags[] = { { CODEC_ID_NONE, 0 }, }; +const AVCodecGuid ff_codec_wav_guids[] = { + {CODEC_ID_AC3, {0x2C,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, + {CODEC_ID_ATRAC3P, {0xBF,0xAA,0x23,0xE9,0x58,0xCB,0x71,0x44,0xA1,0x19,0xFF,0xFA,0x01,0xE4,0xCE,0x62}}, + {CODEC_ID_EAC3, {0xAF,0x87,0xFB,0xA7,0x02,0x2D,0xFB,0x42,0xA4,0xD4,0x05,0xCD,0x93,0x84,0x3B,0xDD}}, + {CODEC_ID_MP2, {0x2B,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, + {CODEC_ID_NONE} +}; + const AVMetadataConv ff_riff_info_conv[] = { { "IART", "artist" }, { "ICMT", "comment" }, @@ -471,7 +495,7 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) if(waveformatextensible) { /* write WAVEFORMATEXTENSIBLE extensions */ hdrsize += 22; avio_wl16(pb, riff_extradata - riff_extradata_start + 22); /* 22 is WAVEFORMATEXTENSIBLE size */ - avio_wl16(pb, enc->bits_per_coded_sample); /* ValidBitsPerSample || SamplesPerBlock || Reserved */ + 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); @@ -501,7 +525,7 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *t 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 * 3); + 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); @@ -528,7 +552,6 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) id = avio_rl16(pb); codec->codec_type = AVMEDIA_TYPE_AUDIO; - codec->codec_tag = id; codec->channels = avio_rl16(pb); codec->sample_rate = avio_rl32(pb); codec->bit_rate = avio_rl32(pb) * 8; @@ -537,15 +560,29 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) 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; codec->bits_per_coded_sample = avio_rl16(pb); codec->channel_layout = avio_rl32(pb); /* dwChannelMask */ - id = avio_rl32(pb); /* 4 first bytes of GUID */ - avio_skip(pb, 12); /* skip end of GUID */ + 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; } @@ -563,7 +600,6 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size) if (size > 0) avio_skip(pb, size); } - codec->codec_id = ff_wav_codec_get_id(id, codec->bits_per_coded_sample); if (codec->codec_id == CODEC_ID_AAC_LATM) { /* channels and sample_rate values are those prior to applying SBR and/or PS */ codec->channels = 0; @@ -637,6 +673,23 @@ void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssiz *au_rate /= gcd; } +void ff_get_guid(AVIOContext *s, ff_asf_guid *g) +{ + assert(sizeof(*g) == 16); + if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) + memset(*g, 0, sizeof(*g)); +} + +enum CodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) +{ + int i; + for (i = 0; guids[i].id != CODEC_ID_NONE; i++) { + if (!ff_guidcmp(guids[i].guid, guid)) + return guids[i].id; + } + return CODEC_ID_NONE; +} + int ff_read_riff_info(AVFormatContext *s, int64_t size) { int64_t start, end, cur; @@ -669,7 +722,7 @@ int ff_read_riff_info(AVFormatContext *s, int64_t size) AV_WL32(key, chunk_code); if (avio_read(pb, value, chunk_size) != chunk_size) { - av_free(value); + av_freep(&value); av_log(s, AV_LOG_ERROR, "premature end of file while reading INFO tag\n"); return AVERROR_INVALIDDATA; } diff --git a/libavformat/riff.h b/libavformat/riff.h index 3bd309f86b..67521e25cc 100644 --- a/libavformat/riff.h +++ b/libavformat/riff.h @@ -2,20 +2,20 @@ * RIFF codec tags * copyright (c) 2000 Fabrice Bellard * - * 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 */ @@ -58,6 +58,32 @@ unsigned int ff_codec_get_tag(const AVCodecTag *tags, enum CodecID id); enum CodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag); void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale); +typedef uint8_t ff_asf_guid[16]; + int ff_read_riff_info(AVFormatContext *s, int64_t size); +#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] + +static av_always_inline int ff_guidcmp(const void *g1, const void *g2) +{ + return memcmp(g1, g2, sizeof(ff_asf_guid)); +} + +void ff_get_guid(AVIOContext *s, ff_asf_guid *g); + +typedef struct { + enum CodecID id; + ff_asf_guid guid; +} AVCodecGuid; + +enum CodecID 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 + #endif /* AVFORMAT_RIFF_H */ diff --git a/libavformat/rl2.c b/libavformat/rl2.c index 8ec76ff921..b160098150 100644 --- a/libavformat/rl2.c +++ b/libavformat/rl2.c @@ -2,20 +2,20 @@ * RL2 Format Demuxer * Copyright (c) 2008 Sascha Sommer (saschasommer@freenet.de) * - * 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 */ @@ -137,6 +137,9 @@ static av_cold int rl2_read_header(AVFormatContext *s) /** setup audio stream if present */ if(sound_rate){ + if(channels <= 0) + return AVERROR_INVALIDDATA; + pts_num = def_sound_size; pts_den = rate; diff --git a/libavformat/rm.c b/libavformat/rm.c index 9c0ad4a58b..f2942964d4 100644 --- a/libavformat/rm.c +++ b/libavformat/rm.c @@ -2,20 +2,20 @@ * "Real" compatible muxer and demuxer common code. * Copyright (c) 2009 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/rm.h b/libavformat/rm.h index 9d104ad74c..6de10924ab 100644 --- a/libavformat/rm.h +++ b/libavformat/rm.h @@ -2,20 +2,20 @@ * "Real" compatible muxer and demuxer. * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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/libavformat/rmdec.c b/libavformat/rmdec.c index ee8abdd800..68383b2d21 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -2,20 +2,20 @@ * "Real" compatible demuxer. * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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 */ @@ -233,6 +233,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, } if ((ret = rm_read_extradata(pb, st->codec, codecdata_length)) < 0) return ret; + break; case CODEC_ID_AAC: avio_rb16(pb); avio_r8(pb); @@ -313,7 +314,7 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb, int fps; if (avio_rl32(pb) != MKTAG('V', 'I', 'D', 'O')) { fail1: - av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n"); + av_log(s, AV_LOG_WARNING, "Unsupported stream type %08x\n", v); goto skip; } st->codec->codec_tag = avio_rl32(pb); @@ -429,7 +430,7 @@ static int rm_read_header(AVFormatContext *s) avio_rb32(pb); /* number of headers */ for(;;) { - if (pb->eof_reached) + if (url_feof(pb)) return -1; tag = avio_rl32(pb); tag_size = avio_rb32(pb); @@ -533,7 +534,7 @@ static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_ AVStream *st; uint32_t state=0xFFFFFFFF; - while(!pb->eof_reached){ + while(!url_feof(pb)){ int len, num, i; *pos= avio_tell(pb) - 3; if(rm->remaining_len > 0){ @@ -869,7 +870,7 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) st = s->streams[i]; } - if(len<0 || s->pb->eof_reached) + if(len<0 || url_feof(s->pb)) return AVERROR(EIO); res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, @@ -925,7 +926,9 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index, if(rm->old_format) return AV_NOPTS_VALUE; - avio_seek(s->pb, pos, SEEK_SET); + if (avio_seek(s->pb, pos, SEEK_SET) < 0) + return AV_NOPTS_VALUE; + rm->remaining_len=0; for(;;){ int seq=1; diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c index 0312d161c7..b3d0cf6a66 100644 --- a/libavformat/rmenc.c +++ b/libavformat/rmenc.c @@ -2,20 +2,20 @@ * "Real" compatible muxer. * Copyright (c) 2000, 2001 Fabrice Bellard * - * 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" diff --git a/libavformat/rpl.c b/libavformat/rpl.c index 3454fbe491..c1c66b77b4 100644 --- a/libavformat/rpl.c +++ b/libavformat/rpl.c @@ -2,20 +2,20 @@ * ARMovie/RPL demuxer * Copyright (c) 2007 Christian Ohm, 2008 Eli Friedman * - * 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 */ @@ -58,7 +58,7 @@ static int read_line(AVIOContext * pb, char* line, int bufsize) break; if (b == '\n') { line[i] = '\0'; - return 0; + return url_feof(pb) ? -1 : 0; } line[i] = b; } @@ -164,11 +164,9 @@ static int rpl_read_header(AVFormatContext *s) // The header is wrong here, at least sometimes vst->codec->bits_per_coded_sample = 16; break; -#if 0 case 130: vst->codec->codec_id = CODEC_ID_ESCAPE130; break; -#endif default: av_log(s, AV_LOG_WARNING, "RPL video format %i not supported yet!\n", @@ -254,7 +252,7 @@ static int rpl_read_header(AVFormatContext *s) // Read the index avio_seek(pb, chunk_catalog_offset, SEEK_SET); total_audio_size = 0; - for (i = 0; i < number_of_chunks; i++) { + 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, diff --git a/libavformat/rso.c b/libavformat/rso.c index fc39abcc8a..178fd3f224 100644 --- a/libavformat/rso.c +++ b/libavformat/rso.c @@ -2,20 +2,20 @@ * RSO format common data * Copyright (c) 2010 Rafael Carre * - * 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/libavformat/rso.h b/libavformat/rso.h index e3e88ea644..1f65dd90c7 100644 --- a/libavformat/rso.h +++ b/libavformat/rso.h @@ -2,20 +2,20 @@ * RSO format common data * Copyright (c) 2010 Rafael Carre * - * 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/libavformat/rsodec.c b/libavformat/rsodec.c index c148b2ee57..9c9f815e66 100644 --- a/libavformat/rsodec.c +++ b/libavformat/rsodec.c @@ -3,20 +3,20 @@ * Copyright (c) 2001 Fabrice Bellard (original AU code) * Copyright (c) 2010 Rafael Carre * - * 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/libavformat/rsoenc.c b/libavformat/rsoenc.c index f338d0df4e..ef4350b970 100644 --- a/libavformat/rsoenc.c +++ b/libavformat/rsoenc.c @@ -3,20 +3,20 @@ * Copyright (c) 2001 Fabrice Bellard (original AU code) * Copyright (c) 2010 Rafael Carre * - * 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/libavformat/rtmp.h b/libavformat/rtmp.h index 45de73ef2b..b0436c0391 100644 --- a/libavformat/rtmp.h +++ b/libavformat/rtmp.h @@ -2,20 +2,20 @@ * RTMP definitions * Copyright (c) 2009 Kostya 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 */ diff --git a/libavformat/rtmppkt.c b/libavformat/rtmppkt.c index 8c455a09f0..61e159b06a 100644 --- a/libavformat/rtmppkt.c +++ b/libavformat/rtmppkt.c @@ -2,20 +2,20 @@ * RTMP input format * Copyright (c) 2009 Kostya 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 */ diff --git a/libavformat/rtmppkt.h b/libavformat/rtmppkt.h index 8372484fbd..8acbfc116b 100644 --- a/libavformat/rtmppkt.h +++ b/libavformat/rtmppkt.h @@ -2,20 +2,20 @@ * RTMP packet utilities * Copyright (c) 2009 Kostya 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 */ diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 867969a670..a2c7b5da88 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -2,20 +2,20 @@ * RTMP network protocol * Copyright (c) 2009 Kostya 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 */ @@ -700,7 +700,7 @@ static int get_packet(URLContext *s, int for_header) } } rt->bytes_read += ret; - if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) { + if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) { av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n"); gen_bytes_read(s, rt, rpkt.timestamp + 1); rt->last_bytes_read = rt->bytes_read; diff --git a/libavformat/rtp.c b/libavformat/rtp.c index b6b4b72aa3..98d96160db 100644 --- a/libavformat/rtp.c +++ b/libavformat/rtp.c @@ -2,20 +2,20 @@ * RTP input/output format * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -44,7 +44,7 @@ static const struct { {0, "PCMU", AVMEDIA_TYPE_AUDIO, CODEC_ID_PCM_MULAW, 8000, 1}, {3, "GSM", AVMEDIA_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, - {4, "G723", AVMEDIA_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, + {4, "G723", AVMEDIA_TYPE_AUDIO, CODEC_ID_G723_1, 8000, 1}, {5, "DVI4", AVMEDIA_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, {6, "DVI4", AVMEDIA_TYPE_AUDIO, CODEC_ID_NONE, 16000, 1}, {7, "LPC", AVMEDIA_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1}, diff --git a/libavformat/rtp.h b/libavformat/rtp.h index e619008007..23588755ec 100644 --- a/libavformat/rtp.h +++ b/libavformat/rtp.h @@ -2,20 +2,20 @@ * RTP definitions * Copyright (c) 2002 Fabrice Bellard * - * 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 */ #ifndef AVFORMAT_RTP_H diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 3442c9b2b1..7170e97ec9 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -2,20 +2,20 @@ * RTP input format * Copyright (c) 2002 Fabrice Bellard * - * 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/libavformat/rtpdec.h b/libavformat/rtpdec.h index 9e2bfd01d5..db44443479 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -3,20 +3,20 @@ * Copyright (c) 2002 Fabrice Bellard * Copyright (c) 2006 Ryan Martell <rdm4@martellventures.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 */ #ifndef AVFORMAT_RTPDEC_H diff --git a/libavformat/rtpdec_amr.c b/libavformat/rtpdec_amr.c index b7ff3aa05e..fbf4321698 100644 --- a/libavformat/rtpdec_amr.c +++ b/libavformat/rtpdec_amr.c @@ -2,20 +2,20 @@ * RTP AMR Depacketizer, RFC 3267 * Copyright (c) 2010 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/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index 483b196d62..e6586b036a 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -2,20 +2,20 @@ * Microsoft RTP/ASF support. * Copyright (c) 2008 Ronald S. Bultje * - * 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/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h index 3074565db7..afd047be21 100644 --- a/libavformat/rtpdec_formats.h +++ b/libavformat/rtpdec_formats.h @@ -2,20 +2,20 @@ * RTP depacketizer declarations * Copyright (c) 2010 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/libavformat/rtpdec_g726.c b/libavformat/rtpdec_g726.c index 4a0b6acf59..20450d8dfb 100644 --- a/libavformat/rtpdec_g726.c +++ b/libavformat/rtpdec_g726.c @@ -1,20 +1,20 @@ /* * Copyright (c) 2011 Miroslav Slugeň <Thunder.m@seznam.cz> * - * 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/libavformat/rtpdec_h263.c b/libavformat/rtpdec_h263.c index 0fb1b25eb0..ea42fff320 100644 --- a/libavformat/rtpdec_h263.c +++ b/libavformat/rtpdec_h263.c @@ -2,20 +2,20 @@ * RTP H.263 Depacketizer, RFC 4629 * Copyright (c) 2010 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/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c index effdc1fe66..730ed14807 100644 --- a/libavformat/rtpdec_h264.c +++ b/libavformat/rtpdec_h264.c @@ -2,20 +2,20 @@ * RTP H264 Protocol (RFC3984) * Copyright (c) 2006 Ryan Martell * - * 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/libavformat/rtpdec_latm.c b/libavformat/rtpdec_latm.c index 96f4e83c6e..f08415dde7 100644 --- a/libavformat/rtpdec_latm.c +++ b/libavformat/rtpdec_latm.c @@ -2,20 +2,20 @@ * RTP Depacketization of MP4A-LATM, RFC 3016 * Copyright (c) 2010 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/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c index b143c1aee8..f6547bc70e 100644 --- a/libavformat/rtpdec_mpeg4.c +++ b/libavformat/rtpdec_mpeg4.c @@ -3,20 +3,20 @@ * Copyright (c) 2010 Fabrice Bellard * Romain Degez * - * 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/libavformat/rtpdec_qcelp.c b/libavformat/rtpdec_qcelp.c index 325683c396..5eb6770297 100644 --- a/libavformat/rtpdec_qcelp.c +++ b/libavformat/rtpdec_qcelp.c @@ -2,20 +2,20 @@ * RTP Depacketization of QCELP/PureVoice, RFC 2658 * Copyright (c) 2010 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/libavformat/rtpdec_qdm2.c b/libavformat/rtpdec_qdm2.c index 76b4c5317d..0802b80dc3 100644 --- a/libavformat/rtpdec_qdm2.c +++ b/libavformat/rtpdec_qdm2.c @@ -2,20 +2,20 @@ * QDesign Music 2 (QDM2) payload for RTP * Copyright (c) 2010 Ronald S. Bultje * - * 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/libavformat/rtpdec_qt.c b/libavformat/rtpdec_qt.c index 10371547d1..33cb3dab4e 100644 --- a/libavformat/rtpdec_qt.c +++ b/libavformat/rtpdec_qt.c @@ -2,20 +2,20 @@ * RTP/Quicktime support. * Copyright (c) 2009 Ronald S. Bultje * - * 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/libavformat/rtpdec_svq3.c b/libavformat/rtpdec_svq3.c index 4df3e3a3e0..7800766ecf 100644 --- a/libavformat/rtpdec_svq3.c +++ b/libavformat/rtpdec_svq3.c @@ -2,20 +2,20 @@ * Sorenson-3 (SVQ3/SV3V) payload for RTP * Copyright (c) 2010 Ronald S. Bultje * - * 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/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c index d13c3982df..bfc96570d1 100644 --- a/libavformat/rtpdec_vp8.c +++ b/libavformat/rtpdec_vp8.c @@ -2,20 +2,20 @@ * RTP VP8 Depacketizer * Copyright (c) 2010 Josh Allmann * - * 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/libavformat/rtpdec_xiph.c b/libavformat/rtpdec_xiph.c index a7f36ef59a..6aeea2fd3c 100644 --- a/libavformat/rtpdec_xiph.c +++ b/libavformat/rtpdec_xiph.c @@ -3,20 +3,20 @@ * Copyright (c) 2009 Colin McQuillian * Copyright (c) 2010 Josh Allmann * - * 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/libavformat/rtpenc.c b/libavformat/rtpenc.c index 1f036a6baf..ac9b32cc0c 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -2,20 +2,20 @@ * RTP output format * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -89,7 +89,7 @@ static int rtp_write_header(AVFormatContext *s1) return -1; st = s1->streams[0]; if (!is_supported(st->codec->codec_id)) { - av_log(s1, AV_LOG_ERROR, "Unsupported codec %x\n", st->codec->codec_id); + av_log(s1, AV_LOG_ERROR, "Unsupported codec %s\n", avcodec_get_name(st->codec->codec_id)); return -1; } diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h index 72d7f65783..901336322d 100644 --- a/libavformat/rtpenc.h +++ b/libavformat/rtpenc.h @@ -2,20 +2,20 @@ * RTP muxer definitions * Copyright (c) 2002 Fabrice Bellard * - * 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 */ #ifndef AVFORMAT_RTPENC_H diff --git a/libavformat/rtpenc_aac.c b/libavformat/rtpenc_aac.c index 86318dfa6e..e19b28697e 100644 --- a/libavformat/rtpenc_aac.c +++ b/libavformat/rtpenc_aac.c @@ -1,20 +1,20 @@ /* * copyright (c) 2007 Luca Abeni * - * 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/libavformat/rtpenc_amr.c b/libavformat/rtpenc_amr.c index 4da7ace32a..367789fccd 100644 --- a/libavformat/rtpenc_amr.c +++ b/libavformat/rtpenc_amr.c @@ -3,20 +3,20 @@ * Copyright (c) 2007 Luca Abeni * Copyright (c) 2009 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/libavformat/rtpenc_chain.c b/libavformat/rtpenc_chain.c index b9d1690008..8a5adf54ed 100644 --- a/libavformat/rtpenc_chain.c +++ b/libavformat/rtpenc_chain.c @@ -2,20 +2,20 @@ * RTP muxer chaining code * Copyright (c) 2010 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 */ @@ -53,6 +53,7 @@ AVFormatContext *ff_rtp_chain_mux_open(AVFormatContext *s, AVStream *st, rtpctx->max_delay = s->max_delay; /* Copy other stream parameters. */ rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; + rtpctx->flags |= s->flags & AVFMT_FLAG_MP4A_LATM; if (av_opt_get(s, "rtpflags", AV_OPT_SEARCH_CHILDREN, &rtpflags) >= 0) av_dict_set(&opts, "rtpflags", rtpflags, AV_DICT_DONT_STRDUP_VAL); diff --git a/libavformat/rtpenc_chain.h b/libavformat/rtpenc_chain.h index 6bdddcfe99..8e6b80aa3f 100644 --- a/libavformat/rtpenc_chain.h +++ b/libavformat/rtpenc_chain.h @@ -2,20 +2,20 @@ * RTP muxer chaining code * Copyright (c) 2010 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/libavformat/rtpenc_h263.c b/libavformat/rtpenc_h263.c index fbc696e1b4..84403a1069 100644 --- a/libavformat/rtpenc_h263.c +++ b/libavformat/rtpenc_h263.c @@ -3,20 +3,20 @@ * Copyright (c) 2009 Luca Abeni * Copyright (c) 2009 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/libavformat/rtpenc_h264.c b/libavformat/rtpenc_h264.c index 776da83a62..86930bbac1 100644 --- a/libavformat/rtpenc_h264.c +++ b/libavformat/rtpenc_h264.c @@ -2,20 +2,20 @@ * RTP packetization for H.264 (RFC3984) * Copyright (c) 2008 Luca Abeni * - * 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/libavformat/rtpenc_latm.c b/libavformat/rtpenc_latm.c index 64676771a7..7535a0fd5f 100644 --- a/libavformat/rtpenc_latm.c +++ b/libavformat/rtpenc_latm.c @@ -2,9 +2,9 @@ * RTP Packetization of MPEG-4 Audio (RFC 3016) * Copyright (c) 2011 Juan Carlos Rodriguez <ing.juancarlosrodriguez@hotmail.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. diff --git a/libavformat/rtpenc_mpv.c b/libavformat/rtpenc_mpv.c index 1c67f9593b..0c617337b2 100644 --- a/libavformat/rtpenc_mpv.c +++ b/libavformat/rtpenc_mpv.c @@ -3,20 +3,20 @@ * Copyright (c) 2002 Fabrice Bellard * Copyright (c) 2007 Luca Abeni * - * 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/libavformat/rtpenc_vp8.c b/libavformat/rtpenc_vp8.c index afedbb49c0..e865514cef 100644 --- a/libavformat/rtpenc_vp8.c +++ b/libavformat/rtpenc_vp8.c @@ -2,20 +2,20 @@ * RTP VP8 Packetizer * Copyright (c) 2010 Josh Allmann * - * 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/libavformat/rtpenc_xiph.c b/libavformat/rtpenc_xiph.c index 07086b1a12..57686326a8 100644 --- a/libavformat/rtpenc_xiph.c +++ b/libavformat/rtpenc_xiph.c @@ -2,20 +2,20 @@ * RTP packetization for Xiph audio and video * Copyright (c) 2010 Josh Allmann * - * 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/libavformat/rtpproto.c b/libavformat/rtpproto.c index 03794ae1ce..4ce1d6bbbb 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -2,20 +2,20 @@ * RTP network protocol * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -115,6 +115,7 @@ static void build_udp_url(char *buf, int buf_size, url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size); if (connect) url_add_option(buf, buf_size, "connect=1"); + url_add_option(buf, buf_size, "fifo_size=0"); } /** diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index c47cb0e4f1..4a0e8bffee 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -2,20 +2,20 @@ * RTSP/SDP client * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -1119,10 +1119,6 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, /* default timeout: 1 minute */ rt->timeout = 60; - /* for each stream, make the setup request */ - /* XXX: we assume the same server is used for the control of each - * RTSP stream */ - /* Choose a random starting offset within the first half of the * port range, to allow for a number of ports to try even if the offset * happens to be at the end of the random range. */ @@ -1176,7 +1172,6 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, &s->interrupt_callback, NULL)) goto rtp_opened; } - av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n"); err = AVERROR(EIO); goto fail; diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 6872a51a24..f67ceb89ca 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -2,20 +2,20 @@ * RTSP definitions * Copyright (c) 2002 Fabrice Bellard * - * 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 */ #ifndef AVFORMAT_RTSP_H @@ -70,7 +70,7 @@ enum RTSPControlTransport { #define RTSP_DEFAULT_NB_AUDIO_CHANNELS 1 #define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100 #define RTSP_RTP_PORT_MIN 5000 -#define RTSP_RTP_PORT_MAX 10000 +#define RTSP_RTP_PORT_MAX 65000 /** * This describes a single item in the "Transport:" line of one stream as diff --git a/libavformat/rtspcodes.h b/libavformat/rtspcodes.h index 63ceb66cfe..9ee96bfcd0 100644 --- a/libavformat/rtspcodes.h +++ b/libavformat/rtspcodes.h @@ -2,20 +2,20 @@ * RTSP definitions * copyright (c) 2002 Fabrice Bellard * - * 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/libavformat/rtspdec.c b/libavformat/rtspdec.c index 785d162b41..18a76ab626 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -2,20 +2,20 @@ * RTSP demuxer * Copyright (c) 2002 Fabrice Bellard * - * 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 */ @@ -204,7 +204,7 @@ redo: id = buf[0]; len = AV_RB16(buf + 1); av_dlog(s, "id=%d len=%d\n", id, len); - if (len > buf_size || len < 12) + if (len > buf_size || len < 8) goto redo; /* get the data */ ret = ffurl_read_complete(rt->rtsp_hd, buf, len); diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c index e4e79cad03..b54ae28eb8 100644 --- a/libavformat/rtspenc.c +++ b/libavformat/rtspenc.c @@ -2,20 +2,20 @@ * RTSP muxer * Copyright (c) 2010 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/libavformat/sapdec.c b/libavformat/sapdec.c index aa176c73ee..0f96a1ecc0 100644 --- a/libavformat/sapdec.c +++ b/libavformat/sapdec.c @@ -2,20 +2,20 @@ * Session Announcement Protocol (RFC 2974) demuxer * Copyright (c) 2010 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/libavformat/sapenc.c b/libavformat/sapenc.c index d8ec465afa..0f2b4b51f0 100644 --- a/libavformat/sapenc.c +++ b/libavformat/sapenc.c @@ -2,20 +2,20 @@ * Session Announcement Protocol (RFC 2974) muxer * Copyright (c) 2010 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/libavformat/sauce.c b/libavformat/sauce.c index a125241335..21cc95bccb 100644 --- a/libavformat/sauce.c +++ b/libavformat/sauce.c @@ -2,20 +2,20 @@ * SAUCE header parser * Copyright (c) 2010 Peter Ross <pross@xvid.org> * - * 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/libavformat/sauce.h b/libavformat/sauce.h index 62d8e688a4..0ba9ae5b4a 100644 --- a/libavformat/sauce.h +++ b/libavformat/sauce.h @@ -2,20 +2,20 @@ * SAUCE header parser * Copyright (c) 2010 Peter Ross <pross@xvid.org> * - * 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/libavformat/sbgdec.c b/libavformat/sbgdec.c new file mode 100644 index 0000000000..8b569c88b2 --- /dev/null +++ b/libavformat/sbgdec.c @@ -0,0 +1,1517 @@ +/* + * SBG (SBaGen) file format decoder + * Copyright (c) 2011 Nicolas George + * + * 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 <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "avformat.h" +#include "internal.h" + +#define SBG_SCALE (1 << 16) +#define DAY (24 * 60 * 60) +#define DAY_TS ((int64_t)DAY * AV_TIME_BASE) + +struct sbg_demuxer { + AVClass *class; + int sample_rate; + int frame_size; + int max_file_size; +}; + +struct sbg_string { + char *s; + char *e; +}; + +enum sbg_fade_type { + SBG_FADE_SILENCE = 0, + SBG_FADE_SAME = 1, + SBG_FADE_ADAPT = 3, +}; + +struct sbg_fade { + int8_t in, out, slide; +}; + +enum sbg_synth_type { + SBG_TYPE_NONE, + SBG_TYPE_SINE, + SBG_TYPE_NOISE, + SBG_TYPE_BELL, + SBG_TYPE_MIX, + SBG_TYPE_SPIN, +}; + +/* bell: freq constant, ampl decreases exponentially, can be approx lin */ + +struct sbg_timestamp { + int64_t t; + char type; /* 0 for relative, 'N' for now, 'T' for absolute */ +}; + +struct sbg_script_definition { + char *name; + int name_len; + int elements, nb_elements; + char type; /* 'S' or 'B' */ +}; + +struct sbg_script_synth { + int carrier; + int beat; + int vol; + enum sbg_synth_type type; + struct { + int l, r; + } ref; +}; + +struct sbg_script_tseq { + struct sbg_timestamp ts; + char *name; + int name_len; + int lock; + struct sbg_fade fade; +}; + +struct sbg_script_event { + int64_t ts; + int64_t ts_int, ts_trans, ts_next; + int elements, nb_elements; + struct sbg_fade fade; +}; + +struct sbg_script { + struct sbg_script_definition *def; + struct sbg_script_synth *synth; + struct sbg_script_tseq *tseq; + struct sbg_script_tseq *block_tseq; + struct sbg_script_event *events; + int nb_def; + int nb_tseq; + int nb_events; + int nb_synth; + int64_t start_ts; + int64_t end_ts; + int64_t opt_fade_time; + int64_t opt_duration; + char *opt_mix; + int sample_rate; + uint8_t opt_start_at_first; + uint8_t opt_end_at_last; +}; + +struct sbg_parser { + void *log; + char *script, *end; + char *cursor; + struct sbg_script scs; + struct sbg_timestamp current_time; + int nb_block_tseq; + int nb_def_max, nb_synth_max, nb_tseq_max, nb_block_tseq_max; + int line_no; + char err_msg[128]; +}; + +enum ws_interval_type { + WS_SINE = MKTAG('S','I','N','E'), + WS_NOISE = MKTAG('N','O','I','S'), +}; + +struct ws_interval { + int64_t ts1, ts2; + enum ws_interval_type type; + uint32_t channels; + int32_t f1, f2; + int32_t a1, a2; + uint32_t phi; +}; + +struct ws_intervals { + struct ws_interval *inter; + int nb_inter; + int max_inter; +}; + +static void *alloc_array_elem(void **array, size_t elsize, + int *size, int *max_size) +{ + void *ret; + + if (*size == *max_size) { + int m = FFMAX(32, FFMIN(*max_size, INT_MAX / 2) * 2); + if (*size >= m) + return NULL; + *array = av_realloc_f(*array, m, elsize); + if (!*array) + return NULL; + *max_size = m; + } + ret = (char *)*array + elsize * *size; + memset(ret, 0, elsize); + (*size)++; + return ret; +} + +static int str_to_time(const char *str, int64_t *rtime) +{ + const char *cur = str; + char *end; + int hours, minutes; + double seconds = 0; + + if (*cur < '0' || *cur > '9') + return 0; + hours = strtol(cur, &end, 10); + if (end == cur || *end != ':' || end[1] < '0' || end[1] > '9') + return 0; + cur = end + 1; + minutes = strtol(cur, &end, 10); + if (end == cur) + return 0; + cur = end; + if (*end == ':'){ + seconds = strtod(cur + 1, &end); + if (end > cur + 1) + cur = end; + } + *rtime = (hours * 3600 + minutes * 60 + seconds) * AV_TIME_BASE; + return cur - str; +} + +static inline int is_space(char c) +{ + return c == ' ' || c == '\t' || c == '\r'; +} + +static inline int scale_double(void *log, double d, double m, int *r) +{ + m *= d * SBG_SCALE; + if (m < INT_MIN || m >= INT_MAX) { + if (log) + av_log(log, AV_LOG_ERROR, "%g is too large\n", d); + return AVERROR(EDOM); + } + *r = m; + return 0; +} + +static int lex_space(struct sbg_parser *p) +{ + char *c = p->cursor; + + while (p->cursor < p->end && is_space(*p->cursor)) + p->cursor++; + return p->cursor > c; +} + +static int lex_char(struct sbg_parser *p, char c) +{ + int r = p->cursor < p->end && *p->cursor == c; + + p->cursor += r; + return r; +} + +static int lex_double(struct sbg_parser *p, double *r) +{ + double d; + char *end; + + if (p->cursor == p->end || is_space(*p->cursor) || *p->cursor == '\n') + return 0; + d = strtod(p->cursor, &end); + if (end > p->cursor) { + *r = d; + p->cursor = end; + return 1; + } + return 0; +} + +static int lex_fixed(struct sbg_parser *p, const char *t, int l) +{ + if (p->end - p->cursor < l || memcmp(p->cursor, t, l)) + return 0; + p->cursor += l; + return 1; +} + +static int lex_line_end(struct sbg_parser *p) +{ + if (p->cursor < p->end && *p->cursor == '#') { + p->cursor++; + while (p->cursor < p->end && *p->cursor != '\n') + p->cursor++; + } + if (p->cursor == p->end) + /* simulate final LF for files lacking it */ + return 1; + if (*p->cursor != '\n') + return 0; + p->cursor++; + p->line_no++; + lex_space(p); + return 1; +} + +static int lex_wsword(struct sbg_parser *p, struct sbg_string *rs) +{ + char *s = p->cursor, *c = s; + + if (s == p->end || *s == '\n') + return 0; + while (c < p->end && *c != '\n' && !is_space(*c)) + c++; + rs->s = s; + rs->e = p->cursor = c; + lex_space(p); + return 1; +} + +static int lex_name(struct sbg_parser *p, struct sbg_string *rs) +{ + char *s = p->cursor, *c = s; + + while (c < p->end && ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') + || (*c >= '0' && *c <= '9') || *c == '_' || *c == '-')) + c++; + if (c == s) + return 0; + rs->s = s; + rs->e = p->cursor = c; + return 1; +} + +static int lex_time(struct sbg_parser *p, int64_t *rt) +{ + int r = str_to_time(p->cursor, rt); + p->cursor += r; + return r > 0; +} + +#define FORWARD_ERROR(c) \ + do { \ + int errcode = c; \ + if (errcode <= 0) \ + return errcode ? errcode : AVERROR_INVALIDDATA; \ + } while(0); + +static int parse_immediate(struct sbg_parser *p) +{ + snprintf(p->err_msg, sizeof(p->err_msg), + "immediate sequences not yet implemented"); + return AVERROR_PATCHWELCOME; +} + +static int parse_preprogrammed(struct sbg_parser *p) +{ + snprintf(p->err_msg, sizeof(p->err_msg), + "preprogrammed sequences not yet implemented"); + return AVERROR_PATCHWELCOME; +} + +static int parse_optarg(struct sbg_parser *p, char o, struct sbg_string *r) +{ + if (!lex_wsword(p, r)) { + snprintf(p->err_msg, sizeof(p->err_msg), + "option '%c' requires an argument", o); + return AVERROR_INVALIDDATA; + } + return 1; +} + +static int parse_options(struct sbg_parser *p) +{ + struct sbg_string ostr, oarg; + char mode = 0; + int r; + char *tptr; + double v; + + if (p->cursor == p->end || *p->cursor != '-') + return 0; + while (lex_char(p, '-') && lex_wsword(p, &ostr)) { + for (; ostr.s < ostr.e; ostr.s++) { + char opt = *ostr.s; + switch (opt) { + case 'S': + p->scs.opt_start_at_first = 1; + break; + case 'E': + p->scs.opt_end_at_last = 1; + break; + case 'i': + mode = 'i'; + break; + case 'p': + mode = 'p'; + break; + case 'F': + FORWARD_ERROR(parse_optarg(p, opt, &oarg)); + v = strtod(oarg.s, &tptr); + if (oarg.e != tptr) { + snprintf(p->err_msg, sizeof(p->err_msg), + "syntax error for option -F"); + return AVERROR_INVALIDDATA; + } + p->scs.opt_fade_time = v * AV_TIME_BASE / 1000; + break; + case 'L': + FORWARD_ERROR(parse_optarg(p, opt, &oarg)); + r = str_to_time(oarg.s, &p->scs.opt_duration); + if (oarg.e != oarg.s + r) { + snprintf(p->err_msg, sizeof(p->err_msg), + "syntax error for option -L"); + return AVERROR_INVALIDDATA; + } + break; + case 'T': + FORWARD_ERROR(parse_optarg(p, opt, &oarg)); + r = str_to_time(oarg.s, &p->scs.start_ts); + if (oarg.e != oarg.s + r) { + snprintf(p->err_msg, sizeof(p->err_msg), + "syntax error for option -T"); + return AVERROR_INVALIDDATA; + } + break; + case 'm': + FORWARD_ERROR(parse_optarg(p, opt, &oarg)); + tptr = av_malloc(oarg.e - oarg.s + 1); + if (!tptr) + return AVERROR(ENOMEM); + memcpy(tptr, oarg.s, oarg.e - oarg.s); + tptr[oarg.e - oarg.s] = 0; + av_free(p->scs.opt_mix); + p->scs.opt_mix = tptr; + break; + case 'q': + FORWARD_ERROR(parse_optarg(p, opt, &oarg)); + v = strtod(oarg.s, &tptr); + if (oarg.e != tptr) { + snprintf(p->err_msg, sizeof(p->err_msg), + "syntax error for option -q"); + return AVERROR_INVALIDDATA; + } + if (v != 1) { + snprintf(p->err_msg, sizeof(p->err_msg), + "speed factor other than 1 not supported"); + return AVERROR_PATCHWELCOME; + } + break; + case 'r': + FORWARD_ERROR(parse_optarg(p, opt, &oarg)); + r = strtol(oarg.s, &tptr, 10); + if (oarg.e != tptr) { + snprintf(p->err_msg, sizeof(p->err_msg), + "syntax error for option -r"); + return AVERROR_INVALIDDATA; + } + if (r < 40) { + snprintf(p->err_msg, sizeof(p->err_msg), + "invalid sample rate"); + return AVERROR_PATCHWELCOME; + } + p->scs.sample_rate = r; + break; + default: + snprintf(p->err_msg, sizeof(p->err_msg), + "unknown option: '%c'", *ostr.s); + return AVERROR_INVALIDDATA; + } + } + } + switch (mode) { + case 'i': + return parse_immediate(p); + case 'p': + return parse_preprogrammed(p); + case 0: + if (!lex_line_end(p)) + return AVERROR_INVALIDDATA; + return 1; + } + return AVERROR_BUG; +} + +static int parse_timestamp(struct sbg_parser *p, + struct sbg_timestamp *rts, int64_t *rrel) +{ + int64_t abs = 0, rel = 0, dt; + char type = 0; + int r; + + if (lex_fixed(p, "NOW", 3)) { + type = 'N'; + r = 1; + } else { + r = lex_time(p, &abs); + if (r) + type = 'T'; + } + while (lex_char(p, '+')) { + if (!lex_time(p, &dt)) + return AVERROR_INVALIDDATA; + rel += dt; + r = 1; + } + if (r) { + if (!lex_space(p)) + return AVERROR_INVALIDDATA; + rts->type = type; + rts->t = abs; + *rrel = rel; + } + return r; +} + +static int parse_fade(struct sbg_parser *p, struct sbg_fade *fr) +{ + struct sbg_fade f; + + if (lex_char(p, '<')) + f.in = SBG_FADE_SILENCE; + else if (lex_char(p, '-')) + f.in = SBG_FADE_SAME; + else if (lex_char(p, '=')) + f.in = SBG_FADE_ADAPT; + else + return 0; + if (lex_char(p, '>')) + f.out = SBG_FADE_SILENCE; + else if (lex_char(p, '-')) + f.out = SBG_FADE_SAME; + else if (lex_char(p, '=')) + f.out = SBG_FADE_ADAPT; + else + return AVERROR_INVALIDDATA; + *fr = f; + return 1; +} + +static int parse_time_sequence(struct sbg_parser *p, int inblock) +{ + struct sbg_timestamp ts; + int64_t rel_ts; + int r; + struct sbg_fade fade = { SBG_FADE_SAME, SBG_FADE_SAME, 0 }; + struct sbg_string name; + struct sbg_script_tseq *tseq; + + r = parse_timestamp(p, &ts, &rel_ts); + if (!r) + return 0; + if (r < 0) + return r; + if (ts.type) { + if (inblock) + return AVERROR_INVALIDDATA; + p->current_time.type = ts.type; + p->current_time.t = ts.t; + } else if(!inblock && !p->current_time.type) { + snprintf(p->err_msg, sizeof(p->err_msg), + "relative time without previous absolute time"); + return AVERROR_INVALIDDATA; + } + ts.type = p->current_time.type; + ts.t = p->current_time.t + rel_ts; + r = parse_fade(p, &fade); + if (r < 0) + return r; + lex_space(p); + if (!lex_name(p, &name)) + return AVERROR_INVALIDDATA; + lex_space(p); + if (lex_fixed(p, "->", 2)) { + fade.slide = SBG_FADE_ADAPT; + lex_space(p); + } + if (!lex_line_end(p)) + return AVERROR_INVALIDDATA; + tseq = inblock ? + alloc_array_elem((void **)&p->scs.block_tseq, sizeof(*tseq), + &p->nb_block_tseq, &p->nb_block_tseq_max) : + alloc_array_elem((void **)&p->scs.tseq, sizeof(*tseq), + &p->scs.nb_tseq, &p->nb_tseq_max); + if (!tseq) + return AVERROR(ENOMEM); + tseq->ts = ts; + tseq->name = name.s; + tseq->name_len = name.e - name.s; + tseq->fade = fade; + return 1; +} + +static int parse_wave_def(struct sbg_parser *p, int wavenum) +{ + snprintf(p->err_msg, sizeof(p->err_msg), + "waveform definitions not yet implemented"); + return AVERROR_PATCHWELCOME; +} + +static int parse_block_def(struct sbg_parser *p, + struct sbg_script_definition *def) +{ + int r, tseq; + + lex_space(p); + if (!lex_line_end(p)) + return AVERROR_INVALIDDATA; + tseq = p->nb_block_tseq; + while (1) { + r = parse_time_sequence(p, 1); + if (r < 0) + return r; + if (!r) + break; + } + if (!lex_char(p, '}')) + return AVERROR_INVALIDDATA; + lex_space(p); + if (!lex_line_end(p)) + return AVERROR_INVALIDDATA; + def->type = 'B'; + def->elements = tseq; + def->nb_elements = p->nb_block_tseq - tseq; + if (!def->nb_elements) + return AVERROR_INVALIDDATA; + return 1; +} + +static int parse_volume(struct sbg_parser *p, int *vol) +{ + double v; + + if (!lex_char(p, '/')) + return 0; + if (!lex_double(p, &v)) + return AVERROR_INVALIDDATA; + if (scale_double(p->log, v, 0.01, vol)) + return AVERROR(ERANGE); + return 1; +} + +static int parse_synth_channel_sine(struct sbg_parser *p, + struct sbg_script_synth *synth) +{ + double carrierf, beatf; + int carrier, beat, vol; + + if (!lex_double(p, &carrierf)) + return 0; + if (!lex_double(p, &beatf)) + beatf = 0; + FORWARD_ERROR(parse_volume(p, &vol)); + if (scale_double(p->log, carrierf, 1, &carrier) < 0 || + scale_double(p->log, beatf, 1, &beat) < 0) + return AVERROR(EDOM); + synth->type = SBG_TYPE_SINE; + synth->carrier = carrier; + synth->beat = beat; + synth->vol = vol; + return 1; +} + +static int parse_synth_channel_pink(struct sbg_parser *p, + struct sbg_script_synth *synth) +{ + int vol; + + if (!lex_fixed(p, "pink", 4)) + return 0; + FORWARD_ERROR(parse_volume(p, &vol)); + synth->type = SBG_TYPE_NOISE; + synth->vol = vol; + return 1; +} + +static int parse_synth_channel_bell(struct sbg_parser *p, + struct sbg_script_synth *synth) +{ + double carrierf; + int carrier, vol; + + if (!lex_fixed(p, "bell", 4)) + return 0; + if (!lex_double(p, &carrierf)) + return AVERROR_INVALIDDATA; + FORWARD_ERROR(parse_volume(p, &vol)); + if (scale_double(p->log, carrierf, 1, &carrier) < 0) + return AVERROR(EDOM); + synth->type = SBG_TYPE_BELL; + synth->carrier = carrier; + synth->vol = vol; + return 1; +} + +static int parse_synth_channel_mix(struct sbg_parser *p, + struct sbg_script_synth *synth) +{ + int vol; + + if (!lex_fixed(p, "mix", 3)) + return 0; + FORWARD_ERROR(parse_volume(p, &vol)); + synth->type = SBG_TYPE_MIX; + synth->vol = vol; + return 1; +} + +static int parse_synth_channel_spin(struct sbg_parser *p, + struct sbg_script_synth *synth) +{ + double carrierf, beatf; + int carrier, beat, vol; + + if (!lex_fixed(p, "spin:", 5)) + return 0; + if (!lex_double(p, &carrierf)) + return AVERROR_INVALIDDATA; + if (!lex_double(p, &beatf)) + return AVERROR_INVALIDDATA; + FORWARD_ERROR(parse_volume(p, &vol)); + if (scale_double(p->log, carrierf, 1, &carrier) < 0 || + scale_double(p->log, beatf, 1, &beat) < 0) + return AVERROR(EDOM); + synth->type = SBG_TYPE_SPIN; + synth->carrier = carrier; + synth->beat = beat; + synth->vol = vol; + return 1; +} + +static int parse_synth_channel(struct sbg_parser *p) +{ + int r; + struct sbg_script_synth *synth; + + synth = alloc_array_elem((void **)&p->scs.synth, sizeof(*synth), + &p->scs.nb_synth, &p->nb_synth_max); + if (!synth) + return AVERROR(ENOMEM); + r = lex_char(p, '-'); + if (!r) + r = parse_synth_channel_pink(p, synth); + if (!r) + r = parse_synth_channel_bell(p, synth); + if (!r) + r = parse_synth_channel_mix(p, synth); + if (!r) + r = parse_synth_channel_spin(p, synth); + /* Unimplemented: wave%d:%f%f/vol (carrier, beat) */ + if (!r) + r = parse_synth_channel_sine(p, synth); + if (r <= 0) + p->scs.nb_synth--; + return r; +} + +static int parse_synth_def(struct sbg_parser *p, + struct sbg_script_definition *def) +{ + int r, synth; + + synth = p->scs.nb_synth; + while (1) { + r = parse_synth_channel(p); + if (r < 0) + return r; + if (!r || !lex_space(p)) + break; + } + lex_space(p); + if (synth == p->scs.nb_synth) + return AVERROR_INVALIDDATA; + if (!lex_line_end(p)) + return AVERROR_INVALIDDATA; + def->type = 'S'; + def->elements = synth; + def->nb_elements = p->scs.nb_synth - synth; + return 1; +} + +static int parse_named_def(struct sbg_parser *p) +{ + char *cursor_save = p->cursor; + struct sbg_string name; + struct sbg_script_definition *def; + + if (!lex_name(p, &name) || !lex_char(p, ':') || !lex_space(p)) { + p->cursor = cursor_save; + return 0; + } + if (name.e - name.s == 6 && !memcmp(name.s, "wave", 4) && + name.s[4] >= '0' && name.s[4] <= '9' && + name.s[5] >= '0' && name.s[5] <= '9') { + int wavenum = (name.s[4] - '0') * 10 + (name.s[5] - '0'); + return parse_wave_def(p, wavenum); + } + def = alloc_array_elem((void **)&p->scs.def, sizeof(*def), + &p->scs.nb_def, &p->nb_def_max); + if (!def) + return AVERROR(ENOMEM); + def->name = name.s; + def->name_len = name.e - name.s; + if (lex_char(p, '{')) + return parse_block_def(p, def); + return parse_synth_def(p, def); +} + +static void free_script(struct sbg_script *s) +{ + av_freep(&s->def); + av_freep(&s->synth); + av_freep(&s->tseq); + av_freep(&s->block_tseq); + av_freep(&s->events); + av_freep(&s->opt_mix); +} + +static int parse_script(void *log, char *script, int script_len, + struct sbg_script *rscript) +{ + struct sbg_parser sp = { + .log = log, + .script = script, + .end = script + script_len, + .cursor = script, + .line_no = 1, + .err_msg = "", + .scs = { + /* default values */ + .start_ts = AV_NOPTS_VALUE, + .sample_rate = 44100, + .opt_fade_time = 60 * AV_TIME_BASE, + }, + }; + int r; + + lex_space(&sp); + while (sp.cursor < sp.end) { + r = parse_options(&sp); + if (r < 0) + goto fail; + if (!r && !lex_line_end(&sp)) + break; + } + while (sp.cursor < sp.end) { + r = parse_named_def(&sp); + if (!r) + r = parse_time_sequence(&sp, 0); + if (!r) + r = lex_line_end(&sp) ? 1 : AVERROR_INVALIDDATA; + if (r < 0) + goto fail; + } + *rscript = sp.scs; + return 1; +fail: + free_script(&sp.scs); + if (!*sp.err_msg) + if (r == AVERROR_INVALIDDATA) + snprintf(sp.err_msg, sizeof(sp.err_msg), "syntax error"); + if (log && *sp.err_msg) { + const char *ctx = sp.cursor; + const char *ectx = av_x_if_null(memchr(ctx, '\n', sp.end - sp.cursor), + sp.end); + int lctx = ectx - ctx; + const char *quote = "\""; + if (lctx > 0 && ctx[lctx - 1] == '\r') + lctx--; + if (lctx == 0) { + ctx = "the end of line"; + lctx = strlen(ctx); + quote = ""; + } + av_log(log, AV_LOG_ERROR, "Error line %d: %s near %s%.*s%s.\n", + sp.line_no, sp.err_msg, quote, lctx, ctx, quote); + } + return r; +} + +static int read_whole_file(AVIOContext *io, int max_size, char **rbuf) +{ + char *buf = NULL; + int size = 0, bufsize = 0, r; + + while (1) { + if (bufsize - size < 1024) { + bufsize = FFMIN(FFMAX(2 * bufsize, 8192), max_size); + if (bufsize - size < 2) { + size = AVERROR(EFBIG); + goto fail; + } + buf = av_realloc_f(buf, bufsize, 1); + if (!buf) { + size = AVERROR(ENOMEM); + goto fail; + } + } + r = avio_read(io, buf, bufsize - size - 1); + if (r == AVERROR_EOF) + break; + if (r < 0) + goto fail; + size += r; + } + buf[size] = 0; + *rbuf = buf; + return size; +fail: + av_free(buf); + return size; +} + +static void expand_timestamps(void *log, struct sbg_script *s) +{ + int i, nb_rel = 0; + int64_t now, cur_ts, delta = 0; + + for (i = 0; i < s->nb_tseq; i++) + nb_rel += s->tseq[i].ts.type == 'N'; + if (nb_rel == s->nb_tseq) { + /* All ts are relative to NOW: consider NOW = 0 */ + now = 0; + if (s->start_ts != AV_NOPTS_VALUE) + av_log(log, AV_LOG_WARNING, + "Start time ignored in a purely relative script.\n"); + } else if (nb_rel == 0 && s->start_ts != AV_NOPTS_VALUE || + s->opt_start_at_first) { + /* All ts are absolute and start time is specified */ + if (s->start_ts == AV_NOPTS_VALUE) + s->start_ts = s->tseq[0].ts.t; + now = s->start_ts; + } else { + /* Mixed relative/absolute ts: expand */ + time_t now0; + struct tm *tm; + + av_log(log, AV_LOG_WARNING, + "Scripts with mixed absolute and relative timestamps can give " + "unexpected results (pause, seeking, time zone change).\n"); +#undef time + time(&now0); + tm = localtime(&now0); + now = tm ? tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec : + now0 % DAY; + av_log(log, AV_LOG_INFO, "Using %02d:%02d:%02d as NOW.\n", + (int)(now / 3600), (int)(now / 60) % 60, (int)now % 60); + now *= AV_TIME_BASE; + for (i = 0; i < s->nb_tseq; i++) { + if (s->tseq[i].ts.type == 'N') { + s->tseq[i].ts.t += now; + s->tseq[i].ts.type = 'T'; /* not necessary */ + } + } + } + if (s->start_ts == AV_NOPTS_VALUE) + s->start_ts = s->opt_start_at_first ? s->tseq[0].ts.t : now; + s->end_ts = s->opt_duration ? s->start_ts + s->opt_duration : + AV_NOPTS_VALUE; /* may be overridden later by -E option */ + cur_ts = now; + for (i = 0; i < s->nb_tseq; i++) { + if (s->tseq[i].ts.t + delta < cur_ts) + delta += DAY_TS; + cur_ts = s->tseq[i].ts.t += delta; + } +} + +static int expand_tseq(void *log, struct sbg_script *s, int *nb_ev_max, + int64_t t0, struct sbg_script_tseq *tseq) +{ + int i, r; + struct sbg_script_definition *def; + struct sbg_script_tseq *be; + struct sbg_script_event *ev; + + if (tseq->lock++) { + av_log(log, 16, "Recursion loop on \"%.*s\"\n", + tseq->name_len, tseq->name); + return AVERROR(EINVAL); + } + t0 += tseq->ts.t; + for (i = 0; i < s->nb_def; i++) { + if (s->def[i].name_len == tseq->name_len && + !memcmp(s->def[i].name, tseq->name, tseq->name_len)) + break; + } + if (i >= s->nb_def) { + av_log(log, 16, "Tone-set \"%.*s\" not defined\n", + tseq->name_len, tseq->name); + return AVERROR(EINVAL); + } + def = &s->def[i]; + if (def->type == 'B') { + be = s->block_tseq + def->elements; + for (i = 0; i < def->nb_elements; i++) { + r = expand_tseq(log, s, nb_ev_max, t0, &be[i]); + if (r < 0) + return r; + } + } else { + ev = alloc_array_elem((void **)&s->events, sizeof(*ev), + &s->nb_events, nb_ev_max); + ev->ts = tseq->ts.t; + ev->elements = def->elements; + ev->nb_elements = def->nb_elements; + ev->fade = tseq->fade; + } + tseq->lock--; + return 0; +} + +static int expand_script(void *log, struct sbg_script *s) +{ + int i, r, nb_events_max = 0; + + expand_timestamps(log, s); + for (i = 0; i < s->nb_tseq; i++) { + r = expand_tseq(log, s, &nb_events_max, 0, &s->tseq[i]); + if (r < 0) + return r; + } + if (!s->nb_events) { + av_log(log, AV_LOG_ERROR, "No events in script\n"); + return AVERROR_INVALIDDATA; + } + if (s->opt_end_at_last) + s->end_ts = s->events[s->nb_events - 1].ts; + return 0; +} + +static int add_interval(struct ws_intervals *inter, + enum ws_interval_type type, uint32_t channels, int ref, + int64_t ts1, int32_t f1, int32_t a1, + int64_t ts2, int32_t f2, int32_t a2) +{ + struct ws_interval *i, *ri; + + if (ref >= 0) { + ri = &inter->inter[ref]; + /* ref and new intervals are constant, identical and adjacent */ + if (ri->type == type && ri->channels == channels && + ri->f1 == ri->f2 && ri->f2 == f1 && f1 == f2 && + ri->a1 == ri->a2 && ri->a2 == a1 && a1 == a2 && + ri->ts2 == ts1) { + ri->ts2 = ts2; + return ref; + } + } + i = alloc_array_elem((void **)&inter->inter, sizeof(*i), + &inter->nb_inter, &inter->max_inter); + if (!i) + return AVERROR(ENOMEM); + i->ts1 = ts1; + i->ts2 = ts2; + i->type = type; + i->channels = channels; + i->f1 = f1; + i->f2 = f2; + i->a1 = a1; + i->a2 = a2; + i->phi = ref >= 0 ? ref | 0x80000000 : 0; + return i - inter->inter; +} + +static int add_bell(struct ws_intervals *inter, struct sbg_script *s, + int64_t ts1, int64_t ts2, int32_t f, int32_t a) +{ + /* SBaGen uses an exponential decrease every 50ms. + We approximate it with piecewise affine segments. */ + int32_t cpoints[][2] = { + { 2, a }, + { 4, a - a / 4 }, + { 8, a / 2 }, + { 16, a / 4 }, + { 25, a / 10 }, + { 50, a / 80 }, + { 75, 0 }, + }; + int i, r; + int64_t dt = s->sample_rate / 20, ts3 = ts1, ts4; + for (i = 0; i < FF_ARRAY_ELEMS(cpoints); i++) { + ts4 = FFMIN(ts2, ts1 + cpoints[i][0] * dt); + r = add_interval(inter, WS_SINE, 3, -1, + ts3, f, a, ts4, f, cpoints[i][1]); + if (r < 0) + return r; + ts3 = ts4; + a = cpoints[i][1]; + } + return 0; +} + +static int generate_interval(void *log, struct sbg_script *s, + struct ws_intervals *inter, + int64_t ts1, int64_t ts2, + struct sbg_script_synth *s1, + struct sbg_script_synth *s2, + int transition) +{ + int r; + + if (ts2 <= ts1 || (s1->vol == 0 && s2->vol == 0)) + return 0; + switch (s1->type) { + case SBG_TYPE_NONE: + break; + case SBG_TYPE_SINE: + if (s1->beat == 0 && s2->beat == 0) { + r = add_interval(inter, WS_SINE, 3, s1->ref.l, + ts1, s1->carrier, s1->vol, + ts2, s2->carrier, s2->vol); + if (r < 0) + return r; + s2->ref.l = s2->ref.r = r; + } else { + r = add_interval(inter, WS_SINE, 1, s1->ref.l, + ts1, s1->carrier + s1->beat / 2, s1->vol, + ts2, s2->carrier + s2->beat / 2, s2->vol); + if (r < 0) + return r; + s2->ref.l = r; + r = add_interval(inter, WS_SINE, 2, s1->ref.r, + ts1, s1->carrier - s1->beat / 2, s1->vol, + ts2, s2->carrier - s2->beat / 2, s2->vol); + if (r < 0) + return r; + s2->ref.r = r; + } + break; + + case SBG_TYPE_BELL: + if (transition == 2) { + r = add_bell(inter, s, ts1, ts2, s1->carrier, s2->vol); + if (r < 0) + return r; + } + break; + + case SBG_TYPE_SPIN: + av_log(log, AV_LOG_WARNING, "Spinning noise not implemented, " + "using pink noise instead.\n"); + /* fall through */ + case SBG_TYPE_NOISE: + /* SBaGen's pink noise generator uses: + - 1 band of white noise, mean square: 1/3; + - 9 bands of subsampled white noise with linear + interpolation, mean square: 2/3 each; + with 1/10 weight each: the total mean square is 7/300. + Our pink noise generator uses 8 bands of white noise with + rectangular subsampling: the total mean square is 1/24. + Therefore, to match SBaGen's volume, we must multiply vol by + sqrt((7/300) / (1/24)) = sqrt(14/25) =~ 0.748 + */ + r = add_interval(inter, WS_NOISE, 3, s1->ref.l, + ts1, 0, s1->vol - s1->vol / 4, + ts2, 0, s2->vol - s2->vol / 4); + if (r < 0) + return r; + s2->ref.l = s2->ref.r = r; + break; + + case SBG_TYPE_MIX: + /* Unimplemented: silence; warning present elsewhere */ + default: + av_log(log, AV_LOG_ERROR, + "Type %d is not implemented\n", s1->type); + return AVERROR_PATCHWELCOME; + } + return 0; +} + +static int generate_plateau(void *log, struct sbg_script *s, + struct ws_intervals *inter, + struct sbg_script_event *ev1) +{ + int64_t ts1 = ev1->ts_int, ts2 = ev1->ts_trans; + int i, r; + struct sbg_script_synth *s1; + + for (i = 0; i < ev1->nb_elements; i++) { + s1 = &s->synth[ev1->elements + i]; + r = generate_interval(log, s, inter, ts1, ts2, s1, s1, 0); + if (r < 0) + return r; + } + return 0; +} + +/* + + ts1 ts2 ts1 tsmid ts2 + | | | | | + v v v | v +____ ____ v ____ + ''''.... ''.. ..'' + ''''....____ ''....'' + + compatible transition incompatible transition + */ + +static int generate_transition(void *log, struct sbg_script *s, + struct ws_intervals *inter, + struct sbg_script_event *ev1, + struct sbg_script_event *ev2) +{ + int64_t ts1 = ev1->ts_trans, ts2 = ev1->ts_next; + /* (ts1 + ts2) / 2 without overflow */ + int64_t tsmid = (ts1 >> 1) + (ts2 >> 1) + (ts1 & ts2 & 1); + enum sbg_fade_type type = ev1->fade.slide | (ev1->fade.out & ev2->fade.in); + int nb_elements = FFMAX(ev1->nb_elements, ev2->nb_elements); + struct sbg_script_synth *s1, *s2, s1mod, s2mod, smid; + int pass, i, r; + + for (pass = 0; pass < 2; pass++) { + /* pass = 0 -> compatible and first half of incompatible + pass = 1 -> second half of incompatible + Using two passes like that ensures that the intervals are generated + in increasing order according to their start timestamp. + Otherwise it would be necessary to sort them + while keeping the mutual references. + */ + for (i = 0; i < nb_elements; i++) { + s1 = i < ev1->nb_elements ? &s->synth[ev1->elements + i] : &s1mod; + s2 = i < ev2->nb_elements ? &s->synth[ev2->elements + i] : &s2mod; + s1mod = s1 != &s1mod ? *s1 : (struct sbg_script_synth){ 0 }; + s2mod = s2 != &s2mod ? *s2 : (struct sbg_script_synth){ 0 }; + if (ev1->fade.slide) { + /* for slides, and only for slides, silence ("-") is equivalent + to anything with volume 0 */ + if (s1mod.type == SBG_TYPE_NONE) { + s1mod = s2mod; + s1mod.vol = 0; + } else if (s2mod.type == SBG_TYPE_NONE) { + s2mod = s1mod; + s2mod.vol = 0; + } + } + if (s1mod.type == s2mod.type && + s1mod.type != SBG_TYPE_BELL && + (type == SBG_FADE_ADAPT || + (s1mod.carrier == s2mod.carrier && + s1mod.beat == s2mod.beat))) { + /* compatible: single transition */ + if (!pass) { + r = generate_interval(log, s, inter, + ts1, ts2, &s1mod, &s2mod, 3); + if (r < 0) + return r; + s2->ref = s2mod.ref; + } + } else { + /* incompatible: silence at midpoint */ + if (!pass) { + smid = s1mod; + smid.vol = 0; + r = generate_interval(log, s, inter, + ts1, tsmid, &s1mod, &smid, 1); + if (r < 0) + return r; + } else { + smid = s2mod; + smid.vol = 0; + r = generate_interval(log, s, inter, + tsmid, ts2, &smid, &s2mod, 2); + if (r < 0) + return r; + s2->ref = s2mod.ref; + } + } + } + } + return 0; +} + +/* + ev1 trats ev2 intts endts ev3 + | | | | | | + v v v v v v + ________________ +.... .... .... + '''....________________....''' '''...._______________ + +\_________/\______________/\_________/\______________/\_________/\_____________/ + tr x->1 int1 tr 1->2 int2 tr 2->3 int3 + */ + +static int generate_intervals(void *log, struct sbg_script *s, int sample_rate, + struct ws_intervals *inter) +{ + int64_t trans_time = s->opt_fade_time / 2; + struct sbg_script_event ev0, *ev1, *ev2; + int64_t period; + int i, r; + + /* SBaGen handles the time before and after the extremal events, + and the corresponding transitions, as if the sequence were cyclic + with a 24-hours period. */ + period = s->events[s->nb_events - 1].ts - s->events[0].ts; + period = (period + (DAY_TS - 1)) / DAY_TS * DAY_TS; + period = FFMAX(period, DAY_TS); + + /* Prepare timestamps for transitions */ + for (i = 0; i < s->nb_events; i++) { + ev1 = &s->events[i]; + ev2 = &s->events[(i + 1) % s->nb_events]; + ev1->ts_int = ev1->ts; + ev1->ts_trans = ev1->fade.slide ? ev1->ts + : ev2->ts + (ev1 < ev2 ? 0 : period); + } + for (i = 0; i < s->nb_events; i++) { + ev1 = &s->events[i]; + ev2 = &s->events[(i + 1) % s->nb_events]; + if (!ev1->fade.slide) { + ev1->ts_trans = FFMAX(ev1->ts_int, ev1->ts_trans - trans_time); + ev2->ts_int = FFMIN(ev2->ts_trans, ev2->ts_int + trans_time); + } + ev1->ts_next = ev2->ts_int + (ev1 < ev2 ? 0 : period); + } + + /* Pseudo event before the first one */ + ev0 = s->events[s->nb_events - 1]; + ev0.ts_int -= period; + ev0.ts_trans -= period; + ev0.ts_next -= period; + + /* Convert timestamps */ + for (i = -1; i < s->nb_events; i++) { + ev1 = i < 0 ? &ev0 : &s->events[i]; + ev1->ts_int = av_rescale(ev1->ts_int, sample_rate, AV_TIME_BASE); + ev1->ts_trans = av_rescale(ev1->ts_trans, sample_rate, AV_TIME_BASE); + ev1->ts_next = av_rescale(ev1->ts_next, sample_rate, AV_TIME_BASE); + } + + /* Generate intervals */ + for (i = 0; i < s->nb_synth; i++) + s->synth[i].ref.l = s->synth[i].ref.r = -1; + for (i = -1; i < s->nb_events; i++) { + ev1 = i < 0 ? &ev0 : &s->events[i]; + ev2 = &s->events[(i + 1) % s->nb_events]; + r = generate_plateau(log, s, inter, ev1); + if (r < 0) + return r; + r = generate_transition(log, s, inter, ev1, ev2); + if (r < 0) + return r; + } + if (!inter->nb_inter) + av_log(log, AV_LOG_WARNING, "Completely silent script.\n"); + return 0; +} + +static int encode_intervals(struct sbg_script *s, AVCodecContext *avc, + struct ws_intervals *inter) +{ + int i, edata_size = 4; + uint8_t *edata; + + for (i = 0; i < inter->nb_inter; i++) { + edata_size += inter->inter[i].type == WS_SINE ? 44 : + inter->inter[i].type == WS_NOISE ? 32 : 0; + if (edata_size < 0) + return AVERROR(ENOMEM); + } + edata = av_malloc(edata_size); + if (!edata) + return AVERROR(ENOMEM); + avc->extradata = edata; + avc->extradata_size = edata_size; + +#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) + ADD_EDATA32(inter->nb_inter); + for (i = 0; i < inter->nb_inter; i++) { + ADD_EDATA64(inter->inter[i].ts1); + ADD_EDATA64(inter->inter[i].ts2); + ADD_EDATA32(inter->inter[i].type); + ADD_EDATA32(inter->inter[i].channels); + switch (inter->inter[i].type) { + case WS_SINE: + ADD_EDATA32(inter->inter[i].f1); + ADD_EDATA32(inter->inter[i].f2); + ADD_EDATA32(inter->inter[i].a1); + ADD_EDATA32(inter->inter[i].a2); + ADD_EDATA32(inter->inter[i].phi); + break; + case WS_NOISE: + ADD_EDATA32(inter->inter[i].a1); + ADD_EDATA32(inter->inter[i].a2); + break; + } + } + if (edata != avc->extradata + edata_size) + return AVERROR_BUG; + return 0; +} + +static av_cold int sbg_read_probe(AVProbeData *p) +{ + int r, score; + struct sbg_script script = { 0 }; + + r = parse_script(NULL, p->buf, p->buf_size, &script); + score = r < 0 || !script.nb_def || !script.nb_tseq ? 0 : + AVPROBE_SCORE_MAX / 3; + free_script(&script); + return score; +} + +static av_cold int sbg_read_header(AVFormatContext *avf) +{ + struct sbg_demuxer *sbg = avf->priv_data; + int r; + char *buf = NULL; + struct sbg_script script = { 0 }; + AVStream *st; + struct ws_intervals inter = { 0 }; + + r = read_whole_file(avf->pb, sbg->max_file_size, &buf); + if (r < 0) + goto fail; + r = parse_script(avf, buf, r, &script); + if (r < 0) + goto fail; + if (!sbg->sample_rate) + sbg->sample_rate = script.sample_rate; + else + script.sample_rate = sbg->sample_rate; + if (!sbg->frame_size) + sbg->frame_size = FFMAX(1, sbg->sample_rate / 10); + if (script.opt_mix) + av_log(avf, AV_LOG_WARNING, "Mix feature not implemented: " + "-m is ignored and mix channels will be silent.\n"); + r = expand_script(avf, &script); + if (r < 0) + goto fail; + av_freep(&buf); + r = generate_intervals(avf, &script, sbg->sample_rate, &inter); + if (r < 0) + goto fail; + + st = avformat_new_stream(avf, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_FFWAVESYNTH; + st->codec->channels = 2; + st->codec->channel_layout = AV_CH_LAYOUT_STEREO; + st->codec->sample_rate = sbg->sample_rate; + st->codec->frame_size = sbg->frame_size; + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + st->probe_packets = 0; + st->start_time = av_rescale(script.start_ts, + sbg->sample_rate, AV_TIME_BASE); + st->duration = script.end_ts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE : + av_rescale(script.end_ts - script.start_ts, + sbg->sample_rate, AV_TIME_BASE); + st->cur_dts = st->start_time; + r = encode_intervals(&script, st->codec, &inter); + if (r < 0) + goto fail; + + av_free(inter.inter); + free_script(&script); + return 0; + +fail: + av_free(inter.inter); + free_script(&script); + av_free(buf); + return r; +} + +static int sbg_read_packet(AVFormatContext *avf, AVPacket *packet) +{ + int64_t ts, end_ts; + + ts = avf->streams[0]->cur_dts; + end_ts = ts + avf->streams[0]->codec->frame_size; + if (avf->streams[0]->duration != AV_NOPTS_VALUE) + end_ts = FFMIN(avf->streams[0]->start_time + avf->streams[0]->duration, + end_ts); + if (end_ts <= ts) + return AVERROR_EOF; + if (av_new_packet(packet, 12) < 0) + return AVERROR(ENOMEM); + packet->dts = packet->pts = ts; + packet->duration = end_ts - ts; + AV_WL64(packet->data + 0, ts); + AV_WL32(packet->data + 8, packet->duration); + return packet->size; +} + +static int sbg_read_seek2(AVFormatContext *avf, int stream_index, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + if (flags || stream_index > 0) + return AVERROR(EINVAL); + if (stream_index < 0) + ts = av_rescale_q(ts, AV_TIME_BASE_Q, avf->streams[0]->time_base); + avf->streams[0]->cur_dts = ts; + return 0; +} + +#if FF_API_READ_SEEK +static int sbg_read_seek(AVFormatContext *avf, int stream_index, + int64_t ts, int flags) +{ + return sbg_read_seek2(avf, stream_index, ts, ts, ts, 0); +} +#endif + +static const AVOption sbg_options[] = { + { "sample_rate", "", offsetof(struct sbg_demuxer, sample_rate), + AV_OPT_TYPE_INT, { .dbl = 0 }, 0, INT_MAX, + AV_OPT_FLAG_DECODING_PARAM }, + { "frame_size", "", offsetof(struct sbg_demuxer, frame_size), + AV_OPT_TYPE_INT, { .dbl = 0 }, 0, INT_MAX, + AV_OPT_FLAG_DECODING_PARAM }, + { "max_file_size", "", offsetof(struct sbg_demuxer, max_file_size), + AV_OPT_TYPE_INT, { .dbl = 5000000 }, 0, INT_MAX, + AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass sbg_demuxer_class = { + .class_name = "sbg_demuxer", + .item_name = av_default_item_name, + .option = sbg_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_sbg_demuxer = { + .name = "sbg", + .long_name = NULL_IF_CONFIG_SMALL("SBaGen binaural beats script"), + .priv_data_size = sizeof(struct sbg_demuxer), + .read_probe = sbg_read_probe, + .read_header = sbg_read_header, + .read_packet = sbg_read_packet, +#if FF_API_READ_SEEK + .read_seek = sbg_read_seek, +#endif + .read_seek2 = sbg_read_seek2, + .extensions = "sbg", + .priv_class = &sbg_demuxer_class, +}; diff --git a/libavformat/sdp.c b/libavformat/sdp.c index ddf28bd7ab..2417663885 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -1,20 +1,20 @@ /* * copyright (c) 2007 Luca Abeni * - * 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 */ @@ -419,7 +419,7 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, payload_type, config ? config : ""); break; case CODEC_ID_AAC: - if (fmt && fmt->oformat->priv_class && + if (fmt && fmt->oformat && fmt->oformat->priv_class && av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) { config = latm_context2config(c); if (!config) diff --git a/libavformat/seek-test.c b/libavformat/seek-test.c index 699c693c3f..9d7575d39e 100644 --- a/libavformat/seek-test.c +++ b/libavformat/seek-test.c @@ -2,20 +2,20 @@ * Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2007 Michael Niedermayer * - * 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 */ @@ -48,13 +48,12 @@ static const char *ret_str(int v) static void ts_str(char buffer[60], int64_t ts, AVRational base) { - double tsval; if (ts == AV_NOPTS_VALUE) { strcpy(buffer, " NOPTS "); return; } - tsval = ts * av_q2d(base); - snprintf(buffer, 60, "%9f", tsval); + ts= av_rescale_q(ts, base, (AVRational){1, 1000000}); + snprintf(buffer, 60, "%c%"PRId64".%06"PRId64"", ts<0 ? '-' : ' ', FFABS(ts)/1000000, FFABS(ts)%1000000); } int main(int argc, char **argv) diff --git a/libavformat/seek.c b/libavformat/seek.c index 6c4286bb8e..65211bfacf 100644 --- a/libavformat/seek.c +++ b/libavformat/seek.c @@ -3,20 +3,20 @@ * * Copyright (c) 2009 Ivan Schreter * - * 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/libavformat/seek.h b/libavformat/seek.h index fd95f497d6..408f7d6ac7 100644 --- a/libavformat/seek.h +++ b/libavformat/seek.h @@ -3,20 +3,20 @@ * * Copyright (c) 2009 Ivan Schreter * - * 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/libavformat/segafilm.c b/libavformat/segafilm.c index 83ba4f06ad..210dedad48 100644 --- a/libavformat/segafilm.c +++ b/libavformat/segafilm.c @@ -2,20 +2,20 @@ * Sega FILM Format (CPK) Demuxer * Copyright (c) 2003 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 */ @@ -30,6 +30,7 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" +#include "avio_internal.h" #define FILM_TAG MKBETAG('F', 'I', 'L', 'M') #define FDSC_TAG MKBETAG('F', 'D', 'S', 'C') @@ -263,6 +264,8 @@ static int film_read_packet(AVFormatContext *s, (film->audio_type != 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); diff --git a/libavformat/segment.c b/libavformat/segment.c index 89ae62d312..c75dd9c216 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -206,7 +206,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) if (seg->list) { avio_printf(seg->pb, "%s\n", oc->filename); avio_flush(seg->pb); - if (!(seg->number % seg->size)) { + if (seg->size && !(seg->number % seg->size)) { avio_close(seg->pb); if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL)) < 0) diff --git a/libavformat/sierravmd.c b/libavformat/sierravmd.c index 48b192e04c..18bcb38bbf 100644 --- a/libavformat/sierravmd.c +++ b/libavformat/sierravmd.c @@ -2,20 +2,20 @@ * Sierra VMD Format Demuxer * Copyright (c) 2004 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 */ @@ -30,6 +30,7 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" +#include "avio_internal.h" #define VMD_HEADER_SIZE 0x0330 #define BYTES_PER_FRAME_RECORD 16 @@ -245,6 +246,8 @@ static int vmd_read_packet(AVFormatContext *s, /* position the stream (will probably be there already) */ avio_seek(pb, frame->frame_offset, SEEK_SET); + if(ffio_limit(pb, frame->frame_size) != frame->frame_size) + return AVERROR(EIO); if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD)) return AVERROR(ENOMEM); pkt->pos= avio_tell(pb); diff --git a/libavformat/siff.c b/libavformat/siff.c index 7e5b0b4d8c..e0f21f3f4b 100644 --- a/libavformat/siff.c +++ b/libavformat/siff.c @@ -2,26 +2,27 @@ * Beam Software SIFF demuxer * Copyright (c) 2007 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 */ #include "libavutil/intreadwrite.h" #include "avformat.h" #include "internal.h" +#include "avio_internal.h" enum SIFFTags{ TAG_SIFF = MKTAG('S', 'I', 'F', 'F'), @@ -201,13 +202,16 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt) } if (!c->curstrm){ - size = c->pktsize - c->sndsize; - if (av_new_packet(pkt, size) < 0) + size = c->pktsize - c->sndsize - c->gmcsize - 2; + size = ffio_limit(s->pb, size); + if(size < 0 || c->pktsize < c->sndsize) + return AVERROR_INVALIDDATA; + if (av_new_packet(pkt, size + c->gmcsize + 2) < 0) return AVERROR(ENOMEM); AV_WL16(pkt->data, c->flags); if (c->gmcsize) memcpy(pkt->data + 2, c->gmc, c->gmcsize); - avio_read(s->pb, pkt->data + 2 + c->gmcsize, size - c->gmcsize - 2); + avio_read(s->pb, pkt->data + 2 + c->gmcsize, size); pkt->stream_index = 0; c->curstrm = -1; }else{ diff --git a/libavformat/smacker.c b/libavformat/smacker.c index adc67e727e..c023b0ea27 100644 --- a/libavformat/smacker.c +++ b/libavformat/smacker.c @@ -2,20 +2,20 @@ * Smacker demuxer * Copyright (c) 2006 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 */ @@ -238,7 +238,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) int frame_size = 0; int palchange = 0; - if (s->pb->eof_reached || smk->cur_frame >= smk->frames) + if (url_feof(s->pb) || smk->cur_frame >= smk->frames) return AVERROR_EOF; /* if we demuxed all streams, pass another frame */ @@ -255,6 +255,8 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) memcpy(oldpal, pal, 768); size = avio_r8(s->pb); size = size * 4 - 1; + if(size + 1 > frame_size) + return AVERROR_INVALIDDATA; frame_size -= size; frame_size--; sz = 0; @@ -289,10 +291,12 @@ 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) { - int size; + unsigned int size; uint8_t *tmpbuf; size = avio_rl32(s->pb) - 4; + if(size + 4L > frame_size) + return AVERROR_INVALIDDATA; frame_size -= size; frame_size -= 4; smk->curstream++; diff --git a/libavformat/smjpeg.c b/libavformat/smjpeg.c index 573a8a3536..82316ed448 100644 --- a/libavformat/smjpeg.c +++ b/libavformat/smjpeg.c @@ -2,20 +2,20 @@ * SMJPEG common code * Copyright (c) 2011-2012 Paul B Mahol * - * 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/libavformat/sol.c b/libavformat/sol.c index 4b3a5adbc0..700078c9cc 100644 --- a/libavformat/sol.c +++ b/libavformat/sol.c @@ -2,20 +2,20 @@ * Sierra SOL demuxer * Copyright 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 */ @@ -128,7 +128,7 @@ static int sol_read_packet(AVFormatContext *s, { int ret; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); ret= av_get_packet(s->pb, pkt, MAX_SIZE); if (ret < 0) diff --git a/libavformat/sox.h b/libavformat/sox.h index e59531bea3..f4a12e93ff 100644 --- a/libavformat/sox.h +++ b/libavformat/sox.h @@ -2,20 +2,20 @@ * SoX native format common data * Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu> * - * 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/libavformat/soxdec.c b/libavformat/soxdec.c index 29d13d4f7b..282e16ec43 100644 --- a/libavformat/soxdec.c +++ b/libavformat/soxdec.c @@ -5,20 +5,20 @@ * Based on libSoX sox-fmt.c * Copyright (c) 2008 robs@users.sourceforge.net * - * 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 */ @@ -97,6 +97,8 @@ static int sox_read_header(AVFormatContext *s) if (comment_size && comment_size < UINT_MAX) { char *comment = av_malloc(comment_size+1); + if(!comment) + return AVERROR(ENOMEM); if (avio_read(pb, comment, comment_size) != comment_size) { av_freep(&comment); return AVERROR(EIO); @@ -129,7 +131,7 @@ static int sox_read_packet(AVFormatContext *s, { int ret, size; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR_EOF; size = SOX_SAMPLES*s->streams[0]->codec->block_align; diff --git a/libavformat/soxenc.c b/libavformat/soxenc.c index 55d5bd98c0..811cb0e97d 100644 --- a/libavformat/soxenc.c +++ b/libavformat/soxenc.c @@ -5,20 +5,20 @@ * Based on libSoX sox-fmt.c * Copyright (c) 2008 robs@users.sourceforge.net * - * 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/libavformat/spdif.c b/libavformat/spdif.c index 777ac47ba5..604141a261 100644 --- a/libavformat/spdif.c +++ b/libavformat/spdif.c @@ -2,20 +2,20 @@ * IEC 61937 common code * Copyright (c) 2009 Bartlomiej Wolowiec * - * 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/libavformat/spdif.h b/libavformat/spdif.h index b2a6b63be4..4b11de20d1 100644 --- a/libavformat/spdif.h +++ b/libavformat/spdif.h @@ -2,20 +2,20 @@ * IEC 61937 common header * Copyright (c) 2009 Bartlomiej Wolowiec * - * 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/libavformat/spdifdec.c b/libavformat/spdifdec.c index 106dd8f479..89e9b7c3d8 100644 --- a/libavformat/spdifdec.c +++ b/libavformat/spdifdec.c @@ -2,20 +2,20 @@ * IEC 61937 demuxer * Copyright (c) 2010 Anssi Hannula <anssi.hannula at iki.fi> * - * 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 */ @@ -171,7 +171,7 @@ static int spdif_read_packet(AVFormatContext *s, AVPacket *pkt) while (state != (AV_BSWAP16C(SYNCWORD1) << 16 | AV_BSWAP16C(SYNCWORD2))) { state = (state << 8) | avio_r8(pb); - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR_EOF; } diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 5a1b8e4cb0..05b3879d45 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -4,20 +4,20 @@ * Copyright (c) 2010 Anssi Hannula * Copyright (c) 2010 Carl Eugen Hoyos * - * 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 */ @@ -521,13 +521,13 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) } if (ctx->extra_bswap ^ (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN)) { - avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1); + avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1); } else { - av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE); - if (!ctx->buffer) - return AVERROR(ENOMEM); - ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1); - avio_write(s->pb, ctx->buffer, ctx->out_bytes & ~1); + av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE); + if (!ctx->buffer) + return AVERROR(ENOMEM); + ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1); + avio_write(s->pb, ctx->buffer, ctx->out_bytes & ~1); } /* a final lone byte has to be MSB aligned */ diff --git a/libavformat/srtdec.c b/libavformat/srtdec.c index d170f9f856..481f4a6bb0 100644 --- a/libavformat/srtdec.c +++ b/libavformat/srtdec.c @@ -2,20 +2,20 @@ * SubRip subtitle demuxer * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org> * - * 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 */ @@ -81,7 +81,7 @@ static int srt_read_packet(AVFormatContext *s, AVPacket *pkt) do { ptr2 = ptr; ptr += ff_get_line(s->pb, ptr, sizeof(buffer)+buffer-ptr); - } while (!is_eol(*ptr2) && !s->pb->eof_reached && ptr-buffer<sizeof(buffer)-1); + } while (!is_eol(*ptr2) && !url_feof(s->pb) && ptr-buffer<sizeof(buffer)-1); if (buffer[0] && !(res = av_new_packet(pkt, ptr-buffer))) { memcpy(pkt->data, buffer, pkt->size); diff --git a/libavformat/swf.h b/libavformat/swf.h index 2be6cd5795..affebe9c73 100644 --- a/libavformat/swf.h +++ b/libavformat/swf.h @@ -3,20 +3,20 @@ * Copyright (c) 2000 Fabrice Bellard * Copyright (c) 2003 Tinic Uro * - * 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/libavformat/swfdec.c b/libavformat/swfdec.c index 842cda3349..f24d0a898c 100644 --- a/libavformat/swfdec.c +++ b/libavformat/swfdec.c @@ -3,20 +3,20 @@ * Copyright (c) 2000 Fabrice Bellard * Copyright (c) 2003 Tinic Uro * - * 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 */ @@ -27,8 +27,8 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr) { int tag, len; - if (pb->eof_reached) - return -1; + if (url_feof(pb)) + return AVERROR_EOF; tag = avio_rl16(pb); len = tag & 0x3f; @@ -90,7 +90,7 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) uint64_t pos = avio_tell(pb); tag = get_swf_tag(pb, &len); if (tag < 0) - return AVERROR(EIO); + return tag; if (tag == TAG_VIDEOSTREAM) { int ch_id = avio_rl16(pb); len -= 2; diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c index f4494cd63a..af812d09eb 100644 --- a/libavformat/swfenc.c +++ b/libavformat/swfenc.c @@ -3,20 +3,20 @@ * Copyright (c) 2000 Fabrice Bellard * Copyright (c) 2003 Tinic Uro * - * 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 */ @@ -421,7 +421,7 @@ static int swf_write_video(AVFormatContext *s, put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG); avio_wl16(pb, swf->sound_samples); avio_wl16(pb, 0); // seek samples - av_fifo_generic_read(swf->audio_fifo, pb, frame_size, &avio_write); + av_fifo_generic_read(swf->audio_fifo, pb, frame_size, (void*)avio_write); put_swf_end_tag(s); /* update FIFO */ diff --git a/libavformat/tcp.c b/libavformat/tcp.c index fdb457e8c5..4eaf0a02b4 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -2,20 +2,20 @@ * TCP protocol * Copyright (c) 2002 Fabrice Bellard * - * 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" @@ -45,7 +45,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) char buf[256]; int ret; socklen_t optlen; - int timeout = 100; + int timeout = 50; char hostname[1024],proto[1024],path[1024]; char portstr[10]; diff --git a/libavformat/thp.c b/libavformat/thp.c index 731f5af968..dc30fbaf70 100644 --- a/libavformat/thp.c +++ b/libavformat/thp.c @@ -2,20 +2,20 @@ * THP Demuxer * Copyright (c) 2007 Marco Gerards * - * 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,7 +41,7 @@ typedef struct ThpDemuxContext { unsigned char components[16]; AVStream* vst; int has_audio; - int audiosize; + unsigned audiosize; } ThpDemuxContext; @@ -59,6 +59,7 @@ static int thp_read_header(AVFormatContext *s) ThpDemuxContext *thp = s->priv_data; AVStream *st; AVIOContext *pb = s->pb; + int64_t fsize= avio_size(pb); int i; /* Read the file header. */ @@ -71,7 +72,9 @@ static int thp_read_header(AVFormatContext *s) thp->fps = av_d2q(av_int2float(avio_rb32(pb)), INT_MAX); thp->framecnt = avio_rb32(pb); thp->first_framesz = avio_rb32(pb); - avio_rb32(pb); /* Data size. */ + pb->maxsize = avio_rb32(pb); + if(fsize>0 && (!pb->maxsize || fsize < pb->maxsize)) + pb->maxsize= fsize; thp->compoff = avio_rb32(pb); avio_rb32(pb); /* offsetDataOffset. */ @@ -142,7 +145,7 @@ static int thp_read_packet(AVFormatContext *s, { ThpDemuxContext *thp = s->priv_data; AVIOContext *pb = s->pb; - int size; + unsigned int size; int ret; if (thp->audiosize == 0) { diff --git a/libavformat/tiertexseq.c b/libavformat/tiertexseq.c index 194c83abc1..d2d4e880c2 100644 --- a/libavformat/tiertexseq.c +++ b/libavformat/tiertexseq.c @@ -2,20 +2,20 @@ * Tiertex Limited SEQ File Demuxer * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) * - * 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/libavformat/tmv.c b/libavformat/tmv.c index 0f8ab597ad..bfc5326068 100644 --- a/libavformat/tmv.c +++ b/libavformat/tmv.c @@ -2,20 +2,20 @@ * 8088flex TMV file demuxer * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu> * - * 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 */ @@ -147,7 +147,7 @@ static int tmv_read_packet(AVFormatContext *s, AVPacket *pkt) int ret, pkt_size = tmv->stream_index ? tmv->audio_chunk_size : tmv->video_chunk_size; - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR_EOF; ret = av_get_packet(pb, pkt, pkt_size); @@ -174,7 +174,8 @@ static int tmv_read_seek(AVFormatContext *s, int stream_index, pos = timestamp * (tmv->audio_chunk_size + tmv->video_chunk_size + tmv->padding); - avio_seek(s->pb, pos + TMV_HEADER_SIZE, SEEK_SET); + if (avio_seek(s->pb, pos + TMV_HEADER_SIZE, SEEK_SET) < 0) + return -1; tmv->stream_index = 0; return 0; } diff --git a/libavformat/tta.c b/libavformat/tta.c index 4d6bc0aff2..c2f0902535 100644 --- a/libavformat/tta.c +++ b/libavformat/tta.c @@ -2,20 +2,20 @@ * TTA demuxer * Copyright (c) 2006 Alex Beregszaszi * - * 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 */ @@ -73,8 +73,8 @@ static int tta_read_header(AVFormatContext *s) c->totalframes = datalen / framelen + ((datalen % framelen) ? 1 : 0); c->currentframe = 0; - if(c->totalframes >= UINT_MAX/sizeof(uint32_t)){ - av_log(s, AV_LOG_ERROR, "totalframes too large\n"); + 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; } @@ -142,9 +142,10 @@ static int tta_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp int index = av_index_search_timestamp(st, timestamp, flags); if (index < 0) return -1; + if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0) + return -1; c->currentframe = index; - avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET); return 0; } diff --git a/libavformat/tty.c b/libavformat/tty.c index 84f99377da..6d8a6eb541 100644 --- a/libavformat/tty.c +++ b/libavformat/tty.c @@ -2,20 +2,20 @@ * Tele-typewriter demuxer * Copyright (c) 2010 Peter Ross <pross@xvid.org> * - * 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 */ @@ -121,7 +121,7 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt) TtyDemuxContext *s = avctx->priv_data; int n; - if (avctx->pb->eof_reached) + if (url_feof(avctx->pb)) return AVERROR_EOF; n = s->chars_per_frame; diff --git a/libavformat/txd.c b/libavformat/txd.c index acf15554ff..f6060330ba 100644 --- a/libavformat/txd.c +++ b/libavformat/txd.c @@ -2,20 +2,20 @@ * Renderware TeXture Dictionary (.txd) demuxer * Copyright (c) 2007 Ivo van Poorten * - * 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 */ @@ -48,6 +48,7 @@ static int txd_read_header(AVFormatContext *s) { st->codec->time_base.den = 5; st->codec->time_base.num = 1; /* the parameters will be extracted from the compressed bitstream */ + return 0; } @@ -61,7 +62,7 @@ next_chunk: chunk_size = avio_rl32(pb); marker = avio_rl32(pb); - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR_EOF; if (marker != TXD_MARKER && marker != TXD_MARKER2) { av_log(s, AV_LOG_ERROR, "marker does not match\n"); diff --git a/libavformat/udp.c b/libavformat/udp.c index 8bb63c6298..9694ad2f57 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -2,20 +2,20 @@ * UDP prototype streaming system * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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 */ @@ -29,12 +29,19 @@ #include "avformat.h" #include "avio_internal.h" #include "libavutil/parseutils.h" +#include "libavutil/fifo.h" +#include "libavutil/intreadwrite.h" #include "libavutil/avstring.h" #include <unistd.h> #include "internal.h" #include "network.h" #include "os_support.h" #include "url.h" + +#if HAVE_PTHREADS +#include <pthread.h> +#endif + #include <sys/time.h> #ifndef IPV6_ADD_MEMBERSHIP @@ -42,6 +49,9 @@ #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif +#define UDP_TX_BUF_SIZE 32768 +#define UDP_MAX_PKT_SIZE 65536 + typedef struct { int udp_fd; int ttl; @@ -52,10 +62,21 @@ typedef struct { struct sockaddr_storage dest_addr; int dest_addr_len; int is_connected; -} UDPContext; -#define UDP_TX_BUF_SIZE 32768 -#define UDP_MAX_PKT_SIZE 65536 + /* Circular Buffer variables for use in UDP receive code */ + int circular_buffer_size; + AVFifoBuffer *fifo; + int circular_buffer_error; +#if HAVE_PTHREADS + pthread_t circular_buffer_thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + int thread_started; + volatile int exit_thread; +#endif + uint8_t tmp[UDP_MAX_PKT_SIZE+4]; + int remaining_in_dg; +} UDPContext; static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) @@ -300,6 +321,73 @@ static int udp_get_file_handle(URLContext *h) return s->udp_fd; } +#if HAVE_PTHREADS +static void *circular_buffer_task( void *_URLContext) +{ + URLContext *h = _URLContext; + UDPContext *s = h->priv_data; + fd_set rfds; + struct timeval tv; + + while(!s->exit_thread) { + int left; + int ret; + int len; + + if (ff_check_interrupt(&h->interrupt_callback)) { + s->circular_buffer_error = EINTR; + goto end; + } + + FD_ZERO(&rfds); + FD_SET(s->udp_fd, &rfds); + tv.tv_sec = 1; + tv.tv_usec = 0; + ret = select(s->udp_fd + 1, &rfds, NULL, NULL, &tv); + if (ret < 0) { + if (ff_neterrno() == AVERROR(EINTR)) + continue; + s->circular_buffer_error = EIO; + goto end; + } + + if (!(ret > 0 && FD_ISSET(s->udp_fd, &rfds))) + continue; + + /* How much do we have left to the end of the buffer */ + /* Whats the minimum we can read so that we dont comletely fill the buffer */ + left = av_fifo_space(s->fifo); + + /* No Space left, error, what do we do now */ + if(left < UDP_MAX_PKT_SIZE + 4) { + av_log(h, AV_LOG_ERROR, "circular_buffer: OVERRUN\n"); + s->circular_buffer_error = EIO; + goto end; + } + left = FFMIN(left, s->fifo->end - s->fifo->wptr); + len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0); + if (len < 0) { + if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) { + s->circular_buffer_error = EIO; + goto end; + } + continue; + } + AV_WL32(s->tmp, len); + pthread_mutex_lock(&s->mutex); + av_fifo_generic_write(s->fifo, s->tmp, len+4, NULL); + pthread_cond_signal(&s->cond); + pthread_mutex_unlock(&s->mutex); + } + +end: + pthread_mutex_lock(&s->mutex); + pthread_cond_signal(&s->cond); + pthread_mutex_unlock(&s->mutex); + return NULL; +} +#endif + /* put it in UDP context */ /* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) @@ -322,6 +410,8 @@ static int udp_open(URLContext *h, const char *uri, int flags) s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; + s->circular_buffer_size = 7*188*4096; + p = strchr(uri, '?'); if (p) { if (av_find_info_tag(buf, sizeof(buf), "reuse", p)) { @@ -347,6 +437,9 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { s->is_connected = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) { + s->circular_buffer_size = strtol(buf, NULL, 10)*188; + } if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) { av_strlcpy(localaddr, buf, sizeof(localaddr)); } @@ -431,10 +524,43 @@ static int udp_open(URLContext *h, const char *uri, int flags) } s->udp_fd = udp_fd; + +#if HAVE_PTHREADS + if (!is_output && s->circular_buffer_size) { + int ret; + + /* start the task going */ + s->fifo = av_fifo_alloc(s->circular_buffer_size); + ret = pthread_mutex_init(&s->mutex, NULL); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", strerror(ret)); + goto fail; + } + ret = pthread_cond_init(&s->cond, NULL); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", strerror(ret)); + goto cond_fail; + } + ret = pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h); + if (ret != 0) { + av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", strerror(ret)); + goto thread_fail; + } + s->thread_started = 1; + } +#endif + return 0; +#if HAVE_PTHREADS + thread_fail: + pthread_cond_destroy(&s->cond); + cond_fail: + pthread_mutex_destroy(&s->mutex); +#endif fail: if (udp_fd >= 0) closesocket(udp_fd); + av_fifo_free(s->fifo); return AVERROR(EIO); } @@ -442,6 +568,40 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) { UDPContext *s = h->priv_data; int ret; + int avail; + +#if HAVE_PTHREADS + if (s->fifo) { + pthread_mutex_lock(&s->mutex); + do { + avail = av_fifo_size(s->fifo); + if (avail) { // >=size) { + uint8_t tmp[4]; + pthread_mutex_unlock(&s->mutex); + + av_fifo_generic_read(s->fifo, tmp, 4, NULL); + avail= AV_RL32(tmp); + if(avail > size){ + av_log(h, AV_LOG_WARNING, "Part of datagram lost due to insufficient buffer size\n"); + avail= size; + } + + av_fifo_generic_read(s->fifo, buf, avail, NULL); + av_fifo_drain(s->fifo, AV_RL32(tmp) - avail); + return avail; + } else if(s->circular_buffer_error){ + pthread_mutex_unlock(&s->mutex); + return s->circular_buffer_error; + } else if(h->flags & AVIO_FLAG_NONBLOCK) { + pthread_mutex_unlock(&s->mutex); + return AVERROR(EAGAIN); + } + else { + pthread_cond_wait(&s->cond, &s->mutex); + } + } while( 1); + } +#endif if (!(h->flags & AVIO_FLAG_NONBLOCK)) { ret = ff_network_wait_fd(s->udp_fd, 0); @@ -449,6 +609,7 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) return ret; } ret = recv(s->udp_fd, buf, size, 0); + return ret < 0 ? ff_neterrno() : ret; } @@ -476,10 +637,23 @@ static int udp_write(URLContext *h, const uint8_t *buf, int size) static int udp_close(URLContext *h) { UDPContext *s = h->priv_data; + int ret; if (s->is_multicast && (h->flags & AVIO_FLAG_READ)) udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); closesocket(s->udp_fd); + av_fifo_free(s->fifo); +#if HAVE_PTHREADS + if (s->thread_started) { + s->exit_thread = 1; + ret = pthread_join(s->circular_buffer_thread, NULL); + if (ret != 0) + av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", strerror(ret)); + } + + pthread_mutex_destroy(&s->mutex); + pthread_cond_destroy(&s->cond); +#endif return 0; } diff --git a/libavformat/url.h b/libavformat/url.h index 265a8ab2b6..b459a59e03 100644 --- a/libavformat/url.h +++ b/libavformat/url.h @@ -1,19 +1,19 @@ /* * - * 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/libavformat/utils.c b/libavformat/utils.c index 41450971af..912c2baaa8 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -1,21 +1,21 @@ /* - * various utility functions for use within Libav + * various utility functions for use within FFmpeg * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * - * 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 */ @@ -25,7 +25,9 @@ #include "avio_internal.h" #include "internal.h" #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/pixdesc.h" @@ -50,23 +52,24 @@ /** * @file - * various utility functions for use within Libav + * various utility functions for use within FFmpeg */ unsigned avformat_version(void) { + av_assert0(LIBAVFORMAT_VERSION_MICRO >= 100); return LIBAVFORMAT_VERSION_INT; } const char *avformat_configuration(void) { - return LIBAV_CONFIGURATION; + return FFMPEG_CONFIGURATION; } const char *avformat_license(void) { #define LICENSE_PREFIX "libavformat license: " - return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1; + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; } /* fraction handling */ @@ -265,10 +268,32 @@ AVInputFormat *av_find_input_format(const char *short_name) return NULL; } +int ffio_limit(AVIOContext *s, int size) +{ + if(s->maxsize>=0){ + int64_t remaining= s->maxsize - avio_tell(s); + if(remaining < size){ + int64_t newsize= avio_size(s); + if(!s->maxsize || s->maxsize<newsize) + s->maxsize= newsize - !newsize; + remaining= s->maxsize - avio_tell(s); + remaining= FFMAX(remaining, 0); + } + + if(s->maxsize>=0 && remaining+1 < size){ + av_log(0, AV_LOG_ERROR, "Truncating packet of size %d to %"PRId64"\n", size, remaining+1); + size= remaining+1; + } + } + return size; +} int av_get_packet(AVIOContext *s, AVPacket *pkt, int size) { - int ret= av_new_packet(pkt, size); + int ret; + size= ffio_limit(s, size); + + ret= av_new_packet(pkt, size); if(ret<0) return ret; @@ -306,19 +331,19 @@ int av_filename_number_test(const char *filename) return filename && (av_get_frame_filename(buf, sizeof(buf), filename, 1)>=0); } -AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret) { AVProbeData lpd = *pd; AVInputFormat *fmt1 = NULL, *fmt; - int score, id3 = 0; + int score, nodat = 0, score_max=0; if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) { int id3len = ff_id3v2_tag_len(lpd.buf); if (lpd.buf_size > id3len + 16) { lpd.buf += id3len; lpd.buf_size -= id3len; - } - id3 = 1; + }else + nodat = 1; } fmt = NULL; @@ -328,44 +353,41 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score score = 0; 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); } else if (fmt1->extensions) { if (av_match_ext(lpd.filename, fmt1->extensions)) { score = 50; } } - if (score > *score_max) { - *score_max = score; + if (score > score_max) { + score_max = score; fmt = fmt1; - }else if (score == *score_max) + }else if (score == score_max) fmt = NULL; } - - /* a hack for files with huge id3v2 tags -- try to guess by file extension. */ - if (!fmt && is_opened && *score_max < AVPROBE_SCORE_MAX/4) { - while ((fmt = av_iformat_next(fmt))) - if (fmt->extensions && av_match_ext(lpd.filename, fmt->extensions)) { - *score_max = AVPROBE_SCORE_MAX/4; - break; - } - } - - if (!fmt && id3 && *score_max < AVPROBE_SCORE_MAX/4-1) { - while ((fmt = av_iformat_next(fmt))) - if (fmt->extensions && av_match_ext("mp3", fmt->extensions)) { - *score_max = AVPROBE_SCORE_MAX/4-1; - break; - } - } + *score_ret= score_max; return fmt; } +AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) +{ + int score_ret; + AVInputFormat *fmt= av_probe_input_format3(pd, is_opened, &score_ret); + if(score_ret > *score_max){ + *score_max= score_ret; + return fmt; + }else + return NULL; +} + AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened){ int score=0; return av_probe_input_format2(pd, is_opened, &score); } -static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd, int score) +static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeData *pd) { static const struct { const char *name; enum CodecID id; enum AVMediaType type; @@ -375,12 +397,14 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa { "dts" , CODEC_ID_DTS , AVMEDIA_TYPE_AUDIO }, { "eac3" , CODEC_ID_EAC3 , AVMEDIA_TYPE_AUDIO }, { "h264" , CODEC_ID_H264 , AVMEDIA_TYPE_VIDEO }, + { "loas" , CODEC_ID_AAC_LATM , AVMEDIA_TYPE_AUDIO }, { "m4v" , CODEC_ID_MPEG4 , AVMEDIA_TYPE_VIDEO }, { "mp3" , CODEC_ID_MP3 , AVMEDIA_TYPE_AUDIO }, { "mpegvideo", CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO }, { 0 } }; - AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score); + int score; + AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score); if (fmt) { int i; @@ -394,12 +418,28 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, AVProbeDa } } } - return !!fmt; + return score; } /************************************************************/ /* input media file */ +int av_demuxer_open(AVFormatContext *ic){ + int err; + + if (ic->iformat->read_header) { + err = ic->iformat->read_header(ic); + if (err < 0) + return err; + } + + if (ic->pb && !ic->data_offset) + ic->data_offset = avio_tell(ic->pb); + + return 0; +} + + /** size of probe buffer, for guessing file type from file contents */ #define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1<<20) @@ -428,13 +468,19 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, probe_size = FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1))) { int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX/4 : 0; int buf_offset = (probe_size == PROBE_BUF_MIN) ? 0 : probe_size>>1; + void *buftmp; if (probe_size < offset) { continue; } /* read probe data */ - buf = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); + buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); + if(!buftmp){ + av_free(buf); + return AVERROR(ENOMEM); + } + buf=buftmp; 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) { @@ -453,9 +499,9 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, *fmt = av_probe_input_format2(&pd, 1, &score); if(*fmt){ if(score <= AVPROBE_SCORE_MAX/4){ //this can only be true in the last iteration - av_log(logctx, AV_LOG_WARNING, "Format detected only with low score of %d, misdetection possible!\n", score); + 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, "Probed with size=%d and score=%d\n", probe_size, score); + av_log(logctx, AV_LOG_DEBUG, "Format %s probed with size=%d and score=%d\n", (*fmt)->name, probe_size, score); } } @@ -482,7 +528,8 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o if (!s->iformat) return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); else if (s->iformat->flags & AVFMT_NOFILE) - return AVERROR(EINVAL); + av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and " + "will be ignored with AVFMT_NOFILE format.\n"); return 0; } @@ -547,11 +594,11 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma if (s->pb) ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC); - if (s->iformat->read_header) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) if ((ret = s->iformat->read_header(s)) < 0) goto fail; - if (s->pb && !s->data_offset) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset) s->data_offset = avio_tell(s->pb); s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; @@ -601,12 +648,7 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) if (pktl) { *pkt = pktl->pkt; - if(s->streams[pkt->stream_index]->codec->codec_id != CODEC_ID_PROBE || - !s->streams[pkt->stream_index]->probe_packets || - s->raw_packet_buffer_remaining_size < pkt->size){ - AVProbeData *pd = &s->streams[pkt->stream_index]->probe_data; - av_freep(&pd->buf); - pd->buf_size = 0; + if(s->streams[pkt->stream_index]->request_probe <= 0){ s->raw_packet_buffer = pktl->next; s->raw_packet_buffer_remaining_size += pkt->size; av_free(pktl); @@ -620,7 +662,8 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) if (!pktl || ret == AVERROR(EAGAIN)) return ret; for (i = 0; i < s->nb_streams; i++) - s->streams[i]->probe_packets = 0; + if(s->streams[i]->request_probe > 0) + s->streams[i]->request_probe = -1; continue; } @@ -633,6 +676,14 @@ int av_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]; switch(st->codec->codec_type){ @@ -647,16 +698,16 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) break; } - if(!pktl && (st->codec->codec_id != CODEC_ID_PROBE || - !st->probe_packets)) + if(!pktl && st->request_probe <= 0) return ret; add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); s->raw_packet_buffer_remaining_size -= pkt->size; - if(st->codec->codec_id == CODEC_ID_PROBE){ + if(st->request_probe>0){ AVProbeData *pd = &st->probe_data; - av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index); + int end; + av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets); --st->probe_packets; pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); @@ -664,13 +715,20 @@ int av_read_packet(AVFormatContext *s, AVPacket *pkt) pd->buf_size += pkt->size; memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE); - if(av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){ - //FIXME we do not reduce score to 0 for the case of running out of buffer space in bytes - set_codec_from_probe_data(s, st, pd, st->probe_packets > 0 ? AVPROBE_SCORE_MAX/4 : 0); - if(st->codec->codec_id != CODEC_ID_PROBE){ + end= s->raw_packet_buffer_remaining_size <= 0 + || st->probe_packets<=0; + + if(end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){ + int score= set_codec_from_probe_data(s, st, pd); + if( (st->codec->codec_id != CODEC_ID_NONE && score > AVPROBE_SCORE_MAX/4) + || end){ pd->buf_size=0; av_freep(&pd->buf); + st->request_probe= -1; + if(st->codec->codec_id != CODEC_ID_NONE){ av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index); + }else + av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index); } } } @@ -721,7 +779,7 @@ static void compute_frame_duration(int *pnum, int *pden, AVStream *st, *pden = 0; switch(st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: - if (st->r_frame_rate.num) { + if (st->r_frame_rate.num && !pc) { *pnum = st->r_frame_rate.den; *pden = st->r_frame_rate.num; } else if(st->time_base.num*1000LL > st->time_base.den) { @@ -868,8 +926,7 @@ 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 && pkt->dts > pkt->pts && st->pts_wrap_bits<63 - /*&& pkt->dts-(1LL<<st->pts_wrap_bits) < pkt->pts*/){ + if(pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && pkt->dts - (1LL<<(st->pts_wrap_bits-1)) > pkt->pts && st->pts_wrap_bits<63){ pkt->dts -= 1LL<<st->pts_wrap_bits; } @@ -877,8 +934,8 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, // we take the conservative approach and discard both // 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\n"); - pkt->dts= pkt->pts= AV_NOPTS_VALUE; + av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts); + pkt->dts= AV_NOPTS_VALUE; } if (pkt->duration == 0) { @@ -1015,7 +1072,10 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (!st->need_parsing || !st->parser) { /* no parsing needed: we just output the packet as is */ /* raw data support */ - *pkt = st->cur_pkt; st->cur_pkt.data= NULL; + *pkt = st->cur_pkt; + st->cur_pkt.data= NULL; + st->cur_pkt.side_data_elems = 0; + st->cur_pkt.side_data = NULL; compute_pkt_fields(s, st, NULL, pkt); s->cur_st = NULL; if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && @@ -1055,8 +1115,9 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) compute_pkt_fields(s, st, st->parser, pkt); if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY){ + int64_t pos= (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->pos : st->parser->frame_offset; ff_reduce_index(s, st->index); - av_add_index_entry(st, st->parser->frame_offset, pkt->dts, + av_add_index_entry(st, pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME); } @@ -1120,6 +1181,9 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) { st->parser = av_parser_init(st->codec->codec_id); if (!st->parser) { + av_log(s, AV_LOG_VERBOSE, "parser not found for codec " + "%s, packets or times may be invalid.\n", + avcodec_get_name(st->codec->codec_id)); /* no parser available: just output the raw packets */ st->need_parsing = AVSTREAM_PARSE_NONE; }else if(st->need_parsing == AVSTREAM_PARSE_HEADERS){ @@ -1270,7 +1334,8 @@ void ff_read_frame_flush(AVFormatContext *s) av_free_packet(&st->cur_pkt); } st->last_IP_pts = AV_NOPTS_VALUE; - st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ + if(st->first_dts == AV_NOPTS_VALUE) st->cur_dts = 0; + else st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ st->reference_dts = AV_NOPTS_VALUE; /* fail safe */ st->cur_ptr = NULL; @@ -1460,6 +1525,7 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0) return ret; + ff_read_frame_flush(s); ff_update_cur_dts(s, st, ts); return 0; @@ -1483,6 +1549,11 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, return -1; } + if(ts_min >= target_ts){ + *ts_ret= ts_min; + return pos_min; + } + if(ts_max == AV_NOPTS_VALUE){ int step= 1024; filesize = avio_size(s->pb); @@ -1508,6 +1579,11 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, pos_limit= pos_max; } + if(ts_max <= target_ts){ + *ts_ret= ts_max; + return pos_max; + } + if(ts_min > ts_max){ return -1; }else if(ts_min == ts_max){ @@ -1565,12 +1641,14 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max; +#if 0 pos_min = pos; ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX); pos_min++; ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX); av_dlog(s, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n", pos, ts_min, target_ts, ts_max); +#endif *ts_ret= ts; return pos; } @@ -1617,6 +1695,7 @@ static int seek_frame_generic(AVFormatContext *s, if(index < 0 || index==st->nb_index_entries-1){ AVPacket pkt; + int nonkey=0; if(st->nb_index_entries){ assert(st->index_entries); @@ -1636,9 +1715,13 @@ static int seek_frame_generic(AVFormatContext *s, if (read_status < 0) break; av_free_packet(&pkt); - if(stream_index == pkt.stream_index){ - if((pkt.flags & AV_PKT_FLAG_KEY) && pkt.dts > timestamp) + if(stream_index == pkt.stream_index && pkt.dts > timestamp){ + if(pkt.flags & AV_PKT_FLAG_KEY) + break; + if(nonkey++ > 1000 && st->codec->codec_id != CODEC_ID_CDGRAPHICS){ + av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey); break; + } } } index = av_index_search_timestamp(st, timestamp, flags); @@ -1647,10 +1730,12 @@ static int seek_frame_generic(AVFormatContext *s, return -1; ff_read_frame_flush(s); + AV_NOWARN_DEPRECATED( if (s->iformat->read_seek){ if(s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0) return 0; } + ) ie = &st->index_entries[index]; if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0) return ret; @@ -1682,11 +1767,13 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int f } /* first, we try the format specific seek */ + AV_NOWARN_DEPRECATED( if (s->iformat->read_seek) { ff_read_frame_flush(s); ret = s->iformat->read_seek(s, stream_index, timestamp, flags); } else ret = -1; + ) if (ret >= 0) { return 0; } @@ -1718,8 +1805,10 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int //Fallback to old API if new is not implemented but old is //Note the old has somewat different sematics + AV_NOWARN_DEPRECATED( if(s->iformat->read_seek || 1) return av_seek_frame(s, stream_index, ts, flags | (ts - min_ts > (uint64_t)(max_ts - ts) ? AVSEEK_FLAG_BACKWARD : 0)); + ) // try some generic seek like seek_frame_generic() but with new ts semantics } @@ -1735,6 +1824,8 @@ static int has_duration(AVFormatContext *ic) { int i; AVStream *st; + if(ic->duration != AV_NOPTS_VALUE) + return 1; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; @@ -1751,18 +1842,23 @@ static int has_duration(AVFormatContext *ic) */ static void update_stream_timings(AVFormatContext *ic) { - int64_t start_time, start_time1, end_time, end_time1; + int64_t start_time, start_time1, start_time_text, end_time, end_time1; int64_t duration, duration1, filesize; int i; AVStream *st; start_time = INT64_MAX; + start_time_text = INT64_MAX; end_time = INT64_MIN; duration = INT64_MIN; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) { start_time1= av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q); + if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + if (start_time1 < start_time_text) + start_time_text = start_time1; + } else start_time = FFMIN(start_time, start_time1); if (st->duration != AV_NOPTS_VALUE) { end_time1 = start_time1 @@ -1775,19 +1871,21 @@ static void update_stream_timings(AVFormatContext *ic) duration = FFMAX(duration, duration1); } } + if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE)) + start_time = start_time_text; if (start_time != INT64_MAX) { ic->start_time = start_time; if (end_time != INT64_MIN) duration = FFMAX(duration, end_time - start_time); } - if (duration != INT64_MIN) { + if (duration != INT64_MIN && ic->duration == AV_NOPTS_VALUE) { ic->duration = duration; - if (ic->pb && (filesize = avio_size(ic->pb)) > 0) { + } + if (ic->pb && (filesize = avio_size(ic->pb)) > 0 && ic->duration != AV_NOPTS_VALUE) { /* compute the bitrate */ ic->bit_rate = (double)filesize * 8.0 * AV_TIME_BASE / (double)ic->duration; } - } } static void fill_all_stream_timings(AVFormatContext *ic) @@ -1985,6 +2083,8 @@ static int has_codec_parameters(AVCodecContext *avctx) case AVMEDIA_TYPE_VIDEO: val = avctx->width && avctx->pix_fmt != PIX_FMT_NONE; break; + case AVMEDIA_TYPE_DATA: + if(avctx->codec_id == CODEC_ID_NONE) return 1; default: val = 1; break; @@ -2049,6 +2149,8 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option ret = got_picture; } } + if(!pkt.data && !got_picture) + return -1; return ret; } @@ -2149,6 +2251,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) AVPacket pkt1, *pkt; int64_t old_offset = avio_tell(ic->pb); int orig_nb_streams = ic->nb_streams; // new streams might appear, no options for those + int flush_codecs = 1; for(i=0;i<ic->nb_streams;i++) { AVCodec *codec; @@ -2226,7 +2329,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; - if(st->first_dts == AV_NOPTS_VALUE) + if(st->first_dts == AV_NOPTS_VALUE && (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || st->codec->codec_type == AVMEDIA_TYPE_AUDIO)) break; } if (i == ic->nb_streams) { @@ -2237,6 +2340,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) /* if we found the info for all the codecs, we can stop */ ret = count; av_log(ic, AV_LOG_DEBUG, "All info found\n"); + flush_codecs = 0; break; } } @@ -2255,33 +2359,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) if (ret < 0) { /* EOF or error*/ - AVPacket empty_pkt = { 0 }; - int err; - 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++) { - st = ic->streams[i]; - - /* flush the decoders */ - do { - err = try_decode_frame(st, &empty_pkt, - (options && i < orig_nb_streams) ? - &options[i] : NULL); - } while (err > 0 && !has_codec_parameters(st->codec)); - - if (err < 0) { - av_log(ic, AV_LOG_WARNING, - "decoding for stream %d failed\n", st->index); - } else if (!has_codec_parameters(st->codec)){ - char buf[256]; - avcodec_string(buf, sizeof(buf), st->codec, 0); - av_log(ic, AV_LOG_WARNING, - "Could not find codec parameters (%s)\n", buf); - } else { - ret = 0; - } - } break; } @@ -2293,8 +2370,14 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) st = ic->streams[pkt->stream_index]; if (st->codec_info_nb_frames>1) { - if (st->time_base.den > 0 && av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) { - av_log(ic, AV_LOG_WARNING, "max_analyze_duration reached\n"); + int64_t t=0; + if (st->time_base.den > 0) + t = av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q); + if (st->avg_frame_rate.num > 0) + t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, (AVRational){st->avg_frame_rate.den, st->avg_frame_rate.num}, AV_TIME_BASE_Q)); + + if (t >= ic->max_analyze_duration) { + av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached at %"PRId64"\n", ic->max_analyze_duration, t); break; } st->info->codec_info_duration += pkt->duration; @@ -2303,18 +2386,20 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int64_t last = st->info->last_dts; if(pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last){ + double dts= pkt->dts * av_q2d(st->time_base); int64_t duration= pkt->dts - last; - double dur= duration * av_q2d(st->time_base); -// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -// av_log(NULL, AV_LOG_ERROR, "%f\n", dur); - if (st->info->duration_count < 2) - memset(st->info->duration_error, 0, sizeof(st->info->duration_error)); - for (i=1; i<FF_ARRAY_ELEMS(st->info->duration_error); i++) { +// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) +// av_log(NULL, AV_LOG_ERROR, "%f\n", dts); + for (i=1; i<FF_ARRAY_ELEMS(st->info->duration_error[0][0]); i++) { int framerate= get_std_framerate(i); - int ticks= lrintf(dur*framerate/(1001*12)); - double error = dur - (double)ticks*1001*12 / framerate; - st->info->duration_error[i] += error*error; + double sdts= dts*framerate/(1001*12); + for(j=0; j<2; j++){ + int ticks= lrintf(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 @@ -2351,6 +2436,37 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) count++; } + if (flush_codecs) { + AVPacket empty_pkt = { 0 }; + int err; + 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++) { + st = ic->streams[i]; + + /* flush the decoders */ + do { + err = try_decode_frame(st, &empty_pkt, + (options && i < orig_nb_streams) ? + &options[i] : NULL); + } while (err > 0 && !has_codec_parameters(st->codec)); + + if (err < 0) { + av_log(ic, AV_LOG_INFO, + "decoding for stream %d failed\n", st->index); + } + if (!has_codec_parameters(st->codec)){ + char buf[256]; + avcodec_string(buf, sizeof(buf), st->codec, 0); + av_log(ic, AV_LOG_WARNING, + "Could not find codec parameters (%s)\n", buf); + } else { + ret = 0; + } + } + } + // close codecs which were opened in try_decode_frame() for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; @@ -2364,26 +2480,42 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) (st->codec_info_nb_frames-2)*(int64_t)st->time_base.den, st->info->codec_info_duration*(int64_t)st->time_base.num, 60000); if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if(st->codec->codec_id == CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample){ + uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); + if(ff_find_pix_fmt(ff_raw_pix_fmt_tags, tag) == st->codec->pix_fmt) + st->codec->codec_tag= tag; + } + // 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 > 1 && !st->r_frame_rate.num) + 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 && !st->r_frame_rate.num && tb_unreliable(st->codec) /*&& //FIXME we should not special-case MPEG-2, but this needs testing with non-MPEG-2 ... st->time_base.num*duration_sum[i]/st->info->duration_count*101LL > st->time_base.den*/){ int num = 0; - double best_error= 2*av_q2d(st->time_base); - best_error = best_error*best_error*st->info->duration_count*1000*12*30; - - for (j=1; j<FF_ARRAY_ELEMS(st->info->duration_error); j++) { - double error = st->info->duration_error[j] * get_std_framerate(j); -// if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO) -// av_log(NULL, AV_LOG_ERROR, "%f %f\n", get_std_framerate(j) / 12.0/1001, error); - if(error < best_error){ - best_error= error; - num = get_std_framerate(j); + double best_error= 0.01; + + for (j=1; j<FF_ARRAY_ELEMS(st->info->duration_error[0][0]); 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. @@ -2458,14 +2590,20 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) return ret; } -static AVProgram *find_program_from_stream(AVFormatContext *ic, int s) +AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s) { int i, j; - for (i = 0; i < ic->nb_programs; i++) - for (j = 0; j < ic->programs[i]->nb_stream_indexes; j++) - if (ic->programs[i]->stream_index[j] == s) - return ic->programs[i]; + for (i = 0; i < ic->nb_programs; i++) { + if (ic->programs[i] == last) { + last = NULL; + } else { + if (!last) + for (j = 0; j < ic->programs[i]->nb_stream_indexes; j++) + if (ic->programs[i]->stream_index[j] == s) + return ic->programs[i]; + } + } return NULL; } @@ -2482,7 +2620,7 @@ int av_find_best_stream(AVFormatContext *ic, AVCodec *decoder = NULL, *best_decoder = NULL; if (related_stream >= 0 && wanted_stream_nb < 0) { - AVProgram *p = find_program_from_stream(ic, related_stream); + AVProgram *p = av_find_program_from_stream(ic, NULL, related_stream); if (p) { program = p->stream_index; nb_streams = p->nb_stream_indexes; @@ -2559,13 +2697,13 @@ void avformat_free_context(AVFormatContext *s) av_free_packet(&st->cur_pkt); } av_dict_free(&st->metadata); - av_free(st->index_entries); - av_free(st->codec->extradata); - av_free(st->codec->subtitle_header); - av_free(st->codec); - av_free(st->priv_data); - av_free(st->info); - av_free(st); + av_freep(&st->index_entries); + av_freep(&st->codec->extradata); + av_freep(&st->codec->subtitle_header); + av_freep(&st->codec); + av_freep(&st->priv_data); + av_freep(&st->info); + av_freep(&st); } for(i=s->nb_programs-1; i>=0; i--) { av_dict_free(&s->programs[i]->metadata); @@ -2576,7 +2714,7 @@ void avformat_free_context(AVFormatContext *s) av_freep(&s->priv_data); while(s->nb_chapters--) { av_dict_free(&s->chapters[s->nb_chapters]->metadata); - av_free(s->chapters[s->nb_chapters]); + av_freep(&s->chapters[s->nb_chapters]); } av_freep(&s->chapters); av_dict_free(&s->metadata); @@ -2594,10 +2732,10 @@ void av_close_input_file(AVFormatContext *s) void avformat_close_input(AVFormatContext **ps) { AVFormatContext *s = *ps; - AVIOContext *pb = (s->iformat->flags & AVFMT_NOFILE) || (s->flags & AVFMT_FLAG_CUSTOM_IO) ? + AVIOContext *pb = (s->iformat && (s->iformat->flags & AVFMT_NOFILE)) || (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; flush_packet_queue(s); - if (s->iformat->read_close) + if (s->iformat && (s->iformat->read_close)) s->iformat->read_close(s); avformat_free_context(s); *ps = NULL; @@ -2705,6 +2843,69 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base, /************************************************************/ /* output media file */ +int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, + const char *format, const char *filename) +{ + AVFormatContext *s = avformat_alloc_context(); + int ret = 0; + + *avctx = NULL; + if (!s) + goto nomem; + + if (!oformat) { + if (format) { + oformat = av_guess_format(format, NULL, NULL); + if (!oformat) { + av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format); + ret = AVERROR(EINVAL); + goto error; + } + } else { + oformat = av_guess_format(NULL, filename, NULL); + if (!oformat) { + ret = AVERROR(EINVAL); + av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", + filename); + goto error; + } + } + } + + s->oformat = oformat; + if (s->oformat->priv_data_size > 0) { + s->priv_data = av_mallocz(s->oformat->priv_data_size); + if (!s->priv_data) + goto nomem; + if (s->oformat->priv_class) { + *(const AVClass**)s->priv_data= s->oformat->priv_class; + av_opt_set_defaults(s->priv_data); + } + } else + s->priv_data = NULL; + + if (filename) + av_strlcpy(s->filename, filename, sizeof(s->filename)); + *avctx = s; + return 0; +nomem: + av_log(s, AV_LOG_ERROR, "Out of memory\n"); + ret = AVERROR(ENOMEM); +error: + avformat_free_context(s); + return ret; +} + +#if FF_API_ALLOC_OUTPUT_CONTEXT +AVFormatContext *avformat_alloc_output_context(const char *format, + AVOutputFormat *oformat, const char *filename) +{ + AVFormatContext *avctx; + int ret = avformat_alloc_output_context2(&avctx, oformat, format, filename); + return ret < 0 ? NULL : avctx; +} +#endif + static int validate_codec_tag(AVFormatContext *s, AVStream *st) { const AVCodecTag *avctag; @@ -2748,6 +2949,9 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) av_dict_copy(&tmp, *options, 0); if ((ret = av_opt_set_dict(s, &tmp)) < 0) goto fail; + if (s->priv_data && s->oformat->priv_class && *(const AVClass**)s->priv_data==s->oformat->priv_class && + (ret = av_opt_set_dict(s->priv_data, &tmp)) < 0) + goto fail; // some sanity checks if (s->nb_streams == 0 && !(s->oformat->flags & AVFMT_NOSTREAMS)) { @@ -2781,7 +2985,9 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) ret = AVERROR(EINVAL); goto fail; } - if(av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)){ + if(av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio) + && FFABS(av_q2d(st->sample_aspect_ratio) - av_q2d(st->codec->sample_aspect_ratio)) > 0.004*av_q2d(st->sample_aspect_ratio) + ){ av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between encoder and muxer layer\n"); ret = AVERROR(EINVAL); goto fail; @@ -2880,9 +3086,6 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){ av_dlog(s, "compute_pkt_fields2: pts:%"PRId64" dts:%"PRId64" cur_dts:%"PRId64" b:%d size:%d st:%d\n", pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index); -/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE) - return AVERROR(EINVAL);*/ - /* duration field */ if (pkt->duration == 0) { compute_frame_duration(&num, &den, st, NULL, pkt); @@ -2912,7 +3115,7 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt){ pkt->dts= st->pts_buffer[0]; } - if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){ + if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && ((!(s->oformat->flags & AVFMT_TS_NONSTRICT) && st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)){ av_log(s, AV_LOG_ERROR, "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %"PRId64" >= %"PRId64"\n", st->index, st->cur_dts, pkt->dts); @@ -2970,27 +3173,51 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) return ret; } -void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, +#define CHUNK_START 0x1000 + +int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt, int (*compare)(AVFormatContext *, AVPacket *, AVPacket *)) { AVPacketList **next_point, *this_pktl; + AVStream *st= s->streams[pkt->stream_index]; + int chunked= s->max_chunk_size || s->max_chunk_duration; this_pktl = av_mallocz(sizeof(AVPacketList)); + if (!this_pktl) + return AVERROR(ENOMEM); this_pktl->pkt= *pkt; pkt->destruct= NULL; // do not free original but only the copy av_dup_packet(&this_pktl->pkt); // duplicate the packet if it uses non-alloced memory if(s->streams[pkt->stream_index]->last_in_packet_buffer){ - next_point = &(s->streams[pkt->stream_index]->last_in_packet_buffer->next); - }else + next_point = &(st->last_in_packet_buffer->next); + }else{ next_point = &s->packet_buffer; + } if(*next_point){ + if(chunked){ + uint64_t max= av_rescale_q(s->max_chunk_duration, AV_TIME_BASE_Q, st->time_base); + if( st->interleaver_chunk_size + pkt->size <= s->max_chunk_size-1U + && st->interleaver_chunk_duration + pkt->duration <= max-1U){ + st->interleaver_chunk_size += pkt->size; + st->interleaver_chunk_duration += pkt->duration; + goto next_non_null; + }else{ + st->interleaver_chunk_size = + st->interleaver_chunk_duration = 0; + this_pktl->pkt.flags |= CHUNK_START; + } + } + if(compare(s, &s->packet_buffer_end->pkt, pkt)){ - while(!compare(s, &(*next_point)->pkt, pkt)){ + while( *next_point + && ((chunked && !((*next_point)->pkt.flags&CHUNK_START)) + || !compare(s, &(*next_point)->pkt, pkt))){ next_point= &(*next_point)->next; } - goto next_non_null; + if(*next_point) + goto next_non_null; }else{ next_point = &(s->packet_buffer_end->next); } @@ -3004,6 +3231,7 @@ next_non_null: s->streams[pkt->stream_index]->last_in_packet_buffer= *next_point= this_pktl; + return 0; } static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacket *pkt) @@ -3012,6 +3240,16 @@ static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacke AVStream *st2= s->streams[ next->stream_index]; int comp = av_compare_ts(next->dts, st2->time_base, pkt->dts, st->time_base); + if(s->audio_preload && ((st->codec->codec_type == AVMEDIA_TYPE_AUDIO) != (st2->codec->codec_type == AVMEDIA_TYPE_AUDIO))){ + int64_t ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st ->codec->codec_type == AVMEDIA_TYPE_AUDIO); + int64_t ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st2->codec->codec_type == AVMEDIA_TYPE_AUDIO); + if(ts == ts2){ + ts= ( pkt ->dts* st->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st ->codec->codec_type == AVMEDIA_TYPE_AUDIO)* st->time_base.den)*st2->time_base.den + -( next->dts*st2->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st2->codec->codec_type == AVMEDIA_TYPE_AUDIO)*st2->time_base.den)* st->time_base.den; + ts2=0; + } + comp= (ts>ts2) - (ts<ts2); + } if (comp == 0) return pkt->stream_index < next->stream_index; @@ -3020,17 +3258,46 @@ static int ff_interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVPacke int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush){ AVPacketList *pktl; - int stream_count=0; - int i; + int stream_count=0, noninterleaved_count=0; + int64_t delta_dts_max = 0; + int i, ret; if(pkt){ - ff_interleave_add_packet(s, pkt, ff_interleave_compare_dts); + ret = ff_interleave_add_packet(s, pkt, ff_interleave_compare_dts); + if (ret < 0) + return ret; } - for(i=0; i < s->nb_streams; i++) - stream_count+= !!s->streams[i]->last_in_packet_buffer; + for(i=0; i < s->nb_streams; i++) { + if (s->streams[i]->last_in_packet_buffer) { + ++stream_count; + } else if(s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { + ++noninterleaved_count; + } + } - if(stream_count && (s->nb_streams == stream_count || flush)){ + if (s->nb_streams == stream_count) { + flush = 1; + } else if (!flush){ + for(i=0; i < s->nb_streams; i++) { + if (s->streams[i]->last_in_packet_buffer) { + int64_t delta_dts = + av_rescale_q(s->streams[i]->last_in_packet_buffer->pkt.dts, + s->streams[i]->time_base, + AV_TIME_BASE_Q) - + av_rescale_q(s->packet_buffer->pkt.dts, + s->streams[s->packet_buffer->pkt.stream_index]->time_base, + AV_TIME_BASE_Q); + delta_dts_max= FFMAX(delta_dts_max, delta_dts); + } + } + if(s->nb_streams == stream_count+noninterleaved_count && + delta_dts_max > 20*AV_TIME_BASE) { + av_log(s, AV_LOG_DEBUG, "flushing with %d noninterleaved\n", noninterleaved_count); + flush = 1; + } + } + if(stream_count && flush){ pktl= s->packet_buffer; *out= pktl->pkt; @@ -3098,6 +3365,8 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){ if(ret<0) return ret; + if(s->pb && s->pb->error) + return s->pb->error; } } @@ -3121,11 +3390,15 @@ int av_write_trailer(AVFormatContext *s) if(ret<0) goto fail; + if(s->pb && s->pb->error) + goto fail; } if(s->oformat->write_trailer) ret = s->oformat->write_trailer(s); fail: + if(ret == 0) + ret = s->pb ? s->pb->error : 0; for(i=0;i<s->nb_streams;i++) { av_freep(&s->streams[i]->priv_data); av_freep(&s->streams[i]->index_entries); @@ -3136,6 +3409,15 @@ fail: return ret; } +int av_get_output_timestamp(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall) +{ + if (!s->oformat || !s->oformat->get_output_timestamp) + return AVERROR(ENOSYS); + s->oformat->get_output_timestamp(s, stream, dts, wall); + return 0; +} + void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx) { int i, j; @@ -3178,8 +3460,13 @@ static void dump_metadata(void *ctx, AVDictionary *m, const char *indent) av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent); while((tag=av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) { - if(strcmp("language", tag->key)) - av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tag->value); + if(strcmp("language", tag->key)){ + char tmp[256]; + int i; + av_strlcpy(tmp, tag->value, sizeof(tmp)); + for(i=0; i<strlen(tmp); i++) if(tmp[i]==0xd) tmp[i]=' '; + av_log(ctx, AV_LOG_INFO, "%s %-16s: %s\n", indent, tag->key, tmp); + } } } } @@ -3193,7 +3480,7 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out int g = av_gcd(st->time_base.num, st->time_base.den); AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); avcodec_string(buf, sizeof(buf), st->codec, is_output); - av_log(NULL, AV_LOG_INFO, " Stream #%d.%d", index, i); + av_log(NULL, AV_LOG_INFO, " Stream #%d:%d", index, i); /* the pid is an important information, so we display it */ /* XXX: add a generic system */ if (flags & AVFMT_SHOW_IDS) @@ -3209,7 +3496,7 @@ static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_out st->codec->width*st->sample_aspect_ratio.num, st->codec->height*st->sample_aspect_ratio.den, 1024*1024); - av_log(NULL, AV_LOG_INFO, ", PAR %d:%d DAR %d:%d", + av_log(NULL, AV_LOG_INFO, ", SAR %d:%d DAR %d:%d", st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, display_aspect_ratio.num, display_aspect_ratio.den); } @@ -3458,11 +3745,27 @@ 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) { @@ -3579,6 +3882,14 @@ int ff_hex_to_data(uint8_t *data, const char *p) return len; } +#if FF_API_SET_PTS_INFO +void av_set_pts_info(AVStream *s, int pts_wrap_bits, + unsigned int pts_num, unsigned int pts_den) +{ + avpriv_set_pts_info(s, pts_wrap_bits, pts_num, pts_den); +} +#endif + void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den) { diff --git a/libavformat/vc1test.c b/libavformat/vc1test.c index 3354ad4b8f..d26e78be87 100644 --- a/libavformat/vc1test.c +++ b/libavformat/vc1test.c @@ -2,20 +2,20 @@ * VC1 Test Bitstreams Format Demuxer * Copyright (c) 2006, 2008 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 */ @@ -92,7 +92,7 @@ static int vc1t_read_packet(AVFormatContext *s, int keyframe = 0; uint32_t pts; - if(pb->eof_reached) + if(url_feof(pb)) return AVERROR(EIO); frame_size = avio_rl24(pb); diff --git a/libavformat/vc1testenc.c b/libavformat/vc1testenc.c index a1228d8d70..10b7b64819 100644 --- a/libavformat/vc1testenc.c +++ b/libavformat/vc1testenc.c @@ -2,20 +2,20 @@ * VC-1 test bitstreams format muxer. * Copyright (c) 2008 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 */ #include "avformat.h" @@ -85,7 +85,6 @@ static int vc1test_write_trailer(AVFormatContext *s) AVOutputFormat ff_vc1t_muxer = { .name = "rcv", .long_name = NULL_IF_CONFIG_SMALL("VC-1 test bitstream"), - .mime_type = "", .extensions = "rcv", .priv_data_size = sizeof(RCVContext), .audio_codec = CODEC_ID_NONE, diff --git a/libavformat/version.h b/libavformat/version.h index 6f3b387ddc..8a86c10d26 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -1,20 +1,20 @@ /* * Version macros. * - * 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 */ @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 54 #define LIBAVFORMAT_VERSION_MINOR 0 -#define LIBAVFORMAT_VERSION_MICRO 0 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ @@ -47,6 +47,24 @@ * Those FF_API_* defines are not part of public API. * They 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) +#endif +#ifndef FF_API_ALLOC_OUTPUT_CONTEXT +#define FF_API_ALLOC_OUTPUT_CONTEXT (LIBAVFORMAT_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_FORMAT_PARAMETERS +#define FF_API_FORMAT_PARAMETERS (LIBAVFORMAT_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_NEW_STREAM +#define FF_API_NEW_STREAM (LIBAVFORMAT_VERSION_MAJOR < 55) +#endif +#ifndef FF_API_SET_PTS_INFO +#define FF_API_SET_PTS_INFO (LIBAVFORMAT_VERSION_MAJOR < 55) +#endif #ifndef FF_API_CLOSE_INPUT_FILE #define FF_API_CLOSE_INPUT_FILE (LIBAVFORMAT_VERSION_MAJOR < 55) #endif diff --git a/libavformat/voc.c b/libavformat/voc.c index 314623ee74..53e02f9464 100644 --- a/libavformat/voc.c +++ b/libavformat/voc.c @@ -2,20 +2,20 @@ * Creative Voice File common data. * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/voc.h b/libavformat/voc.h index abd8fdbfff..3f995ad31f 100644 --- a/libavformat/voc.h +++ b/libavformat/voc.h @@ -2,20 +2,20 @@ * Creative Voice File demuxer. * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/vocdec.c b/libavformat/vocdec.c index 6b3438f758..37fd524b7f 100644 --- a/libavformat/vocdec.c +++ b/libavformat/vocdec.c @@ -2,20 +2,20 @@ * Creative Voice File demuxer. * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> * - * 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 */ @@ -142,7 +142,7 @@ voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) } } - dec->bit_rate = dec->sample_rate * dec->bits_per_coded_sample; + dec->bit_rate = dec->sample_rate * dec->channels * dec->bits_per_coded_sample; if (max_size <= 0) max_size = 2048; diff --git a/libavformat/vocenc.c b/libavformat/vocenc.c index d0986bb02b..0a9f24bdc2 100644 --- a/libavformat/vocenc.c +++ b/libavformat/vocenc.c @@ -2,20 +2,20 @@ * Creative Voice File muxer. * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> * - * 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/libavformat/vorbiscomment.c b/libavformat/vorbiscomment.c index 56936d7666..9b38e6a791 100644 --- a/libavformat/vorbiscomment.c +++ b/libavformat/vorbiscomment.c @@ -2,20 +2,20 @@ * VorbisComment writer * Copyright (c) 2009 James Darnley * - * 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/libavformat/vorbiscomment.h b/libavformat/vorbiscomment.h index 95e1a5676f..4e631e3553 100644 --- a/libavformat/vorbiscomment.h +++ b/libavformat/vorbiscomment.h @@ -2,20 +2,20 @@ * VorbisComment writer * Copyright (c) 2009 James Darnley * - * 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/libavformat/vqf.c b/libavformat/vqf.c index 08ffa734c1..8cd69232ce 100644 --- a/libavformat/vqf.c +++ b/libavformat/vqf.c @@ -2,20 +2,20 @@ * VQF demuxer * Copyright (c) 2009 Vitor Sessak * - * 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/libavformat/wav.c b/libavformat/wav.c index 7b3a0f44f3..610c792e85 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -6,20 +6,20 @@ * RF64 demuxer * Copyright (c) 2009 Daniel Verkamp * - * 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 */ @@ -45,6 +45,14 @@ typedef struct { int last_duration; int w64; int write_bext; + int64_t smv_data_ofs; + int smv_block_size; + int smv_frames_per_jpeg; + int smv_block; + int smv_last_stream; + int smv_eof; + int audio_eof; + int ignore_length; } WAVContext; #if CONFIG_WAV_MUXER @@ -237,7 +245,7 @@ static int64_t find_tag(AVIOContext *pb, uint32_t tag1) int64_t size; for (;;) { - if (pb->eof_reached) + if (url_feof(pb)) return -1; size = next_tag(pb, &tag); if (tag == tag1) @@ -338,7 +346,7 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) } else { /* extended UMID */ snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 - "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]); } @@ -386,11 +394,13 @@ static int wav_read_header(AVFormatContext *s) int rf64; uint32_t tag, list_type; AVIOContext *pb = s->pb; - AVStream *st; + AVStream *st = NULL; WAVContext *wav = s->priv_data; int ret, got_fmt = 0; int64_t next_tag_ofs, data_ofs = -1; + wav->smv_data_ofs = -1; + /* check RIFF header */ tag = avio_rl32(pb); @@ -406,7 +416,7 @@ static int wav_read_header(AVFormatContext *s) if (avio_rl32(pb) != MKTAG('d', 's', '6', '4')) return -1; size = avio_rl32(pb); - if (size < 16) + if (size < 24) return -1; avio_rl64(pb); /* RIFF size */ data_size = avio_rl64(pb); @@ -417,20 +427,22 @@ static int wav_read_header(AVFormatContext *s) data_size, sample_count); return AVERROR_INVALIDDATA; } - avio_skip(pb, size - 16); /* skip rest of ds64 chunk */ + avio_skip(pb, size - 24); /* skip rest of ds64 chunk */ + } for (;;) { + AVStream *vst; size = next_tag(pb, &tag); next_tag_ofs = avio_tell(pb) + size; - if (pb->eof_reached) + if (url_feof(pb)) break; switch (tag) { case MKTAG('f', 'm', 't', ' '): /* only parse the first 'fmt ' tag found */ - if (!got_fmt && (ret = wav_parse_fmt_tag(s, size, &st) < 0)) { + if (!got_fmt && (ret = wav_parse_fmt_tag(s, size, &st)) < 0) { return ret; } else if (got_fmt) av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n"); @@ -466,10 +478,36 @@ static int wav_read_header(AVFormatContext *s) if ((ret = wav_parse_bext_tag(s, size)) < 0) return ret; break; + case MKTAG('S','M','V','0'): + // SMV file, a wav file with video appended. + if (size != MKTAG('0','2','0','0')) { + av_log(s, AV_LOG_ERROR, "Unknown SMV version found\n"); + goto break_loop; + } + av_log(s, AV_LOG_DEBUG, "Found SMV data\n"); + 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 = CODEC_ID_MJPEG; + vst->codec->width = avio_rl24(pb); + vst->codec->height = avio_rl24(pb); + size = avio_rl24(pb); + wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3; + avio_rl24(pb); + wav->smv_block_size = avio_rl24(pb); + avpriv_set_pts_info(vst, 32, 1, avio_rl24(pb)); + vst->duration = avio_rl24(pb); + avio_rl24(pb); + avio_rl24(pb); + wav->smv_frames_per_jpeg = avio_rl24(pb); + goto break_loop; case MKTAG('L', 'I', 'S', 'T'): list_type = avio_rl32(pb); - if (size <= 4) { - av_log(s, AV_LOG_ERROR, "too short LIST"); + if (size < 4) { + av_log(s, AV_LOG_ERROR, "too short LIST tag\n"); return AVERROR_INVALIDDATA; } switch (list_type) { @@ -513,7 +551,7 @@ static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16]) uint8_t guid[16]; int64_t size; - while (!pb->eof_reached) { + while (!url_feof(pb)) { avio_read(pb, guid, 16); size = avio_rl64(pb); if (size <= 24) @@ -538,16 +576,61 @@ static int wav_read_packet(AVFormatContext *s, AVStream *st; WAVContext *wav = s->priv_data; + 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; + 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; + } + wav->smv_last_stream = !wav->smv_last_stream; + wav->smv_last_stream |= wav->audio_eof; + wav->smv_last_stream &= !wav->smv_eof; + if (wav->smv_last_stream) { + uint64_t old_pos = avio_tell(s->pb); + uint64_t new_pos = wav->smv_data_ofs + + wav->smv_block * wav->smv_block_size; + if (avio_seek(s->pb, new_pos, SEEK_SET) < 0) { + ret = AVERROR_EOF; + goto smv_out; + } + size = avio_rl24(s->pb); + ret = av_get_packet(s->pb, pkt, size); + if (ret < 0) + goto smv_out; + pkt->pos -= 3; + pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg; + wav->smv_block++; + pkt->stream_index = 1; +smv_out: + avio_seek(s->pb, old_pos, SEEK_SET); + if (ret == AVERROR_EOF) { + wav->smv_eof = 1; + goto smv_retry; + } + return ret; + } + } + st = s->streams[0]; left = wav->data_end - avio_tell(s->pb); + if (wav->ignore_length) + left= INT_MAX; if (left <= 0){ if (CONFIG_W64_DEMUXER && wav->w64) left = find_guid(s->pb, guid_data) - 24; else left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a')); - if (left < 0) + 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; } @@ -569,7 +652,18 @@ static int wav_read_packet(AVFormatContext *s, static int wav_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { + WAVContext *wav = s->priv_data; AVStream *st; + wav->smv_eof = 0; + wav->audio_eof = 0; + if (wav->smv_data_ofs > 0) { + int64_t smv_timestamp = timestamp; + if (stream_index == 0) + 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; + } st = s->streams[0]; switch (st->codec->codec_id) { @@ -585,6 +679,19 @@ static int wav_read_seek(AVFormatContext *s, return pcm_read_seek(s, stream_index, timestamp, flags); } +#define OFFSET(x) offsetof(WAVContext, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM +static const AVOption demux_options[] = { + { "ignore_length", "Ignore length", OFFSET(ignore_length), AV_OPT_TYPE_INT, { 0 }, 0, 1, DEC }, + { NULL }, +}; + +static const AVClass wav_demuxer_class = { + .class_name = "WAV demuxer", + .item_name = av_default_item_name, + .option = demux_options, + .version = LIBAVUTIL_VERSION_INT, +}; AVInputFormat ff_wav_demuxer = { .name = "wav", .long_name = NULL_IF_CONFIG_SMALL("WAV format"), @@ -595,6 +702,7 @@ AVInputFormat ff_wav_demuxer = { .read_seek = wav_read_seek, .flags= AVFMT_GENERIC_INDEX, .codec_tag= (const AVCodecTag* const []){ff_codec_wav_tags, 0}, + .priv_class = &wav_demuxer_class, }; #endif /* CONFIG_WAV_DEMUXER */ diff --git a/libavformat/wc3movie.c b/libavformat/wc3movie.c index 05e25fc44d..d79d7687f4 100644 --- a/libavformat/wc3movie.c +++ b/libavformat/wc3movie.c @@ -2,20 +2,20 @@ * Wing Commander III Movie (.mve) File Demuxer * Copyright (c) 2003 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 */ @@ -157,7 +157,7 @@ static int wc3_read_header(AVFormatContext *s) fourcc_tag = avio_rl32(pb); /* chunk sizes are 16-bit aligned */ size = (avio_rb32(pb) + 1) & (~1); - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); } while (fourcc_tag != BRCH_TAG); @@ -208,7 +208,7 @@ static int wc3_read_packet(AVFormatContext *s, fourcc_tag = avio_rl32(pb); /* chunk sizes are 16-bit aligned */ size = (avio_rb32(pb) + 1) & (~1); - if (pb->eof_reached) + if (url_feof(pb)) return AVERROR(EIO); switch (fourcc_tag) { diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c index c4e19a9981..47493382c4 100644 --- a/libavformat/westwood_vqa.c +++ b/libavformat/westwood_vqa.c @@ -2,20 +2,20 @@ * Westwood Studios VQA Format Demuxer * Copyright (c) 2003 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 */ @@ -166,10 +166,8 @@ static int wsvqa_read_header(AVFormatContext *s) /* there are 0 or more chunks before the FINF chunk; iterate until * FINF has been skipped and the file will be ready to be demuxed */ do { - if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE) { - av_free(st->codec->extradata); + if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE) return AVERROR(EIO); - } chunk_tag = AV_RB32(&scratch[0]); chunk_size = AV_RB32(&scratch[4]); @@ -212,6 +210,7 @@ static int wsvqa_read_packet(AVFormatContext *s, while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) { chunk_type = AV_RB32(&preamble[0]); chunk_size = AV_RB32(&preamble[4]); + skip_byte = chunk_size & 0x01; if ((chunk_type == SND2_TAG || chunk_type == SND1_TAG) && wsvqa->audio_channels == 0) { @@ -221,13 +220,9 @@ static int wsvqa_read_packet(AVFormatContext *s, if ((chunk_type == SND1_TAG) || (chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) { - if (av_new_packet(pkt, chunk_size)) + ret= av_get_packet(pb, pkt, chunk_size); + if (ret<0) return AVERROR(EIO); - ret = avio_read(pb, pkt->data, chunk_size); - if (ret != chunk_size) { - av_free_packet(pkt); - return AVERROR(EIO); - } if (chunk_type == SND2_TAG) { pkt->stream_index = wsvqa->audio_stream_index; diff --git a/libavformat/wtv.c b/libavformat/wtv.c index 07549b2cc5..7a29309e58 100644 --- a/libavformat/wtv.c +++ b/libavformat/wtv.c @@ -1,1113 +1,76 @@ /* - * Windows Television (WTV) demuxer + * Windows Television (WTV) * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org> * - * 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 */ -/** - * @file - * Windows Television (WTV) demuxer - * @author Peter Ross <pross@xvid.org> - */ - -#include "libavutil/intreadwrite.h" -#include "libavutil/intfloat.h" -#include "libavutil/dict.h" -#include "avformat.h" -#include "internal.h" -#include "riff.h" -#include "asf.h" -#include "mpegts.h" - -/* Macros for formating GUIDs */ -#define PRI_GUID \ - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" -#define 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] - -#define PRI_PRETTY_GUID \ - "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x" -#define ARG_PRETTY_GUID(g) \ - AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15] -#define LEN_PRETTY_GUID 34 - -/* - * - * File system routines - * - */ - -#define WTV_SECTOR_BITS 12 -#define WTV_SECTOR_SIZE (1 << WTV_SECTOR_BITS) -#define WTV_BIGSECTOR_BITS 18 - -typedef struct { - 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 error; - int64_t position; - int64_t length; -} WtvFile; - -/** - * @return bytes read, 0 on end of file, or <0 on error - */ -static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) -{ - WtvFile *wf = opaque; - AVIOContext *pb = wf->pb_filesystem; - int nread = 0; - - if (wf->error || pb->error) - return -1; - if (wf->position >= wf->length || pb->eof_reached) - return 0; - - buf_size = FFMIN(buf_size, wf->length - wf->position); - while(nread < buf_size) { - int n; - int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1)); - int read_request = FFMIN(buf_size - nread, remaining_in_sector); - - n = avio_read(pb, buf, read_request); - if (n <= 0) - break; - nread += n; - buf += n; - wf->position += n; - if (n == remaining_in_sector) { - 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)) { - wf->error = 1; - break; - } - } - } - return nread; -} +#include "wtv.h" -/** - * @return position (or file length) - */ -static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence) -{ - WtvFile *wf = opaque; - AVIOContext *pb = wf->pb_filesystem; - - if (whence == AVSEEK_SIZE) - return wf->length; - else if (whence == SEEK_CUR) - offset = wf->position + offset; - else if (whence == SEEK_END) - 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; - wf->position = offset; - return offset; -} - -/** - * read non-zero integers (le32) from input stream - * @param pb - * @param[out] data destination - * @param count maximum number of integers to read - * @return total number of integers read - */ -static int read_ints(AVIOContext *pb, uint32_t *data, int count) -{ - int i, total = 0; - for (i = 0; i < count; i++) { - if ((data[total] = avio_rl32(pb))) - total++; - } - return total; -} - -/** - * Open file - * @param first_sector First sector - * @param length Length of file (bytes) - * @param depth File allocation table depth - * @return NULL on error - */ -static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s) -{ - AVIOContext *pb; - WtvFile *wf; - uint8_t *buffer; - - if (avio_seek(s->pb, first_sector << WTV_SECTOR_BITS, SEEK_SET) < 0) - return NULL; - - wf = av_mallocz(sizeof(WtvFile)); - if (!wf) - return NULL; - - if (depth == 0) { - wf->sectors = av_malloc(sizeof(uint32_t)); - if (!wf->sectors) { - av_free(wf); - return NULL; - } - wf->sectors[0] = first_sector; - wf->nb_sectors = 1; - wf->sector_bits = WTV_SECTOR_BITS; - } else if (depth == 1) { - wf->sectors = av_malloc(WTV_SECTOR_SIZE); - if (!wf->sectors) { - av_free(wf); - return NULL; - } - wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4); - wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS; - } else if (depth == 2) { - uint32_t sectors1[WTV_SECTOR_SIZE / 4]; - int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4); - int i; - - wf->sectors = av_malloc(nb_sectors1 << 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) - break; - wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4); - } - wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS; - } else { - av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth); - av_free(wf); - return NULL; - } - - if (!wf->nb_sectors) { - av_free(wf->sectors); - av_free(wf); - return NULL; - } - - /* check length */ - length &= 0xFFFFFFFFFFFF; - if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) { - av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits); - length = (int64_t)wf->nb_sectors << wf->sector_bits; - } - wf->length = length; - - /* seek to intial sector */ - wf->position = 0; - if (avio_seek(s->pb, (int64_t)wf->sectors[0] << WTV_SECTOR_BITS, SEEK_SET) < 0) { - av_free(wf->sectors); - av_free(wf); - return NULL; - } - - wf->pb_filesystem = s->pb; - buffer = av_malloc(1 << wf->sector_bits); - if (!buffer) { - av_free(wf->sectors); - av_free(wf); - return NULL; - } - - pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf, - wtvfile_read_packet, NULL, wtvfile_seek); - if (!pb) { - av_free(buffer); - av_free(wf->sectors); - av_free(wf); - } - return pb; -} - -static const ff_asf_guid dir_entry_guid = +/* 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}; - -/** - * Open file using filename - * @param[in] buf directory buffer - * @param buf_size directory buffer size - * @param[in] filename - * @param filename_size size of filename - * @return NULL on error - */ -static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size) -{ - const uint8_t *buf_end = buf + buf_size; - - while(buf + 48 <= buf_end) { - int dir_length, name_size, first_sector, depth; - uint64_t file_length; - const uint8_t *name; - if (ff_guidcmp(buf, dir_entry_guid)) { - av_log(s, AV_LOG_ERROR, "unknown guid "PRI_GUID", expected dir_entry_guid; " - "remaining directory entries ignored\n", ARG_GUID(buf)); - break; - } - dir_length = AV_RL16(buf + 16); - file_length = AV_RL64(buf + 24); - name_size = 2 * AV_RL32(buf + 32); - if (buf + 48 + name_size > buf_end) { - av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n"); - break; - } - first_sector = AV_RL32(buf + 40 + name_size); - depth = AV_RL32(buf + 44 + name_size); - - /* compare file name; test optional null terminator */ - name = buf + 40; - if (name_size >= filename_size && - !memcmp(name, filename, filename_size) && - (name_size < filename_size + 2 || !AV_RN16(name + filename_size))) - return wtvfile_open_sector(first_sector, file_length, depth, s); - - buf += dir_length; - } - return 0; -} - -#define wtvfile_open(s, buf, buf_size, filename) \ - wtvfile_open2(s, buf, buf_size, filename, sizeof(filename)) - -/** - * Close file opened with wtvfile_open_sector(), or wtv_open() - */ -static void wtvfile_close(AVIOContext *pb) -{ - WtvFile *wf = pb->opaque; - av_free(wf->sectors); - av_free(wf); - av_free(pb->buffer); - av_free(pb); -} - -/* - * - * Main demuxer - * - */ - -typedef struct { - int seen_data; -} WtvStream; - -typedef struct { - 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 */ - - /* maintain private seek index, as the AVIndexEntry->pos is relative to the - start of the 'timeline' file, not the file system (AVFormatContext->pb) */ - AVIndexEntry *index_entries; - int nb_index_entries; - unsigned int index_entries_allocated_size; -} WtvContext; - -typedef struct { - enum CodecID id; - ff_asf_guid guid; -} AVCodecGuid; - -static enum CodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) -{ - int i; - for (i = 0; guids[i].id != CODEC_ID_NONE; i++) { - if (!ff_guidcmp(guids[i].guid, guid)) - return guids[i].id; - } - return CODEC_ID_NONE; -} - -/* WTV GUIDs */ -static const ff_asf_guid wtv_guid = +const ff_asf_guid ff_wtv_guid = {0xB7,0xD8,0x00,0x20,0x37,0x49,0xDA,0x11,0xA6,0x4E,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -static const ff_asf_guid metadata_guid = - {0x5A,0xFE,0xD7,0x6D,0xC8,0x1D,0x8F,0x4A,0x99,0x22,0xFA,0xB1,0x1C,0x38,0x14,0x53}; -static const ff_asf_guid timestamp_guid = +const ff_asf_guid ff_timestamp_guid = {0x5B,0x05,0xE6,0x1B,0x97,0xA9,0x49,0x43,0x88,0x17,0x1A,0x65,0x5A,0x29,0x8A,0x97}; -static const ff_asf_guid data_guid = +const ff_asf_guid ff_data_guid = {0x95,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -static const ff_asf_guid stream_guid = +const ff_asf_guid ff_stream_guid = {0xED,0xA4,0x13,0x23,0x2D,0xBF,0x4F,0x45,0xAD,0x8A,0xD9,0x5B,0xA7,0xF9,0x1F,0xEE}; -static const ff_asf_guid stream2_guid = - {0xA2,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; -static const ff_asf_guid EVENTID_SubtitleSpanningEvent = - {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A}; -static const ff_asf_guid EVENTID_LanguageSpanningEvent = - {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95}; -static const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent = - {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E}; -static const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent = - {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24}; -static const ff_asf_guid EVENTID_CSDescriptorSpanningEvent = - {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66}; -static const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent = - {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B}; -static const ff_asf_guid EVENTID_StreamIDSpanningEvent = - {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE}; -static const ff_asf_guid EVENTID_TeletextSpanningEvent = - {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3}; -static const ff_asf_guid EVENTID_AudioTypeSpanningEvent = - {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3}; - -/* Windows media GUIDs */ +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}; -#define MEDIASUBTYPE_BASE_GUID \ - 0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71 +/* 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 _ -/* Media types */ -static const ff_asf_guid mediatype_audio = - {'a','u','d','s',MEDIASUBTYPE_BASE_GUID}; -static const ff_asf_guid mediatype_video = - {'v','i','d','s',MEDIASUBTYPE_BASE_GUID}; -static const ff_asf_guid mediasubtype_mpeg1payload = - {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}; -static const ff_asf_guid mediatype_mpeg2_sections = - {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5}; -static const ff_asf_guid mediatype_mpeg2_pes = - {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}; -static const ff_asf_guid mediatype_mstvcaption = - {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1}; +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 */ -static const ff_asf_guid mediasubtype_cpfilters_processed = +const ff_asf_guid ff_mediasubtype_cpfilters_processed = {0x28,0xBD,0xAD,0x46,0xD0,0x6F,0x96,0x47,0x93,0xB2,0x15,0x5C,0x51,0xDC,0x04,0x8D}; -static const ff_asf_guid mediasubtype_dvb_subtitle = - {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F}; -static const ff_asf_guid mediasubtype_teletext = - {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA}; -static const ff_asf_guid mediasubtype_dtvccdata = - {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A}; -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_cpfilters_processed = +const ff_asf_guid ff_format_cpfilters_processed = {0x6F,0xB3,0x39,0x67,0x5F,0x1D,0xC2,0x4A,0x81,0x92,0x28,0xBB,0x0E,0x73,0xD1,0x6A}; -static const ff_asf_guid format_waveformatex = +const ff_asf_guid ff_format_waveformatex = {0x81,0x9F,0x58,0x05,0x56,0xC3,0xCE,0x11,0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A}; -static const ff_asf_guid format_videoinfo2 = - {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA}; -static const ff_asf_guid format_mpeg2_video = +const ff_asf_guid ff_format_mpeg2_video = {0xE3,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}; -static const ff_asf_guid format_none = - {0xD6,0x17,0x64,0x0F,0x18,0xC3,0xD0,0x11,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96}; -static const AVCodecGuid video_guids[] = { +const AVCodecGuid ff_video_guids[] = { {CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, {CODEC_ID_NONE} }; - -static const AVCodecGuid audio_guids[] = { - {CODEC_ID_AC3, {0x2C,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, - {CODEC_ID_EAC3, {0xAF,0x87,0xFB,0xA7,0x02,0x2D,0xFB,0x42,0xA4,0xD4,0x05,0xCD,0x93,0x84,0x3B,0xDD}}, - {CODEC_ID_MP2, {0x2B,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}}, - {CODEC_ID_NONE} -}; - -static int read_probe(AVProbeData *p) -{ - return ff_guidcmp(p->buf, wtv_guid) ? 0 : AVPROBE_SCORE_MAX; -} - -/** - * Convert win32 FILETIME to ISO-8601 string - */ -static void filetime_to_iso8601(char *buf, int buf_size, int64_t value) -{ - time_t t = (value / 10000000LL) - 11644473600LL; - strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t)); -} - -/** - * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string - */ -static void crazytime_to_iso8601(char *buf, int buf_size, int64_t value) -{ - time_t t = (value / 10000000LL) - 719162LL*86400LL; - strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t)); -} - -/** - * Convert OLE DATE to ISO-8601 string - */ -static void oledate_to_iso8601(char *buf, int buf_size, int64_t value) -{ - time_t t = 631112400LL + 86400*av_int2double(value); - strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t)); -} - -static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length) -{ - char mime[1024]; - char description[1024]; - unsigned int filesize; - AVStream *st; - int64_t pos = avio_tell(pb); - - avio_get_str16le(pb, INT_MAX, mime, sizeof(mime)); - if (strcmp(mime, "image/jpeg")) - goto done; - - avio_r8(pb); - avio_get_str16le(pb, INT_MAX, description, sizeof(description)); - filesize = avio_rl32(pb); - if (!filesize) - goto done; - - st = avformat_new_stream(s, NULL); - if (!st) - goto done; - av_dict_set(&st->metadata, "title", description, 0); - st->codec->codec_id = CODEC_ID_MJPEG; - st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; - st->codec->extradata = av_mallocz(filesize); - if (!st->codec->extradata) - goto done; - st->codec->extradata_size = filesize; - avio_read(pb, st->codec->extradata, filesize); -done: - avio_seek(pb, pos + length, SEEK_SET); -} - -static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length) -{ - int buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1; - char *buf = av_malloc(buf_size); - if (!buf) - return; - - if (type == 0 && length == 4) { - snprintf(buf, buf_size, "%"PRIi32, avio_rl32(pb)); - } else if (type == 1) { - avio_get_str16le(pb, length, buf, buf_size); - if (!strlen(buf)) { - av_free(buf); - return; - } - } else if (type == 3 && length == 4) { - strcpy(buf, avio_rl32(pb) ? "true" : "false"); - } else if (type == 4 && length == 8) { - int64_t num = avio_rl64(pb); - if (!strcmp(key, "WM/EncodingTime") || - !strcmp(key, "WM/MediaOriginalBroadcastDateTime")) - filetime_to_iso8601(buf, buf_size, num); - else if (!strcmp(key, "WM/WMRVEncodeTime") || - !strcmp(key, "WM/WMRVEndTime")) - crazytime_to_iso8601(buf, buf_size, num); - else if (!strcmp(key, "WM/WMRVExpirationDate")) - oledate_to_iso8601(buf, buf_size, num); - else if (!strcmp(key, "WM/WMRVBitrate")) - snprintf(buf, buf_size, "%f", av_int2double(num)); - else - snprintf(buf, buf_size, "%"PRIi64, num); - } else if (type == 5 && length == 2) { - snprintf(buf, buf_size, "%"PRIi16, avio_rl16(pb)); - } else if (type == 6 && length == 16) { - ff_asf_guid guid; - avio_read(pb, guid, 16); - snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid)); - } else if (type == 2 && !strcmp(key, "WM/Picture")) { - get_attachment(s, pb, length); - av_freep(&buf); - return; - } else { - av_freep(&buf); - av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length); - avio_skip(pb, length); - return; - } - - av_dict_set(&s->metadata, key, buf, 0); - av_freep(&buf); -} - -/** - * Parse metadata entries - */ -static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb) -{ - ff_asf_guid guid; - int length, type; - while(!pb->eof_reached) { - char key[1024]; - ff_get_guid(pb, &guid); - type = avio_rl32(pb); - length = avio_rl32(pb); - if (!length) - break; - if (ff_guidcmp(&guid, metadata_guid)) { - av_log(s, AV_LOG_WARNING, "unknown guid "PRI_GUID", expected metadata_guid; " - "remaining metadata entries ignored\n", ARG_GUID(guid)); - break; - } - avio_get_str16le(pb, INT_MAX, key, sizeof(key)); - get_tag(s, pb, key, type, length); - } - - ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv); -} - -/** - * parse VIDEOINFOHEADER2 structure - * @return bytes consumed - */ -static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st) -{ - WtvContext *wtv = s->priv_data; - AVIOContext *pb = wtv->pb; - - avio_skip(pb, 72); // picture aspect ratio is unreliable - ff_get_bmp_header(pb, st); - - return 72 + 40; -} - -/** - * Parse MPEG1WAVEFORMATEX extradata structure - */ -static void parse_mpeg1waveformatex(AVStream *st) -{ - /* fwHeadLayer */ - switch (AV_RL16(st->codec->extradata)) { - case 0x0001 : st->codec->codec_id = CODEC_ID_MP1; break; - case 0x0002 : st->codec->codec_id = CODEC_ID_MP2; break; - case 0x0004 : st->codec->codec_id = CODEC_ID_MP3; break; - } - - st->codec->bit_rate = AV_RL32(st->codec->extradata + 2); /* dwHeadBitrate */ - - /* dwHeadMode */ - switch (AV_RL16(st->codec->extradata + 6)) { - case 1 : case 2 : case 4 : st->codec->channels = 2; break; - case 8 : st->codec->channels = 1; break; - } -} - -/** - * Initialise stream - * @param st Stream to initialise, or NULL to create and initialise new stream - * @return NULL on error - */ -static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type) -{ - if (st) { - if (st->codec->extradata) { - av_freep(&st->codec->extradata); - st->codec->extradata_size = 0; - } - } else { - WtvStream *wst = av_mallocz(sizeof(WtvStream)); - if (!wst) - return NULL; - st = avformat_new_stream(s, NULL); - if (!st) - return NULL; - st->id = sid; - st->priv_data = wst; - } - st->codec->codec_type = codec_type; - st->need_parsing = AVSTREAM_PARSE_FULL; - avpriv_set_pts_info(st, 64, 1, 10000000); - return st; -} - -/** - * parse Media Type structure and populate stream - * @param st Stream, or NULL to create new stream - * @param mediatype Mediatype GUID - * @param subtype Subtype GUID - * @param formattype Format GUID - * @param size Size of format buffer - * @return NULL on error - */ -static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, - ff_asf_guid mediatype, ff_asf_guid subtype, - ff_asf_guid formattype, int size) -{ - WtvContext *wtv = s->priv_data; - AVIOContext *pb = wtv->pb; - if (!ff_guidcmp(subtype, mediasubtype_cpfilters_processed) && - !ff_guidcmp(formattype, format_cpfilters_processed)) { - ff_asf_guid actual_subtype; - ff_asf_guid actual_formattype; - - if (size < 32) { - av_log(s, AV_LOG_WARNING, "format buffer size underflow\n"); - avio_skip(pb, size); - return NULL; - } - - avio_skip(pb, size - 32); - ff_get_guid(pb, &actual_subtype); - ff_get_guid(pb, &actual_formattype); - avio_seek(pb, -size, SEEK_CUR); - - st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32); - avio_skip(pb, 32); - return st; - } else if (!ff_guidcmp(mediatype, mediatype_audio)) { - st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO); - if (!st) - return NULL; - if (!ff_guidcmp(formattype, format_waveformatex)) { - int ret = ff_get_wav_header(pb, st->codec, size); - if (ret < 0) - return NULL; - } else { - if (ff_guidcmp(formattype, format_none)) - av_log(s, AV_LOG_WARNING, "unknown formattype:"PRI_GUID"\n", ARG_GUID(formattype)); - avio_skip(pb, size); - } - - if (!memcmp(subtype + 4, (const uint8_t[]){MEDIASUBTYPE_BASE_GUID}, 12)) { - st->codec->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codec->bits_per_coded_sample); - } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) { - if (st->codec->extradata && st->codec->extradata_size >= 22) - parse_mpeg1waveformatex(st); - else - av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n"); - } else { - st->codec->codec_id = ff_codec_guid_get_id(audio_guids, subtype); - if (st->codec->codec_id == CODEC_ID_NONE) - av_log(s, AV_LOG_WARNING, "unknown subtype:"PRI_GUID"\n", ARG_GUID(subtype)); - } - return st; - } else if (!ff_guidcmp(mediatype, mediatype_video)) { - st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO); - if (!st) - return NULL; - if (!ff_guidcmp(formattype, format_videoinfo2)) { - int consumed = parse_videoinfoheader2(s, st); - avio_skip(pb, FFMAX(size - consumed, 0)); - } else if (!ff_guidcmp(formattype, format_mpeg2_video)) { - int consumed = parse_videoinfoheader2(s, st); - avio_skip(pb, FFMAX(size - consumed, 0)); - } else { - if (ff_guidcmp(formattype, format_none)) - av_log(s, AV_LOG_WARNING, "unknown formattype:"PRI_GUID"\n", ARG_GUID(formattype)); - avio_skip(pb, size); - } - - if (!memcmp(subtype + 4, (const uint8_t[]){MEDIASUBTYPE_BASE_GUID}, 12)) { - st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype)); - } else { - st->codec->codec_id = ff_codec_guid_get_id(video_guids, subtype); - } - if (st->codec->codec_id == CODEC_ID_NONE) - av_log(s, AV_LOG_WARNING, "unknown subtype:"PRI_GUID"\n", ARG_GUID(subtype)); - return st; - } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) && - !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) { - st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE); - if (!st) - return NULL; - if (ff_guidcmp(formattype, format_none)) - av_log(s, AV_LOG_WARNING, "unknown formattype:"PRI_GUID"\n", ARG_GUID(formattype)); - avio_skip(pb, size); - st->codec->codec_id = CODEC_ID_DVB_SUBTITLE; - return st; - } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) && - (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) { - st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE); - if (!st) - return NULL; - if (ff_guidcmp(formattype, format_none)) - av_log(s, AV_LOG_WARNING, "unknown formattype:"PRI_GUID"\n", ARG_GUID(formattype)); - avio_skip(pb, size); - st->codec->codec_id = CODEC_ID_DVB_TELETEXT; - return st; - } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) && - !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) { - if (ff_guidcmp(formattype, format_none)) - av_log(s, AV_LOG_WARNING, "unknown formattype:"PRI_GUID"\n", ARG_GUID(formattype)); - avio_skip(pb, size); - return NULL; - } - - av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"PRI_GUID - ", subtype:"PRI_GUID", formattype:"PRI_GUID"\n", - ARG_GUID(mediatype), ARG_GUID(subtype), ARG_GUID(formattype)); - avio_skip(pb, size); - return NULL; -} - -enum { - SEEK_TO_DATA = 0, - SEEK_TO_PTS, -}; - -/** - * Parse WTV chunks - * @param mode SEEK_TO_DATA or SEEK_TO_PTS - * @param seekts timestamp - * @param[out] len_ptr Length of data chunk - * @return stream index of data chunk, or <0 on error - */ -static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr) -{ - WtvContext *wtv = s->priv_data; - AVIOContext *pb = wtv->pb; - while (!pb->eof_reached) { - ff_asf_guid g; - int len, sid, consumed; - - ff_get_guid(pb, &g); - len = avio_rl32(pb); - if (len < 32) - break; - sid = avio_rl32(pb) & 0x7FFF; - avio_skip(pb, 8); - consumed = 32; - - if (!ff_guidcmp(g, stream_guid)) { - if (ff_find_stream_index(s, sid) < 0) { - ff_asf_guid mediatype, subtype, formattype; - int size; - avio_skip(pb, 28); - ff_get_guid(pb, &mediatype); - ff_get_guid(pb, &subtype); - avio_skip(pb, 12); - ff_get_guid(pb, &formattype); - size = avio_rl32(pb); - parse_media_type(s, 0, sid, mediatype, subtype, formattype, size); - consumed += 92 + size; - } - } else if (!ff_guidcmp(g, stream2_guid)) { - int stream_index = ff_find_stream_index(s, sid); - if (stream_index >= 0 && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) { - ff_asf_guid mediatype, subtype, formattype; - int size; - avio_skip(pb, 12); - ff_get_guid(pb, &mediatype); - ff_get_guid(pb, &subtype); - avio_skip(pb, 12); - ff_get_guid(pb, &formattype); - size = avio_rl32(pb); - parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size); - consumed += 76 + size; - } - } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) || - !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) || - !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) || - !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) || - !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) || - !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) { - int stream_index = ff_find_stream_index(s, sid); - if (stream_index >= 0) { - AVStream *st = s->streams[stream_index]; - uint8_t buf[258]; - const uint8_t *pbuf = buf; - int buf_size; - - avio_skip(pb, 8); - consumed += 8; - if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) || - !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) { - avio_skip(pb, 6); - consumed += 6; - } - - buf_size = FFMIN(len - consumed, sizeof(buf)); - avio_read(pb, buf, buf_size); - consumed += buf_size; - ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL); - } - } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) { - int stream_index = ff_find_stream_index(s, sid); - if (stream_index >= 0) { - AVStream *st = s->streams[stream_index]; - int audio_type; - avio_skip(pb, 8); - audio_type = avio_r8(pb); - if (audio_type == 2) - st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; - else if (audio_type == 3) - st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; - consumed += 9; - } - } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) { - int stream_index = ff_find_stream_index(s, sid); - if (stream_index >= 0) { - avio_skip(pb, 12); - if (avio_rl32(pb)) - av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index); - consumed += 16; - } - } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) { - int stream_index = ff_find_stream_index(s, sid); - if (stream_index >= 0) { - AVStream *st = s->streams[stream_index]; - uint8_t language[4]; - avio_skip(pb, 12); - avio_read(pb, language, 3); - if (language[0]) { - language[3] = 0; - av_dict_set(&st->metadata, "language", language, 0); - if (!strcmp(language, "nar") || !strcmp(language, "NAR")) - st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; - } - consumed += 15; - } - } else if (!ff_guidcmp(g, timestamp_guid)) { - int stream_index = ff_find_stream_index(s, sid); - if (stream_index >= 0) { - avio_skip(pb, 8); - wtv->pts = avio_rl64(pb); - consumed += 16; - if (wtv->pts == -1) - wtv->pts = AV_NOPTS_VALUE; - else { - wtv->last_valid_pts = wtv->pts; - if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch) - wtv->epoch = wtv->pts; - if (mode == SEEK_TO_PTS && wtv->pts >= seekts) { -#define WTV_PAD8(x) (((x) + 7) & ~7) - avio_skip(pb, WTV_PAD8(len) - consumed); - return 0; - } - } - } - } else if (!ff_guidcmp(g, data_guid)) { - int stream_index = ff_find_stream_index(s, sid); - if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32) { - WtvStream *wst = s->streams[stream_index]->priv_data; - wst->seen_data = 1; - if (len_ptr) { - *len_ptr = len; - } - return stream_index; - } - } else if ( - !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) || - !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) || - !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ (const ff_asf_guid){0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A}) || - !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) || - !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) || - !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) || - !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) || - !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) || - !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) || - !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) || - !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) || - !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) || - !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) || - !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || - !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) || - !ff_guidcmp(g, (const ff_asf_guid){0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || - !ff_guidcmp(g, (const ff_asf_guid){0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || - !ff_guidcmp(g, (const ff_asf_guid){0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D})) { - //ignore known guids - } else - av_log(s, AV_LOG_WARNING, "unsupported chunk:"PRI_GUID"\n", ARG_GUID(g)); - - avio_skip(pb, WTV_PAD8(len) - consumed); - } - return AVERROR_EOF; -} - -/* declare utf16le strings */ -#define _ , 0, -static const uint8_t timeline_le16[] = - {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0}; -static const uint8_t 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}; -static const uint8_t table_0_entries_time_le16[] = - {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'t'_'i'_'m'_'e', 0}; -static const uint8_t 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}; -#undef _ - -static int read_header(AVFormatContext *s) -{ - WtvContext *wtv = s->priv_data; - int root_sector, root_size; - uint8_t root[WTV_SECTOR_SIZE]; - AVIOContext *pb; - int64_t timeline_pos; - int ret; - - wtv->epoch = - wtv->pts = - wtv->last_valid_pts = AV_NOPTS_VALUE; - - /* read root directory sector */ - avio_skip(s->pb, 0x30); - root_size = avio_rl32(s->pb); - if (root_size > sizeof(root)) { - av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n"); - return AVERROR_INVALIDDATA; - } - avio_skip(s->pb, 4); - root_sector = avio_rl32(s->pb); - - avio_seek(s->pb, root_sector << WTV_SECTOR_BITS, SEEK_SET); - root_size = avio_read(s->pb, root, root_size); - if (root_size < 0) - return AVERROR_INVALIDDATA; - - /* parse chunks up until first data chunk */ - wtv->pb = wtvfile_open(s, root, root_size, timeline_le16); - if (!wtv->pb) { - av_log(s, AV_LOG_ERROR, "timeline data missing\n"); - return AVERROR_INVALIDDATA; - } - - ret = parse_chunks(s, SEEK_TO_DATA, 0, 0); - if (ret < 0) - return ret; - avio_seek(wtv->pb, -32, SEEK_CUR); - - timeline_pos = avio_tell(s->pb); // save before opening another file - - /* read metadata */ - pb = wtvfile_open(s, root, root_size, table_0_entries_legacy_attrib_le16); - if (pb) { - parse_legacy_attrib(s, pb); - wtvfile_close(pb); - } - - /* read seek index */ - if (s->nb_streams) { - AVStream *st = s->streams[0]; - pb = wtvfile_open(s, root, root_size, table_0_entries_time_le16); - if (pb) { - while(1) { - uint64_t timestamp = avio_rl64(pb); - uint64_t frame_nb = avio_rl64(pb); - if (pb->eof_reached) - break; - ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size, - 0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME); - } - wtvfile_close(pb); - - if (wtv->nb_index_entries) { - pb = wtvfile_open(s, root, root_size, timeline_table_0_entries_Events_le16); - if (pb) { - int i; - while (1) { - uint64_t frame_nb = avio_rl64(pb); - uint64_t position = avio_rl64(pb); - if (pb->eof_reached) - break; - for (i = wtv->nb_index_entries - 1; i >= 0; i--) { - AVIndexEntry *e = wtv->index_entries + i; - if (frame_nb > e->size) - break; - if (position > e->pos) - e->pos = position; - } - } - wtvfile_close(pb); - st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp; - } - } - } - } - - avio_seek(s->pb, timeline_pos, SEEK_SET); - return 0; -} - -static int read_packet(AVFormatContext *s, AVPacket *pkt) -{ - WtvContext *wtv = s->priv_data; - AVIOContext *pb = wtv->pb; - int stream_index, len, ret; - - stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len); - if (stream_index < 0) - return stream_index; - - ret = av_get_packet(pb, pkt, len - 32); - if (ret < 0) - return ret; - pkt->stream_index = stream_index; - pkt->pts = wtv->pts; - avio_skip(pb, WTV_PAD8(len) - len); - return 0; -} - -static int read_seek(AVFormatContext *s, int stream_index, - int64_t ts, int flags) -{ - WtvContext *wtv = s->priv_data; - AVIOContext *pb = wtv->pb; - AVStream *st = s->streams[0]; - int64_t ts_relative; - int i; - - if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE)) - return AVERROR(ENOSYS); - - /* timestamp adjustment is required because wtv->pts values are absolute, - * whereas AVIndexEntry->timestamp values are relative to epoch. */ - ts_relative = ts; - if (wtv->epoch != AV_NOPTS_VALUE) - ts_relative -= wtv->epoch; - - i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags); - if (i < 0) { - if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts) - avio_seek(pb, 0, SEEK_SET); - else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries) - avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET); - if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0) - return AVERROR(ERANGE); - return 0; - } - wtv->pts = wtv->index_entries[i].timestamp; - if (wtv->epoch != AV_NOPTS_VALUE) - wtv->pts += wtv->epoch; - wtv->last_valid_pts = wtv->pts; - avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET); - return 0; -} - -static int read_close(AVFormatContext *s) -{ - WtvContext *wtv = s->priv_data; - av_free(wtv->index_entries); - wtvfile_close(wtv->pb); - return 0; -} - -AVInputFormat ff_wtv_demuxer = { - .name = "wtv", - .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"), - .priv_data_size = sizeof(WtvContext), - .read_probe = read_probe, - .read_header = read_header, - .read_packet = read_packet, - .read_seek = read_seek, - .read_close = read_close, - .flags = AVFMT_SHOW_IDS, -}; diff --git a/libavformat/wtv.h b/libavformat/wtv.h new file mode 100644 index 0000000000..7e4f243551 --- /dev/null +++ b/libavformat/wtv.h @@ -0,0 +1,55 @@ +/* + * 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 + */ + +#ifndef AVFORMAT_WTV_H +#define AVFORMAT_WTV_H + +#include "riff.h" +#include "asf.h" + +#define WTV_SECTOR_BITS 12 +#define WTV_SECTOR_SIZE (1 << WTV_SECTOR_BITS) +#define WTV_BIGSECTOR_BITS 18 +#define WTV_PAD8(x) (((x) + 7) & ~7) + +extern const uint8_t ff_timeline_le16[16]; +extern const uint8_t ff_timeline_table_0_entries_Events_le16[62]; +extern const uint8_t ff_table_0_entries_legacy_attrib_le16[58]; +extern const uint8_t ff_table_0_entries_time_le16[40]; + +extern const ff_asf_guid ff_dir_entry_guid; +extern const ff_asf_guid ff_wtv_guid; +extern const ff_asf_guid ff_timestamp_guid; +extern const ff_asf_guid ff_data_guid; +extern const ff_asf_guid ff_stream_guid; +extern const ff_asf_guid ff_mediatype_audio; +extern const ff_asf_guid ff_mediatype_video; +extern const ff_asf_guid ff_format_none; +extern const AVCodecGuid ff_video_guids[]; + +extern const ff_asf_guid ff_DSATTRIB_TRANSPORT_PROPERTIES; +extern const ff_asf_guid ff_metadata_guid; +extern const ff_asf_guid ff_stream2_guid; +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; +#endif /* AVFORMAT_WTV_H */ diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c new file mode 100644 index 0000000000..537dc8ee0d --- /dev/null +++ b/libavformat/wtvdec.c @@ -0,0 +1,1042 @@ +/* + * Windows Television (WTV) demuxer + * 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 + */ + +/** + * @file + * Windows Television (WTV) demuxer + * @author Peter Ross <pross@xvid.org> + */ + +#include "libavutil/intreadwrite.h" +#include "libavutil/intfloat.h" +#include "avformat.h" +#include "internal.h" +#include "wtv.h" +#include "mpegts.h" +#include <strings.h> + +/* Macros for formating GUIDs */ +#define PRI_PRETTY_GUID \ + "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x" +#define ARG_PRETTY_GUID(g) \ + AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15] +#define LEN_PRETTY_GUID 34 + +/* + * + * File system routines + * + */ + +typedef struct { + 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 error; + int64_t position; + int64_t length; +} WtvFile; + +/** + * @return bytes read, 0 on end of file, or <0 on error + */ +static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) +{ + WtvFile *wf = opaque; + AVIOContext *pb = wf->pb_filesystem; + int nread = 0; + + if (wf->error || pb->error) + return -1; + if (wf->position >= wf->length || url_feof(pb)) + return 0; + + buf_size = FFMIN(buf_size, wf->length - wf->position); + while(nread < buf_size) { + int n; + int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1)); + int read_request = FFMIN(buf_size - nread, remaining_in_sector); + + n = avio_read(pb, buf, read_request); + if (n <= 0) + break; + nread += n; + buf += n; + wf->position += n; + if (n == remaining_in_sector) { + 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)) { + wf->error = 1; + break; + } + } + } + return nread; +} + +/** + * @return position (or file length) + */ +static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence) +{ + WtvFile *wf = opaque; + AVIOContext *pb = wf->pb_filesystem; + + if (whence == AVSEEK_SIZE) + return wf->length; + else if (whence == SEEK_CUR) + offset = wf->position + offset; + else if (whence == SEEK_END) + 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; + wf->position = offset; + return offset; +} + +/** + * read non-zero integers (le32) from input stream + * @param pb + * @param[out] data destination + * @param count maximum number of integers to read + * @return total number of integers read + */ +static int read_ints(AVIOContext *pb, uint32_t *data, int count) +{ + int i, total = 0; + for (i = 0; i < count; i++) { + if ((data[total] = avio_rl32(pb))) + total++; + } + return total; +} + +/** + * Open file + * @param first_sector First sector + * @param length Length of file (bytes) + * @param depth File allocation table depth + * @return NULL on error + */ +static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s) +{ + AVIOContext *pb; + WtvFile *wf; + uint8_t *buffer; + + if (avio_seek(s->pb, first_sector << WTV_SECTOR_BITS, SEEK_SET) < 0) + return NULL; + + wf = av_mallocz(sizeof(WtvFile)); + if (!wf) + return NULL; + + if (depth == 0) { + wf->sectors = av_malloc(sizeof(uint32_t)); + if (!wf->sectors) { + av_free(wf); + return NULL; + } + wf->sectors[0] = first_sector; + wf->nb_sectors = 1; + } else if (depth == 1) { + wf->sectors = av_malloc(WTV_SECTOR_SIZE); + if (!wf->sectors) { + av_free(wf); + return NULL; + } + wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4); + } else if (depth == 2) { + uint32_t sectors1[WTV_SECTOR_SIZE / 4]; + int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4); + int i; + + wf->sectors = av_malloc(nb_sectors1 << 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) + break; + wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4); + } + } else { + av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth); + av_free(wf); + return NULL; + } + wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS; + + if (!wf->nb_sectors) { + av_free(wf->sectors); + av_free(wf); + return NULL; + } + + /* check length */ + length &= 0xFFFFFFFFFFFF; + if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) { + av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits); + length = (int64_t)wf->nb_sectors << wf->sector_bits; + } + wf->length = length; + + /* seek to intial sector */ + wf->position = 0; + if (avio_seek(s->pb, (int64_t)wf->sectors[0] << WTV_SECTOR_BITS, SEEK_SET) < 0) { + av_free(wf->sectors); + av_free(wf); + return NULL; + } + + wf->pb_filesystem = s->pb; + buffer = av_malloc(1 << wf->sector_bits); + if (!buffer) { + av_free(wf->sectors); + av_free(wf); + return NULL; + } + + pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf, + wtvfile_read_packet, NULL, wtvfile_seek); + if (!pb) { + av_free(buffer); + av_free(wf->sectors); + av_free(wf); + } + return pb; +} + +/** + * Open file using filename + * @param[in] buf directory buffer + * @param buf_size directory buffer size + * @param[in] filename + * @param filename_size size of filename + * @return NULL on error + */ +static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size) +{ + const uint8_t *buf_end = buf + buf_size; + + while(buf + 48 <= buf_end) { + int dir_length, name_size, first_sector, depth; + uint64_t file_length; + const uint8_t *name; + if (ff_guidcmp(buf, ff_dir_entry_guid)) { + av_log(s, AV_LOG_ERROR, "unknown guid "FF_PRI_GUID", expected dir_entry_guid; " + "remaining directory entries ignored\n", FF_ARG_GUID(buf)); + break; + } + dir_length = AV_RL16(buf + 16); + file_length = AV_RL64(buf + 24); + name_size = 2 * AV_RL32(buf + 32); + if (buf + 48 + name_size > buf_end) { + av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n"); + break; + } + first_sector = AV_RL32(buf + 40 + name_size); + depth = AV_RL32(buf + 44 + name_size); + + /* compare file name; test optional null terminator */ + name = buf + 40; + if (name_size >= filename_size && + !memcmp(name, filename, filename_size) && + (name_size < filename_size + 2 || !AV_RN16(name + filename_size))) + return wtvfile_open_sector(first_sector, file_length, depth, s); + + buf += dir_length; + } + return 0; +} + +#define wtvfile_open(s, buf, buf_size, filename) \ + wtvfile_open2(s, buf, buf_size, filename, sizeof(filename)) + +/** + * Close file opened with wtvfile_open_sector(), or wtv_open() + */ +static void wtvfile_close(AVIOContext *pb) +{ + WtvFile *wf = pb->opaque; + av_free(wf->sectors); + av_freep(&pb->opaque); + av_freep(&pb->buffer); + av_free(pb); +} + +/* + * + * Main demuxer + * + */ + +typedef struct { + int seen_data; +} WtvStream; + +typedef struct { + 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 */ + + /* maintain private seek index, as the AVIndexEntry->pos is relative to the + start of the 'timeline' file, not the file system (AVFormatContext->pb) */ + AVIndexEntry *index_entries; + int nb_index_entries; + unsigned int index_entries_allocated_size; +} WtvContext; + +/* WTV GUIDs */ +static const ff_asf_guid EVENTID_SubtitleSpanningEvent = + {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A}; +static const ff_asf_guid EVENTID_LanguageSpanningEvent = + {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95}; +static const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent = + {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E}; +static const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent = + {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24}; +static const ff_asf_guid EVENTID_CSDescriptorSpanningEvent = + {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66}; +static const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent = + {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B}; +static const ff_asf_guid EVENTID_StreamIDSpanningEvent = + {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE}; +static const ff_asf_guid EVENTID_TeletextSpanningEvent = + {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3}; +static const ff_asf_guid EVENTID_AudioTypeSpanningEvent = + {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3}; + +/* Windows media GUIDs */ + +/* Media types */ +static const ff_asf_guid mediasubtype_mpeg1payload = + {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}; +static const ff_asf_guid mediatype_mpeg2_sections = + {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5}; +static const ff_asf_guid mediatype_mpeg2_pes = + {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}; +static const ff_asf_guid mediatype_mstvcaption = + {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1}; + +/* Media subtypes */ +static const ff_asf_guid mediasubtype_dvb_subtitle = + {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F}; +static const ff_asf_guid mediasubtype_teletext = + {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA}; +static const ff_asf_guid mediasubtype_dtvccdata = + {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A}; +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; +} + +/** + * Convert win32 FILETIME to ISO-8601 string + */ +static void filetime_to_iso8601(char *buf, int buf_size, int64_t value) +{ + time_t t = (value / 10000000LL) - 11644473600LL; + strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t)); +} + +/** + * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string + */ +static void crazytime_to_iso8601(char *buf, int buf_size, int64_t value) +{ + time_t t = (value / 10000000LL) - 719162LL*86400LL; + strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", gmtime(&t)); +} + +/** + * Convert OLE DATE to ISO-8601 string + * @return <0 on error + */ +static int oledate_to_iso8601(char *buf, int buf_size, int64_t value) +{ + time_t t = (av_int2double(value) - 25569.0) * 86400; + struct tm *result= gmtime(&t); + if (!result) + return -1; + strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", result); + return 0; +} + +static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length) +{ + char mime[1024]; + char description[1024]; + unsigned int filesize; + AVStream *st; + int64_t pos = avio_tell(pb); + + avio_get_str16le(pb, INT_MAX, mime, sizeof(mime)); + if (strcmp(mime, "image/jpeg")) + goto done; + + avio_r8(pb); + avio_get_str16le(pb, INT_MAX, description, sizeof(description)); + filesize = avio_rl32(pb); + if (!filesize) + goto done; + + st = avformat_new_stream(s, NULL); + if (!st) + goto done; + av_dict_set(&st->metadata, "title", description, 0); + st->codec->codec_id = CODEC_ID_MJPEG; + st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; + st->codec->extradata = av_mallocz(filesize); + if (!st->codec->extradata) + goto done; + st->codec->extradata_size = filesize; + avio_read(pb, st->codec->extradata, filesize); +done: + avio_seek(pb, pos + length, SEEK_SET); +} + +static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length) +{ + int buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1; + char *buf = av_malloc(buf_size); + if (!buf) + return; + + if (type == 0 && length == 4) { + snprintf(buf, buf_size, "%"PRIi32, avio_rl32(pb)); + } else if (type == 1) { + avio_get_str16le(pb, length, buf, buf_size); + if (!strlen(buf)) { + av_free(buf); + return; + } + } else if (type == 3 && length == 4) { + strcpy(buf, avio_rl32(pb) ? "true" : "false"); + } else if (type == 4 && length == 8) { + int64_t num = avio_rl64(pb); + if (!strcmp(key, "WM/EncodingTime") || + !strcmp(key, "WM/MediaOriginalBroadcastDateTime")) + filetime_to_iso8601(buf, buf_size, num); + else if (!strcmp(key, "WM/WMRVEncodeTime") || + !strcmp(key, "WM/WMRVEndTime")) + crazytime_to_iso8601(buf, buf_size, num); + else if (!strcmp(key, "WM/WMRVExpirationDate")) { + if (oledate_to_iso8601(buf, buf_size, num) < 0 ) { + av_free(buf); + return; + } + } else if (!strcmp(key, "WM/WMRVBitrate")) + snprintf(buf, buf_size, "%f", av_int2double(num)); + else + snprintf(buf, buf_size, "%"PRIi64, num); + } else if (type == 5 && length == 2) { + snprintf(buf, buf_size, "%"PRIi16, avio_rl16(pb)); + } else if (type == 6 && length == 16) { + ff_asf_guid guid; + avio_read(pb, guid, 16); + snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid)); + } else if (type == 2 && !strcmp(key, "WM/Picture")) { + get_attachment(s, pb, length); + av_freep(&buf); + return; + } else { + av_freep(&buf); + av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length); + avio_skip(pb, length); + return; + } + + av_dict_set(&s->metadata, key, buf, 0); + av_freep(&buf); +} + +/** + * Parse metadata entries + */ +static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb) +{ + ff_asf_guid guid; + int length, type; + while(!url_feof(pb)) { + char key[1024]; + ff_get_guid(pb, &guid); + type = avio_rl32(pb); + length = avio_rl32(pb); + if (!length) + break; + if (ff_guidcmp(&guid, ff_metadata_guid)) { + av_log(s, AV_LOG_WARNING, "unknown guid "FF_PRI_GUID", expected metadata_guid; " + "remaining metadata entries ignored\n", FF_ARG_GUID(guid)); + break; + } + avio_get_str16le(pb, INT_MAX, key, sizeof(key)); + get_tag(s, pb, key, type, length); + } + + ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv); +} + +/** + * parse VIDEOINFOHEADER2 structure + * @return bytes consumed + */ +static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st) +{ + WtvContext *wtv = s->priv_data; + AVIOContext *pb = wtv->pb; + + avio_skip(pb, 72); // picture aspect ratio is unreliable + ff_get_bmp_header(pb, st); + + return 72 + 40; +} + +/** + * Parse MPEG1WAVEFORMATEX extradata structure + */ +static void parse_mpeg1waveformatex(AVStream *st) +{ + /* fwHeadLayer */ + switch (AV_RL16(st->codec->extradata)) { + case 0x0001 : st->codec->codec_id = CODEC_ID_MP1; break; + case 0x0002 : st->codec->codec_id = CODEC_ID_MP2; break; + case 0x0004 : st->codec->codec_id = CODEC_ID_MP3; break; + } + + st->codec->bit_rate = AV_RL32(st->codec->extradata + 2); /* dwHeadBitrate */ + + /* dwHeadMode */ + switch (AV_RL16(st->codec->extradata + 6)) { + case 1 : case 2 : case 4 : st->codec->channels = 2; break; + case 8 : st->codec->channels = 1; break; + } +} + +/** + * Initialise stream + * @param st Stream to initialise, or NULL to create and initialise new stream + * @return NULL on error + */ +static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type) +{ + if (st) { + if (st->codec->extradata) { + av_freep(&st->codec->extradata); + st->codec->extradata_size = 0; + } + } else { + WtvStream *wst = av_mallocz(sizeof(WtvStream)); + if (!wst) + return NULL; + st = avformat_new_stream(s, NULL); + if (!st) + return NULL; + st->id = sid; + st->priv_data = wst; + } + st->codec->codec_type = codec_type; + st->need_parsing = AVSTREAM_PARSE_FULL; + avpriv_set_pts_info(st, 64, 1, 10000000); + return st; +} + +/** + * parse Media Type structure and populate stream + * @param st Stream, or NULL to create new stream + * @param mediatype Mediatype GUID + * @param subtype Subtype GUID + * @param formattype Format GUID + * @param size Size of format buffer + * @return NULL on error + */ +static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid, + ff_asf_guid mediatype, ff_asf_guid subtype, + ff_asf_guid formattype, int size) +{ + WtvContext *wtv = s->priv_data; + AVIOContext *pb = wtv->pb; + if (!ff_guidcmp(subtype, ff_mediasubtype_cpfilters_processed) && + !ff_guidcmp(formattype, ff_format_cpfilters_processed)) { + ff_asf_guid actual_subtype; + ff_asf_guid actual_formattype; + + if (size < 32) { + av_log(s, AV_LOG_WARNING, "format buffer size underflow\n"); + avio_skip(pb, size); + return NULL; + } + + avio_skip(pb, size - 32); + ff_get_guid(pb, &actual_subtype); + ff_get_guid(pb, &actual_formattype); + avio_seek(pb, -size, SEEK_CUR); + + st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32); + avio_skip(pb, 32); + return st; + } else if (!ff_guidcmp(mediatype, ff_mediatype_audio)) { + st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO); + if (!st) + return NULL; + if (!ff_guidcmp(formattype, ff_format_waveformatex)) { + int ret = ff_get_wav_header(pb, st->codec, size); + if (ret < 0) + return NULL; + } else { + if (ff_guidcmp(formattype, ff_format_none)) + av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); + avio_skip(pb, size); + } + + if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) { + st->codec->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codec->bits_per_coded_sample); + } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) { + if (st->codec->extradata && st->codec->extradata_size >= 22) + parse_mpeg1waveformatex(st); + else + av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n"); + } else { + st->codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subtype); + if (st->codec->codec_id == CODEC_ID_NONE) + av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype)); + } + return st; + } else if (!ff_guidcmp(mediatype, ff_mediatype_video)) { + st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO); + if (!st) + return NULL; + if (!ff_guidcmp(formattype, format_videoinfo2)) { + int consumed = parse_videoinfoheader2(s, st); + avio_skip(pb, FFMAX(size - consumed, 0)); + } else if (!ff_guidcmp(formattype, ff_format_mpeg2_video)) { + int consumed = parse_videoinfoheader2(s, st); + avio_skip(pb, FFMAX(size - consumed, 0)); + } else { + if (ff_guidcmp(formattype, ff_format_none)) + av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); + avio_skip(pb, size); + } + + if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) { + st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype)); + } else { + st->codec->codec_id = ff_codec_guid_get_id(ff_video_guids, subtype); + } + if (st->codec->codec_id == CODEC_ID_NONE) + av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype)); + return st; + } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) && + !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) { + st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE); + if (!st) + return NULL; + if (ff_guidcmp(formattype, ff_format_none)) + av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); + avio_skip(pb, size); + st->codec->codec_id = CODEC_ID_DVB_SUBTITLE; + return st; + } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) && + (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) { + st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE); + if (!st) + return NULL; + if (ff_guidcmp(formattype, ff_format_none)) + av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); + avio_skip(pb, size); + st->codec->codec_id = CODEC_ID_DVB_TELETEXT; + return st; + } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) && + !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) { + if (ff_guidcmp(formattype, ff_format_none)) + av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype)); + avio_skip(pb, size); + return NULL; + } + + av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"FF_PRI_GUID + ", subtype:"FF_PRI_GUID", formattype:"FF_PRI_GUID"\n", + FF_ARG_GUID(mediatype), FF_ARG_GUID(subtype), FF_ARG_GUID(formattype)); + avio_skip(pb, size); + return NULL; +} + +enum { + SEEK_TO_DATA = 0, + SEEK_TO_PTS, +}; + +/** + * Parse WTV chunks + * @param mode SEEK_TO_DATA or SEEK_TO_PTS + * @param seekts timestamp + * @param[out] len_ptr Length of data chunk + * @return stream index of data chunk, or <0 on error + */ +static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr) +{ + WtvContext *wtv = s->priv_data; + AVIOContext *pb = wtv->pb; + while (!url_feof(pb)) { + ff_asf_guid g; + int len, sid, consumed; + + ff_get_guid(pb, &g); + len = avio_rl32(pb); + if (len < 32) + break; + sid = avio_rl32(pb) & 0x7FFF; + avio_skip(pb, 8); + consumed = 32; + + if (!ff_guidcmp(g, ff_stream_guid)) { + if (ff_find_stream_index(s, sid) < 0) { + ff_asf_guid mediatype, subtype, formattype; + int size; + avio_skip(pb, 28); + ff_get_guid(pb, &mediatype); + ff_get_guid(pb, &subtype); + avio_skip(pb, 12); + ff_get_guid(pb, &formattype); + size = avio_rl32(pb); + parse_media_type(s, 0, sid, mediatype, subtype, formattype, size); + consumed += 92 + size; + } + } else if (!ff_guidcmp(g, ff_stream2_guid)) { + int stream_index = ff_find_stream_index(s, sid); + if (stream_index >= 0 && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) { + ff_asf_guid mediatype, subtype, formattype; + int size; + avio_skip(pb, 12); + ff_get_guid(pb, &mediatype); + ff_get_guid(pb, &subtype); + avio_skip(pb, 12); + ff_get_guid(pb, &formattype); + size = avio_rl32(pb); + parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size); + consumed += 76 + size; + } + } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) || + !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) || + !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) || + !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) || + !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) || + !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) { + int stream_index = ff_find_stream_index(s, sid); + if (stream_index >= 0) { + AVStream *st = s->streams[stream_index]; + uint8_t buf[258]; + const uint8_t *pbuf = buf; + int buf_size; + + avio_skip(pb, 8); + consumed += 8; + if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) || + !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) { + avio_skip(pb, 6); + consumed += 6; + } + + buf_size = FFMIN(len - consumed, sizeof(buf)); + avio_read(pb, buf, buf_size); + consumed += buf_size; + ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL); + } + } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) { + int stream_index = ff_find_stream_index(s, sid); + if (stream_index >= 0) { + AVStream *st = s->streams[stream_index]; + int audio_type; + avio_skip(pb, 8); + audio_type = avio_r8(pb); + if (audio_type == 2) + st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; + else if (audio_type == 3) + st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + consumed += 9; + } + } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) { + int stream_index = ff_find_stream_index(s, sid); + if (stream_index >= 0) { + avio_skip(pb, 12); + if (avio_rl32(pb)) + av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index); + consumed += 16; + } + } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) { + int stream_index = ff_find_stream_index(s, sid); + if (stream_index >= 0) { + AVStream *st = s->streams[stream_index]; + uint8_t language[4]; + avio_skip(pb, 12); + avio_read(pb, language, 3); + if (language[0]) { + language[3] = 0; + av_dict_set(&st->metadata, "language", language, 0); + if (!strcmp(language, "nar") || !strcmp(language, "NAR")) + st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + } + consumed += 15; + } + } else if (!ff_guidcmp(g, ff_timestamp_guid)) { + int stream_index = ff_find_stream_index(s, sid); + if (stream_index >= 0) { + avio_skip(pb, 8); + wtv->pts = avio_rl64(pb); + consumed += 16; + if (wtv->pts == -1) + wtv->pts = AV_NOPTS_VALUE; + else { + wtv->last_valid_pts = wtv->pts; + if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch) + wtv->epoch = wtv->pts; + if (mode == SEEK_TO_PTS && wtv->pts >= seekts) { + avio_skip(pb, WTV_PAD8(len) - consumed); + return 0; + } + } + } + } else if (!ff_guidcmp(g, ff_data_guid)) { + int stream_index = ff_find_stream_index(s, sid); + if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32) { + WtvStream *wst = s->streams[stream_index]->priv_data; + wst->seen_data = 1; + if (len_ptr) { + *len_ptr = len; + } + return stream_index; + } + } else if ( + !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) || + !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) || + !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ ff_DSATTRIB_TRANSPORT_PROPERTIES) || + !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) || + !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) || + !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) || + !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) || + !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) || + !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) || + !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) || + !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) || + !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) || + !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) || + !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || + !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) || + !ff_guidcmp(g, (const ff_asf_guid){0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || + !ff_guidcmp(g, (const ff_asf_guid){0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || + !ff_guidcmp(g, (const ff_asf_guid){0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) || + !ff_guidcmp(g, (const ff_asf_guid){0xF7,0x10,0x02,0xB9,0xEE,0x7C,0xED,0x4E,0xBD,0x7F,0x05,0x40,0x35,0x86,0x18,0xA1})) { + //ignore known guids + } else + av_log(s, AV_LOG_WARNING, "unsupported chunk:"FF_PRI_GUID"\n", FF_ARG_GUID(g)); + + avio_skip(pb, WTV_PAD8(len) - consumed); + } + return AVERROR_EOF; +} + +static int read_header(AVFormatContext *s) +{ + WtvContext *wtv = s->priv_data; + int root_sector, root_size; + uint8_t root[WTV_SECTOR_SIZE]; + AVIOContext *pb; + int64_t timeline_pos; + int ret; + + wtv->epoch = + wtv->pts = + wtv->last_valid_pts = AV_NOPTS_VALUE; + + /* read root directory sector */ + avio_skip(s->pb, 0x30); + root_size = avio_rl32(s->pb); + if (root_size > sizeof(root)) { + av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n"); + return AVERROR_INVALIDDATA; + } + avio_skip(s->pb, 4); + root_sector = avio_rl32(s->pb); + + avio_seek(s->pb, root_sector << WTV_SECTOR_BITS, SEEK_SET); + root_size = avio_read(s->pb, root, root_size); + if (root_size < 0) + return AVERROR_INVALIDDATA; + + /* parse chunks up until first data chunk */ + wtv->pb = wtvfile_open(s, root, root_size, ff_timeline_le16); + if (!wtv->pb) { + av_log(s, AV_LOG_ERROR, "timeline data missing\n"); + return AVERROR_INVALIDDATA; + } + + ret = parse_chunks(s, SEEK_TO_DATA, 0, 0); + if (ret < 0) + return ret; + avio_seek(wtv->pb, -32, SEEK_CUR); + + timeline_pos = avio_tell(s->pb); // save before opening another file + + /* read metadata */ + pb = wtvfile_open(s, root, root_size, ff_table_0_entries_legacy_attrib_le16); + if (pb) { + parse_legacy_attrib(s, pb); + wtvfile_close(pb); + } + + /* read seek index */ + if (s->nb_streams) { + AVStream *st = s->streams[0]; + pb = wtvfile_open(s, root, root_size, ff_table_0_entries_time_le16); + if (pb) { + while(1) { + uint64_t timestamp = avio_rl64(pb); + uint64_t frame_nb = avio_rl64(pb); + if (url_feof(pb)) + break; + ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size, + 0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME); + } + wtvfile_close(pb); + + if (wtv->nb_index_entries) { + pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16); + if (pb) { + int i; + while (1) { + uint64_t frame_nb = avio_rl64(pb); + uint64_t position = avio_rl64(pb); + if (url_feof(pb)) + break; + for (i = wtv->nb_index_entries - 1; i >= 0; i--) { + AVIndexEntry *e = wtv->index_entries + i; + if (frame_nb > e->size) + break; + if (position > e->pos) + e->pos = position; + } + } + wtvfile_close(pb); + st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp; + } + } + } + } + + avio_seek(s->pb, timeline_pos, SEEK_SET); + return 0; +} + +static int read_packet(AVFormatContext *s, AVPacket *pkt) +{ + WtvContext *wtv = s->priv_data; + AVIOContext *pb = wtv->pb; + int stream_index, len, ret; + + stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len); + if (stream_index < 0) + return stream_index; + + ret = av_get_packet(pb, pkt, len - 32); + if (ret < 0) + return ret; + pkt->stream_index = stream_index; + pkt->pts = wtv->pts; + avio_skip(pb, WTV_PAD8(len) - len); + return 0; +} + +static int read_seek(AVFormatContext *s, int stream_index, + int64_t ts, int flags) +{ + WtvContext *wtv = s->priv_data; + AVIOContext *pb = wtv->pb; + AVStream *st = s->streams[0]; + int64_t ts_relative; + int i; + + if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE)) + return AVERROR(ENOSYS); + + /* timestamp adjustment is required because wtv->pts values are absolute, + * whereas AVIndexEntry->timestamp values are relative to epoch. */ + ts_relative = ts; + if (wtv->epoch != AV_NOPTS_VALUE) + ts_relative -= wtv->epoch; + + i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags); + if (i < 0) { + if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts) { + if (avio_seek(pb, 0, SEEK_SET) < 0) + return -1; + } else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries) { + if (avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET) < 0) + return -1; + } + if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0) + return AVERROR(ERANGE); + return 0; + } + if (avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET) < 0) + return -1; + wtv->pts = wtv->index_entries[i].timestamp; + if (wtv->epoch != AV_NOPTS_VALUE) + wtv->pts += wtv->epoch; + wtv->last_valid_pts = wtv->pts; + return 0; +} + +static int read_close(AVFormatContext *s) +{ + WtvContext *wtv = s->priv_data; + av_freep(&wtv->index_entries); + wtvfile_close(wtv->pb); + return 0; +} + +AVInputFormat ff_wtv_demuxer = { + .name = "wtv", + .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"), + .priv_data_size = sizeof(WtvContext), + .read_probe = read_probe, + .read_header = read_header, + .read_packet = read_packet, + .read_seek = read_seek, + .read_close = read_close, + .flags = AVFMT_SHOW_IDS, +}; diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c new file mode 100644 index 0000000000..be83c54f71 --- /dev/null +++ b/libavformat/wtvenc.c @@ -0,0 +1,723 @@ +/* + * Windows Television (WTV) muxer + * Copyright (c) 2011 Zhentan Feng <spyfeng at gmail dot com> + * Copyright (c) 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 + */ + +/** + * @file + * Windows Television (WTV) demuxer + * @author Zhentan Feng <spyfeng at gmail dot com> + */ + +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" +#include "avformat.h" +#include "internal.h" +#include "wtv.h" +#include "asf.h" + +#define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS) +#define INDEX_BASE 0x2 +#define MAX_NB_INDEX 10 + +/* declare utf16le strings */ +#define _ , 0, +static const uint8_t timeline_table_0_header_events[] = + {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0}; +static const uint8_t table_0_header_legacy_attrib[] = + {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0}; +static const uint8_t table_0_redirector_legacy_attrib[] = + {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'r'_'e'_'d'_'i'_'r'_'e'_'c'_'t'_'o'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0}; +static const uint8_t table_0_header_time[] = + {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'t'_'i'_'m'_'e', 0}; +static const uint8_t legacy_attrib[] = + {'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0}; +#undef _ + +static const ff_asf_guid sub_wtv_guid = + {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; +static const ff_asf_guid stream1_guid = + {0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; +static const ff_asf_guid sync_guid = + {0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}; +static const ff_asf_guid index_guid = + {0x96,0xc3,0xd2,0xc2,0x7e,0x9a,0xda,0x11,0x8b,0xf7,0x00,0x07,0xe9,0x5e,0xad,0x8d}; + +enum WtvFileIndex { + WTV_TIMELINE_TABLE_0_HEADER_EVENTS = 0, + WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, + WTV_TIMELINE, + WTV_TABLE_0_HEADER_LEGACY_ATTRIB, + WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, + WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, + WTV_TABLE_0_HEADER_TIME, + WTV_TABLE_0_ENTRIES_TIME, + WTV_FILES +}; + +typedef struct { + int64_t length; + const void *header; + int depth; + int first_sector; +} WtvFile; + +typedef struct { + int64_t pos; + int64_t serial; + const ff_asf_guid * guid; + int stream_id; +} WtvChunkEntry; + +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 frame_nb; + + WtvChunkEntry index[MAX_NB_INDEX]; + int nb_index; + int first_video_flag; + int64_t sync_pos; +} WtvContext; + +typedef int WTVHeaderWriteFunc(AVIOContext *pb); + +typedef struct { + const uint8_t *header; + int header_size; + WTVHeaderWriteFunc *write_header; +} WTVRootEntryTable; + +static int write_pad(AVIOContext *pb, int size) +{ + for (; size > 0; size--) + avio_w8(pb, 0); + return 0; +} + +static const ff_asf_guid *get_codec_guid(enum CodecID id, const AVCodecGuid *av_guid) +{ + int i; + for (i = 0; av_guid[i].id != CODEC_ID_NONE; i++) { + if (id == av_guid[i].id) + return &(av_guid[i].guid); + } + return NULL; +} + +/** + * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks + */ +static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id) +{ + WtvContext *wctx = s->priv_data; + AVIOContext *pb = s->pb; + + wctx->last_chunk_pos = avio_tell(pb) - wctx->timeline_start_pos; + ff_put_guid(pb, guid); + avio_wl32(pb, 32 + length); + avio_wl32(pb, stream_id); + avio_wl64(pb, wctx->serial); + + if ((stream_id & 0x80000000) && guid != &index_guid) { + WtvChunkEntry *t = wctx->index + wctx->nb_index; + av_assert0(wctx->nb_index < MAX_NB_INDEX); + t->pos = wctx->last_chunk_pos; + t->serial = wctx->serial; + t->guid = guid; + t->stream_id = stream_id & 0x3FFFFFFF; + wctx->nb_index++; + } +} + +static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id) +{ + WtvContext *wctx = s->priv_data; + AVIOContext *pb = s->pb; + + int64_t last_chunk_pos = wctx->last_chunk_pos; + write_chunk_header(s, guid, 0, stream_id); // length updated later + avio_wl64(pb, last_chunk_pos); +} + +static void finish_chunk_noindex(AVFormatContext *s) +{ + WtvContext *wctx = s->priv_data; + AVIOContext *pb = s->pb; + + // update the chunk_len field and pad. + int64_t chunk_len = avio_tell(pb) - (wctx->last_chunk_pos + wctx->timeline_start_pos); + avio_seek(pb, -(chunk_len - 16), SEEK_CUR); + avio_wl32(pb, chunk_len); + avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR); + + write_pad(pb, WTV_PAD8(chunk_len) - chunk_len); + wctx->serial++; +} + +static void write_index(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + int i; + + write_chunk_header2(s, &index_guid, 0x80000000); + avio_wl32(pb, 0); + avio_wl32(pb, 0); + + for (i = 0; i < wctx->nb_index; i++) { + WtvChunkEntry *t = wctx->index + i; + ff_put_guid(pb, t->guid); + avio_wl64(pb, t->pos); + avio_wl32(pb, t->stream_id); + avio_wl32(pb, 0); // checksum? + avio_wl64(pb, t->serial); + } + wctx->nb_index = 0; // reset index + finish_chunk_noindex(s); +} + +static void finish_chunk(AVFormatContext *s) +{ + WtvContext *wctx = s->priv_data; + finish_chunk_noindex(s); + if (wctx->nb_index == MAX_NB_INDEX) + write_index(s); +} + +static int write_stream_codec_info(AVFormatContext *s, AVStream *st) +{ + WtvContext *wctx = s->priv_data; + const ff_asf_guid *g, *media_type, *format_type; + AVIOContext *pb = s->pb; + int64_t hdr_pos_start; + int hdr_size = 0; + + 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; + } 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; + } 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); + ff_put_guid(pb,&ff_format_cpfilters_processed); // format type + avio_wl32(pb, 0); // size + + 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); + } + } else { + ff_put_wav_header(pb, st->codec); + } + hdr_size = avio_tell(pb) - hdr_pos_start; + + // seek back write hdr_size + 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 + ff_put_guid(pb, format_type); // actual_formattype + + return 0; +} + +static int write_stream_codec(AVFormatContext *s, AVStream * st) +{ + AVIOContext *pb = s->pb; + int ret; + write_chunk_header2(s, &stream1_guid, 0x80000000 | 0x01); + + avio_wl32(pb, 0x01); + write_pad(pb, 4); + write_pad(pb, 4); + + ret = write_stream_codec_info(s, st); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type); + return -1; + } + + finish_chunk(s); + return 0; +} + +static void write_sync(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + int64_t last_chunk_pos = wctx->last_chunk_pos; + wctx->sync_pos = avio_tell(pb) - wctx->timeline_start_pos; + + write_chunk_header(s, &sync_guid, 0x18, 0); + write_pad(pb, 24); + + finish_chunk(s); + + wctx->last_chunk_pos = last_chunk_pos; +} + +static void write_DSATTRIB_TRANSPORT_PROPERTIES_init(AVFormatContext *s, int stream_index) +{ + AVIOContext *pb = s->pb; + write_chunk_header2(s, &ff_DSATTRIB_TRANSPORT_PROPERTIES, 0x80000000 | stream_index); + avio_wl64(pb, stream_index); + avio_wl64(pb, -1); + avio_wl64(pb, 0); + finish_chunk(s); +} + +static int write_stream_data(AVFormatContext *s, AVStream *st, int flag) +{ + AVIOContext *pb = s->pb; + int ret; + + if (!flag) { + write_chunk_header2(s, &ff_stream_guid, 0x80000000 | (st->index + INDEX_BASE)); + avio_wl32(pb, 0x00000001); + avio_wl32(pb, st->index + INDEX_BASE); //stream_id + avio_wl32(pb, 0x00000001); + write_pad(pb, 8); + } else { + write_chunk_header2(s, &ff_stream2_guid, 0x80000000 | (st->index + INDEX_BASE)); + write_pad(pb, 4); + } + + ret = write_stream_codec_info(s, st); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type); + return -1; + } + finish_chunk(s); + + avpriv_set_pts_info(st, 64, 1, 10000000); + + return 0; +} + +static int write_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + int i, pad, ret; + AVStream *st; + + ff_put_guid(pb, &ff_wtv_guid); + ff_put_guid(pb, &sub_wtv_guid); + + avio_wl32(pb, 0x01); + avio_wl32(pb, 0x02); + avio_wl32(pb, 1 << WTV_SECTOR_BITS); + avio_wl32(pb, 1 << WTV_BIGSECTOR_BITS); + + //write initial root fields + avio_wl32(pb, 0); // root_size, update later + write_pad(pb, 4); + avio_wl32(pb, 0); // root_sector, update it later. + + write_pad(pb, 32); + avio_wl32(pb, 0); // file ends pointer, update it later. + + pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb); + write_pad(pb, pad); + wctx->timeline_start_pos = avio_tell(pb); + + wctx->serial = 1; + wctx->last_chunk_pos = -1; + wctx->first_video_flag = 1; + + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + ret = write_stream_codec(s, st); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type); + return -1; + } + if (i + 1 < s->nb_streams) { + write_sync(s); + } + } + + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + ret = write_stream_data(s, st, 0); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type); + return -1; + } + ret = write_stream_data(s, st, 1); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "write stream2 data failed codec_type(0x%x)\n", st->codec->codec_type); + return -1; + } + } + + for (i = 0; i < s->nb_streams; i++) + write_DSATTRIB_TRANSPORT_PROPERTIES_init(s, INDEX_BASE + i); + + if (wctx->nb_index) + write_index(s); + + return 0; +} + +static void write_timestamp(AVFormatContext *s, AVPacket *pkt) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + AVCodecContext *enc = s->streams[pkt->stream_index]->codec; + int flag = 0; + int64_t frame_number = 0; + + if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { + wctx->frame_nb++; + frame_number = wctx->frame_nb; + flag = pkt->flags & AV_PKT_FLAG_KEY ? 1 : 0; + } + write_chunk_header(s, &ff_timestamp_guid, 56, 0x40000000 | (INDEX_BASE + pkt->stream_index)); + write_pad(pb, 8); + avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts); + avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts); + + avio_wl64(pb, frame_number); + avio_wl64(pb, 0); + avio_wl64(pb, flag); + avio_wl64(pb, 0); +} + +static int write_packet(AVFormatContext *s, AVPacket *pkt) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + + // write timestamp chunk + write_timestamp(s, pkt); + + write_chunk_header(s, &ff_data_guid, pkt->size, INDEX_BASE + pkt->stream_index); + avio_write(pb, pkt->data, pkt->size); + write_pad(pb, WTV_PAD8(pkt->size) - pkt->size); + + wctx->serial++; + avio_flush(pb); + return 0; +} + +static int write_table0_header_envents(AVIOContext *pb) +{ + avio_wl32(pb, 0x10); + write_pad(pb, 84); + avio_wl64(pb, 0x32); + return 96; +} + +static int write_table0_header_legacy_attrib(AVIOContext *pb) +{ + int pad = 0; + avio_wl32(pb, 0xFFFFFFFF); + write_pad(pb, 12); + avio_write(pb, legacy_attrib, sizeof(legacy_attrib)); + pad = WTV_PAD8(sizeof(legacy_attrib)) - sizeof(legacy_attrib); + write_pad(pb, pad); + write_pad(pb, 32); + return 48 + WTV_PAD8(sizeof(legacy_attrib)); +} + +static int write_table0_header_time(AVIOContext *pb) +{ + avio_wl32(pb, 0x10); + write_pad(pb, 76); + avio_wl64(pb, 0x40); + return 88; +} + +static const WTVRootEntryTable wtv_root_entry_table[] = { + { timeline_table_0_header_events, sizeof(timeline_table_0_header_events), write_table0_header_envents}, + { ff_timeline_table_0_entries_Events_le16, sizeof(ff_timeline_table_0_entries_Events_le16), NULL}, + { ff_timeline_le16, sizeof(ff_timeline_le16), NULL}, + { table_0_header_legacy_attrib, sizeof(table_0_header_legacy_attrib), write_table0_header_legacy_attrib}, + { ff_table_0_entries_legacy_attrib_le16, sizeof(ff_table_0_entries_legacy_attrib_le16), NULL}, + { table_0_redirector_legacy_attrib, sizeof(table_0_redirector_legacy_attrib), NULL}, + { table_0_header_time, sizeof(table_0_header_time), write_table0_header_time}, + { ff_table_0_entries_time_le16, sizeof(ff_table_0_entries_time_le16), NULL}, +}; + +static int write_root_table(AVFormatContext *s, int64_t sector_pos) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + int size, pad; + int i; + + const WTVRootEntryTable *h = wtv_root_entry_table; + for (i = 0; i < sizeof(wtv_root_entry_table)/sizeof(WTVRootEntryTable); i++, h++) { + WtvFile *w = &wctx->file[i]; + int filename_padding = WTV_PAD8(h->header_size) - h->header_size; + WTVHeaderWriteFunc *write = h->write_header; + int len = 0; + int64_t len_pos; + + ff_put_guid(pb, &ff_dir_entry_guid); + len_pos = avio_tell(pb); + avio_wl16(pb, 40 + h->header_size + filename_padding + 8); // maybe updated later + write_pad(pb, 6); + avio_wl64(pb, write ? 0 : w->length);// maybe update later + avio_wl32(pb, (h->header_size + filename_padding) >> 1); + write_pad(pb, 4); + + avio_write(pb, h->header, h->header_size); + write_pad(pb, filename_padding); + + if (write) { + len = write(pb); + // update length field + avio_seek(pb, len_pos, SEEK_SET); + avio_wl64(pb, 40 + h->header_size + filename_padding + len); + avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60)); + avio_seek(pb, 8 + h->header_size + filename_padding + len, SEEK_CUR); + } else { + avio_wl32(pb, w->first_sector); + avio_wl32(pb, w->depth); + } + } + + // caculate root table size + size = avio_tell(pb) - sector_pos; + pad = WTV_SECTOR_SIZE- size; + write_pad(pb, pad); + + return size; +} + +static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift) +{ + int i; + for (i = 0; i < nb_sectors; i++) { + avio_wl32(pb, start_sector + (i << shift)); + } + // pad left sector pointer size + write_pad(pb, WTV_SECTOR_SIZE - ((nb_sectors << 2) % WTV_SECTOR_SIZE)); +} + +static int write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth) +{ + int64_t start_sector = start_pos >> WTV_SECTOR_BITS; + int shift = sector_bits - WTV_SECTOR_BITS; + + int64_t fat = avio_tell(s->pb); + write_fat(s->pb, start_sector, nb_sectors, shift); + + if (depth == 2) { + int64_t start_sector1 = fat >> WTV_SECTOR_BITS; + int nb_sectors1 = ((nb_sectors << 2) + WTV_SECTOR_SIZE - 1) / WTV_SECTOR_SIZE; + int64_t fat1 = avio_tell(s->pb); + + write_fat(s->pb, start_sector1, nb_sectors1, 0); + return fat1; + } + + return fat; +} + +static void write_table_entries_events(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + WtvContext *wctx = s->priv_data; + + //FIXME: output frame_nb, position pairs. + //We only set the first sync_chunk position here. + avio_wl64(pb, 0x2); avio_wl64(pb, wctx->sync_pos); +} + +static void write_tag(AVIOContext *pb, const char *key, const char *value) +{ + ff_put_guid(pb, &ff_metadata_guid); + avio_wl32(pb, 1); + avio_wl32(pb, strlen(value)*2 + 2); + avio_put_str16le(pb, key); + avio_put_str16le(pb, value); +} + +static void write_table_entries_attrib(AVFormatContext *s) +{ + AVDictionaryEntry *tag = 0; + + //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation + ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL); + while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) + write_tag(s->pb, tag->key, tag->value); +} + +static void write_table_redirector_legacy_attrib(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + AVDictionaryEntry *tag = 0; + int64_t pos = 0; + + //FIXME: translate special tags to binary representation + while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { + avio_wl64(pb, pos); + pos += 16 + 4 + 4 + strlen(tag->key)*2 + 2 + strlen(tag->value)*2 + 2; + } +} + +/** + * Pad the remainder of a file + * Write out fat table + * @return <0 on error + */ +static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos) +{ + WtvContext *wctx = s->priv_data; + AVIOContext *pb = s->pb; + WtvFile *w = &wctx->file[index]; + int64_t end_pos = avio_tell(pb); + int sector_bits, nb_sectors, pad; + + av_assert0(index < WTV_FILES); + + w->length = (end_pos - start_pos); + + // determine optimal fat table depth, sector_bits, nb_sectors + if (w->length <= WTV_SECTOR_SIZE) { + w->depth = 0; + sector_bits = WTV_SECTOR_BITS; + } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) { + w->depth = 1; + sector_bits = WTV_SECTOR_BITS; + } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) { + w->depth = 1; + sector_bits = WTV_BIGSECTOR_BITS; + } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) { + w->depth = 2; + sector_bits = WTV_SECTOR_BITS; + } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) { + w->depth = 2; + sector_bits = WTV_BIGSECTOR_BITS; + } else { + av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length); + return -1; + } + + // determine the nb_sectors + nb_sectors = (int)(w->length >> sector_bits); + + // pad sector of timeline + pad = (1 << sector_bits) - (w->length % (1 << sector_bits)); + if (pad) { + nb_sectors++; + write_pad(pb, pad); + } + + //write fat table + if (w->depth > 0) { + w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth); + } else { + w->first_sector = start_pos; + } + w->first_sector >>= WTV_SECTOR_BITS; + + w->length |= 1ULL<<60; + if (sector_bits == WTV_SECTOR_BITS) + w->length |= 1ULL<<63; + + return 0; +} + +static int write_trailer(AVFormatContext *s) +{ + WtvContext *wctx = s->priv_data; + AVIOContext *pb = s->pb; + int root_size; + int64_t sector_pos; + int64_t start_pos, file_end_pos; + + if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0) + return -1; + + start_pos = avio_tell(pb); + write_table_entries_events(s); + if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0) + return -1; + + start_pos = avio_tell(pb); + write_table_entries_attrib(s); + if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0) + return -1; + + start_pos = avio_tell(pb); + write_table_redirector_legacy_attrib(s); + if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0) + return -1; + + start_pos = avio_tell(pb); + //FIXME: output timestamp, frame_nb pairs here. + if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0) + return -1; + + // write root table + sector_pos = avio_tell(pb); + root_size = write_root_table(s, sector_pos); + + file_end_pos = avio_tell(pb); + // update root value + avio_seek(pb, 0x30, SEEK_SET); + avio_wl32(pb, root_size); + avio_seek(pb, 4, SEEK_CUR); + avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS); + avio_seek(pb, 0x5c, SEEK_SET); + avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS); + + avio_flush(pb); + return 0; +} + +AVOutputFormat ff_wtv_muxer = { + .name = "wtv", + .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"), + .extensions = "wtv", + .priv_data_size = sizeof(WtvContext), + .audio_codec = CODEC_ID_AC3, + .video_codec = CODEC_ID_MPEG2VIDEO, + .write_header = write_header, + .write_packet = write_packet, + .write_trailer = write_trailer, + .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags, + ff_codec_wav_tags, 0 }, +}; diff --git a/libavformat/wv.c b/libavformat/wv.c index c39cc6843c..537fdec583 100644 --- a/libavformat/wv.c +++ b/libavformat/wv.c @@ -2,20 +2,20 @@ * WavPack demuxer * Copyright (c) 2006,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 */ @@ -252,7 +252,7 @@ static int wv_read_packet(AVFormatContext *s, int size, ver, off; int64_t pos; - if (s->pb->eof_reached) + if (url_feof(s->pb)) return AVERROR(EIO); if(wc->block_parsed){ if(wv_read_block_header(s, s->pb, 0) < 0) diff --git a/libavformat/xa.c b/libavformat/xa.c index c5e5cf5864..1e51eec934 100644 --- a/libavformat/xa.c +++ b/libavformat/xa.c @@ -2,20 +2,20 @@ * Maxis XA (.xa) File Demuxer * Copyright (c) 2008 Robert Marston * - * 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/libavformat/xmv.c b/libavformat/xmv.c index 6fa9a6a0a7..110103ea69 100644 --- a/libavformat/xmv.c +++ b/libavformat/xmv.c @@ -3,20 +3,20 @@ * Copyright (c) 2011 Sven Hesse <drmccoy@drmccoy.de> * Copyright (c) 2011 Matthew Hoops <clone2727@gmail.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 */ @@ -33,80 +33,77 @@ #include "internal.h" #include "riff.h" +/** The min size of an XMV header. */ #define XMV_MIN_HEADER_SIZE 36 +/** Audio flag: ADPCM'd 5.1 stream, front left / right channels */ #define XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT 1 +/** Audio flag: ADPCM'd 5.1 stream, front center / low frequency channels */ #define XMV_AUDIO_ADPCM51_FRONTCENTERLOW 2 +/** Audio flag: ADPCM'd 5.1 stream, rear left / right channels */ #define XMV_AUDIO_ADPCM51_REARLEFTRIGHT 4 +/** Audio flag: Any of the ADPCM'd 5.1 stream flags. */ #define XMV_AUDIO_ADPCM51 (XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT | \ XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \ XMV_AUDIO_ADPCM51_REARLEFTRIGHT) -typedef struct XMVAudioTrack { - uint16_t compression; - uint16_t channels; - uint32_t sample_rate; - uint16_t bits_per_sample; - uint32_t bit_rate; - uint16_t flags; - uint16_t block_align; - uint16_t block_samples; - - enum CodecID codec_id; -} XMVAudioTrack; - +/** A video packet with an XMV file. */ typedef struct XMVVideoPacket { - /* The decoder stream index for this video packet. */ - int stream_index; - - uint32_t data_size; - uint32_t data_offset; + int stream_index; ///< The decoder stream index for this video packet. - uint32_t current_frame; - uint32_t frame_count; + uint32_t data_size; ///< The size of the remaining video data. + uint64_t data_offset; ///< The offset of the video data within the file. - /* Does the video packet contain extra data? */ - int has_extradata; + uint32_t current_frame; ///< The current frame within this video packet. + uint32_t frame_count; ///< The amount of frames within this video packet. - /* Extra data */ - uint8_t extradata[4]; + int has_extradata; ///< Does the video packet contain extra data? + uint8_t extradata[4]; ///< The extra data - int64_t last_pts; - int64_t pts; + int64_t last_pts; ///< PTS of the last video frame. + int64_t pts; ///< PTS of the most current video frame. } XMVVideoPacket; +/** An audio packet with an XMV file. */ typedef struct XMVAudioPacket { - /* The decoder stream index for this audio packet. */ - int stream_index; + int stream_index; ///< The decoder stream index for this audio packet. - /* The audio track this packet encodes. */ - XMVAudioTrack *track; + /* Stream format properties. */ + uint16_t compression; ///< The type of compression. + uint16_t channels; ///< Number of channels. + uint32_t sample_rate; ///< Sampling rate. + uint16_t bits_per_sample; ///< Bits per compressed sample. + uint32_t bit_rate; ///< Bits of compressed data per second. + uint16_t flags; ///< Flags + uint16_t block_align; ///< Bytes per compressed block. + uint16_t block_samples; ///< Decompressed samples per compressed block. - uint32_t data_size; - uint32_t data_offset; + enum CodecID codec_id; ///< The codec ID of the compression scheme. - uint32_t frame_size; + uint32_t data_size; ///< The size of the remaining audio data. + uint64_t data_offset; ///< The offset of the audio data within the file. - uint32_t block_count; + uint32_t frame_size; ///< Number of bytes to put into an audio frame. + + uint64_t block_count; ///< Running counter of decompressed audio block. } XMVAudioPacket; +/** Context for demuxing an XMV file. */ typedef struct XMVDemuxContext { - uint16_t audio_track_count; + uint16_t audio_track_count; ///< Number of audio track in this file. - XMVAudioTrack *audio_tracks; + uint32_t this_packet_size; ///< Size of the current packet. + uint32_t next_packet_size; ///< Size of the next packet. - uint32_t this_packet_size; - uint32_t next_packet_size; + uint64_t this_packet_offset; ///< Offset of the current packet. + uint64_t next_packet_offset; ///< Offset of the next packet. - uint32_t this_packet_offset; - uint32_t next_packet_offset; + uint16_t current_stream; ///< The index of the stream currently handling. + uint16_t stream_count; ///< The number of streams in this file. - uint16_t current_stream; - uint16_t stream_count; - - XMVVideoPacket video; - XMVAudioPacket *audio; + XMVVideoPacket video; ///< The video packet contained in each packet. + XMVAudioPacket *audio; ///< The audio packets contained in each packet. } XMVDemuxContext; static int xmv_probe(AVProbeData *p) @@ -172,34 +169,28 @@ static int xmv_read_header(AVFormatContext *s) avio_skip(pb, 2); /* Unknown (padding?) */ - xmv->audio_tracks = av_malloc(xmv->audio_track_count * sizeof(XMVAudioTrack)); - if (!xmv->audio_tracks) - return AVERROR(ENOMEM); - xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket)); if (!xmv->audio) return AVERROR(ENOMEM); for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) { - XMVAudioTrack *track = &xmv->audio_tracks[audio_track]; - XMVAudioPacket *packet = &xmv->audio [audio_track]; + XMVAudioPacket *packet = &xmv->audio[audio_track]; AVStream *ast = NULL; - track->compression = avio_rl16(pb); - track->channels = avio_rl16(pb); - track->sample_rate = avio_rl32(pb); - track->bits_per_sample = avio_rl16(pb); - track->flags = avio_rl16(pb); - - track->bit_rate = track->bits_per_sample * - track->sample_rate * - track->channels; - track->block_align = 36 * track->channels; - track->block_samples = 64; - track->codec_id = ff_wav_codec_get_id(track->compression, - track->bits_per_sample); - - packet->track = track; + packet->compression = avio_rl16(pb); + packet->channels = avio_rl16(pb); + packet->sample_rate = avio_rl32(pb); + packet->bits_per_sample = avio_rl16(pb); + packet->flags = avio_rl16(pb); + + packet->bit_rate = packet->bits_per_sample * + packet->sample_rate * + packet->channels; + packet->block_align = 36 * packet->channels; + packet->block_samples = 64; + packet->codec_id = ff_wav_codec_get_id(packet->compression, + packet->bits_per_sample); + packet->stream_index = -1; packet->frame_size = 0; @@ -207,24 +198,24 @@ static int xmv_read_header(AVFormatContext *s) /* TODO: ADPCM'd 5.1 sound is encoded in three separate streams. * Those need to be interleaved to a proper 5.1 stream. */ - if (track->flags & XMV_AUDIO_ADPCM51) + if (packet->flags & XMV_AUDIO_ADPCM51) av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream " - "(0x%04X)\n", track->flags); + "(0x%04X)\n", packet->flags); ast = avformat_new_stream(s, NULL); if (!ast) return AVERROR(ENOMEM); ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; - ast->codec->codec_id = track->codec_id; - ast->codec->codec_tag = track->compression; - ast->codec->channels = track->channels; - ast->codec->sample_rate = track->sample_rate; - ast->codec->bits_per_coded_sample = track->bits_per_sample; - ast->codec->bit_rate = track->bit_rate; - ast->codec->block_align = 36 * track->channels; + ast->codec->codec_id = packet->codec_id; + ast->codec->codec_tag = packet->compression; + ast->codec->channels = packet->channels; + ast->codec->sample_rate = packet->sample_rate; + ast->codec->bits_per_coded_sample = packet->bits_per_sample; + ast->codec->bit_rate = packet->bit_rate; + ast->codec->block_align = 36 * packet->channels; - avpriv_set_pts_info(ast, 32, track->block_samples, track->sample_rate); + avpriv_set_pts_info(ast, 32, packet->block_samples, packet->sample_rate); packet->stream_index = ast->index; @@ -232,7 +223,7 @@ static int xmv_read_header(AVFormatContext *s) } - /** Initialize the packet context */ + /* Initialize the packet context */ xmv->next_packet_offset = avio_tell(pb); xmv->next_packet_size = this_packet_size - xmv->next_packet_offset; @@ -277,7 +268,7 @@ static int xmv_process_packet_header(AVFormatContext *s) uint8_t data[8]; uint16_t audio_track; - uint32_t data_offset; + uint64_t data_offset; /* Next packet size */ xmv->next_packet_size = avio_rl32(pb); @@ -328,9 +319,9 @@ static int xmv_process_packet_header(AVFormatContext *s) */ packet->data_size = xmv->audio[audio_track - 1].data_size; - /** Carve up the audio data in frame_count slices */ + /* Carve up the audio data in frame_count slices */ packet->frame_size = packet->data_size / xmv->video.frame_count; - packet->frame_size -= packet->frame_size % packet->track->block_align; + packet->frame_size -= packet->frame_size % packet->block_align; } /* Packet data offsets */ @@ -434,7 +425,7 @@ static int xmv_fetch_audio_packet(AVFormatContext *s, /* Calculate the PTS */ - block_count = data_size / audio->track->block_align; + block_count = data_size / audio->block_align; pkt->duration = block_count; pkt->pts = audio->block_count; @@ -459,7 +450,7 @@ static int xmv_fetch_video_packet(AVFormatContext *s, int result; uint32_t frame_header; uint32_t frame_size, frame_timestamp; - uint32_t i; + uint8_t *data, *end; /* Seek to it */ if (avio_seek(pb, video->data_offset, SEEK_SET) != video->data_offset) @@ -474,17 +465,17 @@ static int xmv_fetch_video_packet(AVFormatContext *s, if ((frame_size + 4) > video->data_size) return AVERROR(EIO); - /* Create the packet */ - result = av_new_packet(pkt, frame_size); - if (result) + /* Get the packet data */ + result = av_get_packet(pb, pkt, frame_size); + if (result != frame_size) return result; /* Contrary to normal WMV2 video, the bit stream in XMV's * WMV2 is little-endian. * TODO: This manual swap is of course suboptimal. */ - for (i = 0; i < frame_size; i += 4) - AV_WB32(pkt->data + i, avio_rl32(pb)); + for (data = pkt->data, end = pkt->data + frame_size; data < end; data += 4) + AV_WB32(data, AV_RL32(data)); pkt->stream_index = video->stream_index; @@ -551,7 +542,6 @@ static int xmv_read_close(AVFormatContext *s) XMVDemuxContext *xmv = s->priv_data; av_free(xmv->audio); - av_free(xmv->audio_tracks); return 0; } diff --git a/libavformat/xwma.c b/libavformat/xwma.c index 2c6ee114bd..ea7cc4f36e 100644 --- a/libavformat/xwma.c +++ b/libavformat/xwma.c @@ -2,20 +2,20 @@ * xWMA demuxer * Copyright (c) 2011 Max Horn * - * 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/libavformat/yop.c b/libavformat/yop.c index e50025970d..d1c24fb2fa 100644 --- a/libavformat/yop.c +++ b/libavformat/yop.c @@ -5,20 +5,20 @@ * derived from the code by * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.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 */ @@ -184,8 +184,6 @@ static int yop_read_seek(AVFormatContext *s, int stream_index, int64_t frame_pos, pos_min, pos_max; int frame_count; - av_free_packet(&yop->video_packet); - if (!stream_index) return -1; @@ -196,9 +194,13 @@ static int yop_read_seek(AVFormatContext *s, int stream_index, timestamp = FFMAX(0, FFMIN(frame_count, timestamp)); frame_pos = timestamp * yop->frame_size + pos_min; + + if (avio_seek(s->pb, frame_pos, SEEK_SET) < 0) + return -1; + + av_free_packet(&yop->video_packet); yop->odd_frame = timestamp & 1; - avio_seek(s->pb, frame_pos, SEEK_SET); return 0; } diff --git a/libavformat/yuv4mpeg.c b/libavformat/yuv4mpeg.c index afb5bfaab2..9d34f7d8f3 100644 --- a/libavformat/yuv4mpeg.c +++ b/libavformat/yuv4mpeg.c @@ -2,20 +2,20 @@ * YUV4MPEG format * Copyright (c) 2001, 2002, 2003 Fabrice Bellard * - * 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" @@ -155,6 +155,12 @@ static int yuv4_write_header(AVFormatContext *s) if (s->nb_streams != 1) return AVERROR(EIO); + if (s->streams[0]->codec->codec_id != CODEC_ID_RAWVIDEO) { + av_log(s, AV_LOG_ERROR, + "A non-rawvideo stream was selected, but yuv4mpeg only handles rawvideo streams\n"); + return AVERROR(EINVAL); + } + if (s->streams[0]->codec->pix_fmt == PIX_FMT_YUV411P) { av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV " "stream, some mjpegtools might not work.\n"); @@ -175,7 +181,6 @@ static int yuv4_write_header(AVFormatContext *s) AVOutputFormat ff_yuv4mpegpipe_muxer = { .name = "yuv4mpegpipe", .long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe format"), - .mime_type = "", .extensions = "y4m", .priv_data_size = sizeof(int), .audio_codec = CODEC_ID_NONE, |