diff options
Diffstat (limited to 'contrib/ffmpeg/libavformat')
158 files changed, 17966 insertions, 16876 deletions
diff --git a/contrib/ffmpeg/libavformat/4xm.c b/contrib/ffmpeg/libavformat/4xm.c index bf10b9e82..151e9c9c8 100644 --- a/contrib/ffmpeg/libavformat/4xm.c +++ b/contrib/ffmpeg/libavformat/4xm.c @@ -44,6 +44,9 @@ #define ifrm_TAG MKTAG('i', 'f', 'r', 'm') #define pfrm_TAG MKTAG('p', 'f', 'r', 'm') #define cfrm_TAG MKTAG('c', 'f', 'r', 'm') +#define ifr2_TAG MKTAG('i', 'f', 'r', '2') +#define pfr2_TAG MKTAG('p', 'f', 'r', '2') +#define cfr2_TAG MKTAG('c', 'f', 'r', '2') #define snd__TAG MKTAG('s', 'n', 'd', '_') #define vtrk_SIZE 0x44 @@ -79,9 +82,6 @@ typedef struct FourxmDemuxContext { static int fourxm_probe(AVProbeData *p) { - if (p->buf_size < 12) - return 0; - if ((AV_RL32(&p->buf[0]) != RIFF_TAG) || (AV_RL32(&p->buf[8]) != _4XMV_TAG)) return 0; @@ -92,11 +92,11 @@ static int fourxm_probe(AVProbeData *p) static int fourxm_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; unsigned int fourcc_tag; unsigned int size; int header_size; - FourxmDemuxContext *fourxm = (FourxmDemuxContext *)s->priv_data; + FourxmDemuxContext *fourxm = s->priv_data; unsigned char *header; int i; int current_track = -1; @@ -119,9 +119,9 @@ static int fourxm_read_header(AVFormatContext *s, /* allocate space for the header and load the whole thing */ header = av_malloc(header_size); if (!header) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); if (get_buffer(pb, header, header_size) != header_size) - return AVERROR_IO; + return AVERROR(EIO); /* take the lazy approach and search for any and all vtrk and strk chunks */ for (i = 0; i < header_size - 8; i++) { @@ -138,22 +138,24 @@ static int fourxm_read_header(AVFormatContext *s, } fourxm->width = AV_RL32(&header[i + 36]); fourxm->height = AV_RL32(&header[i + 40]); - i += 8 + size; /* allocate a new AVStream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 60, 1, fourxm->fps); fourxm->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_4XM; - st->codec->codec_tag = 0; /* no fourcc */ + st->codec->extradata_size = 4; + st->codec->extradata = av_malloc(4); + AV_WL32(st->codec->extradata, AV_RL32(&header[i + 16])); st->codec->width = fourxm->width; st->codec->height = fourxm->height; + i += 8 + size; } else if (fourcc_tag == strk_TAG) { /* check that there is enough data */ if (size != strk_SIZE) { @@ -169,7 +171,7 @@ static int fourxm_read_header(AVFormatContext *s, fourxm->track_count * sizeof(AudioTrack)); if (!fourxm->tracks) { av_free(header); - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } } fourxm->tracks[current_track].adpcm = AV_RL32(&header[i + 12]); @@ -181,7 +183,7 @@ static int fourxm_read_header(AVFormatContext *s, /* allocate a new AVStream */ st = av_new_stream(s, current_track); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 60, 1, fourxm->tracks[current_track].sample_rate); @@ -222,7 +224,7 @@ static int fourxm_read_packet(AVFormatContext *s, AVPacket *pkt) { FourxmDemuxContext *fourxm = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; unsigned int fourcc_tag; unsigned int size, out_size; int ret = 0; @@ -233,12 +235,12 @@ static int fourxm_read_packet(AVFormatContext *s, while (!packet_read) { - if ((ret = get_buffer(&s->pb, header, 8)) < 0) + if ((ret = get_buffer(s->pb, header, 8)) < 0) return ret; fourcc_tag = AV_RL32(&header[0]); size = AV_RL32(&header[4]); if (url_feof(pb)) - return AVERROR_IO; + return AVERROR(EIO); switch (fourcc_tag) { case LIST_TAG: @@ -251,17 +253,21 @@ static int fourxm_read_packet(AVFormatContext *s, case ifrm_TAG: case pfrm_TAG: - case cfrm_TAG:{ + case cfrm_TAG: + case ifr2_TAG: + case pfr2_TAG: + case cfr2_TAG: + { /* allocate 8 more bytes than 'size' to account for fourcc * and size */ if (size + 8 < size || av_new_packet(pkt, size + 8)) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = fourxm->video_stream_index; pkt->pts = fourxm->video_pts; - pkt->pos = url_ftell(&s->pb); + pkt->pos = url_ftell(s->pb); memcpy(pkt->data, header, 8); - ret = get_buffer(&s->pb, &pkt->data[8], size); + ret = get_buffer(s->pb, &pkt->data[8], size); if (ret < 0) av_free_packet(pkt); @@ -276,9 +282,9 @@ static int fourxm_read_packet(AVFormatContext *s, size-=8; if (track_number == fourxm->selected_track) { - ret= av_get_packet(&s->pb, pkt, size); + ret= av_get_packet(s->pb, pkt, size); if(ret<0) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = fourxm->tracks[fourxm->selected_track].stream_index; pkt->pts = fourxm->audio_pts; @@ -313,7 +319,7 @@ static int fourxm_read_packet(AVFormatContext *s, static int fourxm_read_close(AVFormatContext *s) { - FourxmDemuxContext *fourxm = (FourxmDemuxContext *)s->priv_data; + FourxmDemuxContext *fourxm = s->priv_data; av_free(fourxm->tracks); diff --git a/contrib/ffmpeg/libavformat/Makefile b/contrib/ffmpeg/libavformat/Makefile index f1339bd9d..041f224a7 100644 --- a/contrib/ffmpeg/libavformat/Makefile +++ b/contrib/ffmpeg/libavformat/Makefile @@ -4,135 +4,175 @@ # include ../config.mak -CFLAGS+=-I$(SRC_PATH)/libavcodec +CFLAGS += -I$(SRC_PATH)/libavcodec -OBJS= utils.o cutils.o os_support.o allformats.o +OBJS = allformats.o cutils.o os_support.o sdp.o utils.o -HEADERS = avformat.h avio.h rtp.h rtsp.h rtspcodes.h +HEADERS = avformat.h avio.h rtsp.h rtspcodes.h # muxers/demuxers -OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o +OBJS-$(CONFIG_AAC_DEMUXER) += raw.o +OBJS-$(CONFIG_AC3_DEMUXER) += raw.o +OBJS-$(CONFIG_AC3_MUXER) += raw.o OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o -OBJS-$(CONFIG_AIFF_DEMUXER) += aiff.o riff.o +OBJS-$(CONFIG_AIFF_DEMUXER) += aiff.o riff.o raw.o OBJS-$(CONFIG_AIFF_MUXER) += aiff.o riff.o OBJS-$(CONFIG_AMR_DEMUXER) += amr.o OBJS-$(CONFIG_AMR_MUXER) += amr.o -OBJS-$(CONFIG_ASF_DEMUXER) += asf.o riff.o +OBJS-$(CONFIG_APC_DEMUXER) += apc.o +OBJS-$(CONFIG_APE_DEMUXER) += ape.o +OBJS-$(CONFIG_ASF_DEMUXER) += asf.o asfcrypt.o riff.o OBJS-$(CONFIG_ASF_MUXER) += asf-enc.o riff.o OBJS-$(CONFIG_ASF_STREAM_MUXER) += asf-enc.o riff.o -OBJS-$(CONFIG_AU_DEMUXER) += au.o riff.o -OBJS-$(CONFIG_AU_MUXER) += au.o riff.o +OBJS-$(CONFIG_AU_DEMUXER) += au.o raw.o +OBJS-$(CONFIG_AU_MUXER) += au.o OBJS-$(CONFIG_AVI_DEMUXER) += avidec.o riff.o OBJS-$(CONFIG_AVI_MUXER) += avienc.o riff.o OBJS-$(CONFIG_AVISYNTH) += avisynth.o -OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o riff.o -OBJS-$(CONFIG_CRC_MUXER) += crc.o -OBJS-$(CONFIG_FRAMECRC_MUXER) += crc.o +OBJS-$(CONFIG_AVM2_MUXER) += swf.o +OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o +OBJS-$(CONFIG_BETHSOFTVID_DEMUXER) += bethsoftvid.o +OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o +OBJS-$(CONFIG_CRC_MUXER) += crcenc.o OBJS-$(CONFIG_DAUD_DEMUXER) += daud.o -OBJS-$(CONFIG_DC1394_DEMUXER) += dc1394.o OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o +OBJS-$(CONFIG_DTS_DEMUXER) += raw.o OBJS-$(CONFIG_DV_DEMUXER) += dv.o OBJS-$(CONFIG_DV_MUXER) += dvenc.o -OBJS-$(CONFIG_DV1394_DEMUXER) += dv1394.o -OBJS-$(CONFIG_DXA_DEMUXER) += dxa.o +OBJS-$(CONFIG_DXA_DEMUXER) += dxa.o riff.o +OBJS-$(CONFIG_EA_CDATA_DEMUXER) += eacdata.o OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o OBJS-$(CONFIG_FFM_DEMUXER) += ffm.o OBJS-$(CONFIG_FFM_MUXER) += ffm.o +OBJS-$(CONFIG_FLAC_DEMUXER) += raw.o +OBJS-$(CONFIG_FLAC_MUXER) += raw.o OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o OBJS-$(CONFIG_FLV_MUXER) += flvenc.o +OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o +OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o OBJS-$(CONFIG_GIF_MUXER) += gif.o OBJS-$(CONFIG_GIF_DEMUXER) += gifdec.o OBJS-$(CONFIG_GXF_DEMUXER) += gxf.o OBJS-$(CONFIG_GXF_MUXER) += gxfenc.o +OBJS-$(CONFIG_H261_DEMUXER) += raw.o +OBJS-$(CONFIG_H261_MUXER) += raw.o +OBJS-$(CONFIG_H263_DEMUXER) += raw.o +OBJS-$(CONFIG_H263_MUXER) += raw.o +OBJS-$(CONFIG_H264_DEMUXER) += raw.o +OBJS-$(CONFIG_H264_MUXER) += raw.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o -OBJS-$(CONFIG_ROQ_DEMUXER) += idroq.o OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2.o -OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2.o OBJS-$(CONFIG_IMAGE2_MUXER) += img2.o +OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2.o OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2.o +OBJS-$(CONFIG_INGENIENT_DEMUXER) += raw.o OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o -OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroska.o riff.o +OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o +OBJS-$(CONFIG_M4V_DEMUXER) += raw.o +OBJS-$(CONFIG_M4V_MUXER) += raw.o +OBJS-$(CONFIG_MATROSKA_AUDIO_MUXER) += matroskaenc.o matroska.o riff.o avc.o +OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o riff.o +OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o riff.o avc.o +OBJS-$(CONFIG_MJPEG_DEMUXER) += raw.o +OBJS-$(CONFIG_MJPEG_MUXER) += raw.o OBJS-$(CONFIG_MM_DEMUXER) += mm.o -OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o riff.o +OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o raw.o OBJS-$(CONFIG_MMF_MUXER) += mmf.o riff.o OBJS-$(CONFIG_MOV_DEMUXER) += mov.o riff.o isom.o -OBJS-$(CONFIG_MOV_MUXER) += movenc.o riff.o isom.o -OBJS-$(CONFIG_TGP_MUXER) += movenc.o riff.o isom.o -OBJS-$(CONFIG_MP4_MUXER) += movenc.o riff.o isom.o -OBJS-$(CONFIG_PSP_MUXER) += movenc.o riff.o isom.o -OBJS-$(CONFIG_TG2_MUXER) += movenc.o riff.o isom.o -OBJS-$(CONFIG_MP3_DEMUXER) += mp3.o +OBJS-$(CONFIG_MOV_MUXER) += movenc.o riff.o isom.o avc.o OBJS-$(CONFIG_MP2_MUXER) += mp3.o +OBJS-$(CONFIG_MP3_DEMUXER) += mp3.o OBJS-$(CONFIG_MP3_MUXER) += mp3.o +OBJS-$(CONFIG_MP4_MUXER) += movenc.o riff.o isom.o avc.o OBJS-$(CONFIG_MPC_DEMUXER) += mpc.o -OBJS-$(CONFIG_MPEG1SYSTEM_MUXER) += mpeg.o -OBJS-$(CONFIG_MPEG1VCD_MUXER) += mpeg.o -OBJS-$(CONFIG_MPEG2VOB_MUXER) += mpeg.o -OBJS-$(CONFIG_MPEG2SVCD_MUXER) += mpeg.o -OBJS-$(CONFIG_MPEG2DVD_MUXER) += mpeg.o +OBJS-$(CONFIG_MPC8_DEMUXER) += mpc8.o +OBJS-$(CONFIG_MPEG1SYSTEM_MUXER) += mpegenc.o +OBJS-$(CONFIG_MPEG1VCD_MUXER) += mpegenc.o +OBJS-$(CONFIG_MPEG2DVD_MUXER) += mpegenc.o +OBJS-$(CONFIG_MPEG2VOB_MUXER) += mpegenc.o +OBJS-$(CONFIG_MPEG2SVCD_MUXER) += mpegenc.o +OBJS-$(CONFIG_MPEG1VIDEO_MUXER) += raw.o +OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += raw.o OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o +OBJS-$(CONFIG_MPEGTSRAW_DEMUXER) += mpegts.o OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o +OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += raw.o OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o OBJS-$(CONFIG_MTV_DEMUXER) += mtv.o OBJS-$(CONFIG_MXF_DEMUXER) += mxf.o -OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o riff.o +OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o +OBJS-$(CONFIG_NULL_MUXER) += raw.o +OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o riff.o +OBJS-$(CONFIG_NUT_MUXER) += nutenc.o nut.o riff.o OBJS-$(CONFIG_NUV_DEMUXER) += nuv.o riff.o -OBJS-$(CONFIG_OGG_DEMUXER) += ogg2.o \ - oggparsevorbis.o \ - oggparsetheora.o \ +OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ oggparseflac.o \ oggparseogm.o \ + oggparsespeex.o \ + oggparsetheora.o \ + oggparsevorbis.o \ riff.o -OBJS-$(CONFIG_OGG_MUXER) += ogg.o -OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o -OBJS-$(CONFIG_SHORTEN_DEMUXER) += raw.o -OBJS-$(CONFIG_FLAC_DEMUXER) += raw.o -OBJS-$(CONFIG_FLAC_MUXER) += raw.o -OBJS-$(CONFIG_AC3_DEMUXER) += raw.o -OBJS-$(CONFIG_AC3_MUXER) += raw.o -OBJS-$(CONFIG_DTS_DEMUXER) += raw.o -OBJS-$(CONFIG_AAC_DEMUXER) += raw.o -OBJS-$(CONFIG_H261_DEMUXER) += raw.o -OBJS-$(CONFIG_H261_MUXER) += raw.o -OBJS-$(CONFIG_H263_DEMUXER) += raw.o -OBJS-$(CONFIG_H263_MUXER) += raw.o -OBJS-$(CONFIG_M4V_DEMUXER) += raw.o -OBJS-$(CONFIG_M4V_MUXER) += raw.o -OBJS-$(CONFIG_H264_DEMUXER) += raw.o -OBJS-$(CONFIG_H264_MUXER) += raw.o -OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += raw.o -OBJS-$(CONFIG_MPEG1VIDEO_MUXER) += raw.o -OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += raw.o -OBJS-$(CONFIG_MJPEG_DEMUXER) += raw.o -OBJS-$(CONFIG_INGENIENT_DEMUXER) += raw.o -OBJS-$(CONFIG_MJPEG_MUXER) += raw.o +OBJS-$(CONFIG_OGG_MUXER) += oggenc.o +OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_ALAW_MUXER) += raw.o +OBJS-$(CONFIG_PCM_MULAW_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_MULAW_MUXER) += raw.o +OBJS-$(CONFIG_PCM_S16BE_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_S16BE_MUXER) += raw.o +OBJS-$(CONFIG_PCM_S16LE_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_S16LE_MUXER) += raw.o +OBJS-$(CONFIG_PCM_S8_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_S8_MUXER) += raw.o +OBJS-$(CONFIG_PCM_U16BE_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_U16BE_MUXER) += raw.o +OBJS-$(CONFIG_PCM_U16LE_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_U16LE_MUXER) += raw.o +OBJS-$(CONFIG_PCM_U8_DEMUXER) += raw.o +OBJS-$(CONFIG_PCM_U8_MUXER) += raw.o +OBJS-$(CONFIG_PSP_MUXER) += movenc.o riff.o isom.o avc.o +OBJS-$(CONFIG_PVA_DEMUXER) += pva.o OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += raw.o OBJS-$(CONFIG_RAWVIDEO_MUXER) += raw.o -OBJS-$(CONFIG_NULL_MUXER) += raw.o -OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o riff.o -OBJS-$(CONFIG_RM_DEMUXER) += rm.o -OBJS-$(CONFIG_RM_MUXER) += rm.o +OBJS-$(CONFIG_REDIR_DEMUXER) += rtsp.o +OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o +OBJS-$(CONFIG_RM_MUXER) += rmenc.o +OBJS-$(CONFIG_ROQ_DEMUXER) += idroq.o +OBJS-$(CONFIG_ROQ_MUXER) += raw.o +OBJS-$(CONFIG_RTP_MUXER) += rtp.o \ + rtpenc.o \ + rtp_mpv.o \ + rtp_aac.o \ + rtpenc_h264.o \ + avc.o +OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o +OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o rtp.o rtpdec.o rtp_h264.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o -OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o +OBJS-$(CONFIG_SHORTEN_DEMUXER) += raw.o +OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o OBJS-$(CONFIG_SMACKER_DEMUXER) += smacker.o -OBJS-$(CONFIG_SOL_DEMUXER) += sol.o +OBJS-$(CONFIG_SOL_DEMUXER) += sol.o raw.o +OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o OBJS-$(CONFIG_SWF_DEMUXER) += swf.o OBJS-$(CONFIG_SWF_MUXER) += swf.o +OBJS-$(CONFIG_TG2_MUXER) += movenc.o riff.o isom.o avc.o +OBJS-$(CONFIG_TGP_MUXER) += movenc.o riff.o isom.o avc.o OBJS-$(CONFIG_THP_DEMUXER) += thp.o OBJS-$(CONFIG_TIERTEXSEQ_DEMUXER) += tiertexseq.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o -OBJS-$(CONFIG_V4L2_DEMUXER) += v4l2.o -OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o riff.o -OBJS-$(CONFIG_VOC_MUXER) += vocenc.o voc.o riff.o -OBJS-$(CONFIG_WAV_DEMUXER) += wav.o riff.o +OBJS-$(CONFIG_TXD_DEMUXER) += txd.o +OBJS-$(CONFIG_VC1_DEMUXER) += raw.o +OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o +OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o +OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o +OBJS-$(CONFIG_VOC_MUXER) += vocenc.o voc.o +OBJS-$(CONFIG_WAV_DEMUXER) += wav.o riff.o raw.o OBJS-$(CONFIG_WAV_MUXER) += wav.o riff.o OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood.o OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood.o OBJS-$(CONFIG_WV_DEMUXER) += wv.o -OBJS-$(CONFIG_X11_GRAB_DEVICE_DEMUXER) += x11grab.o OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o @@ -140,37 +180,20 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o riff.o OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o riff.o -OBJS+= framehook.o - -ifeq ($(CONFIG_V4L),yes) -OBJS-$(CONFIG_VIDEO_GRAB_DEVICE_DEMUXER) += grab.o -endif - -ifeq ($(CONFIG_BKTR),yes) -OBJS-$(CONFIG_VIDEO_GRAB_DEVICE_DEMUXER) += grab_bktr.o -endif - -ifeq ($(CONFIG_AUDIO_OSS),yes) -OBJS-$(CONFIG_AUDIO_DEMUXER) += audio.o -OBJS-$(CONFIG_AUDIO_MUXER) += audio.o -endif - -EXTRALIBS := -L$(BUILD_ROOT)/libavutil -lavutil$(BUILDSUF) \ - -lavcodec$(BUILDSUF) -L$(BUILD_ROOT)/libavcodec $(EXTRALIBS) +OBJS-$(CONFIG_VHOOK) += framehook.o -ifeq ($(CONFIG_AUDIO_BEOS),yes) -CPPOBJS+= beosaudio.o -endif +EXTRALIBS := -L$(BUILD_ROOT)/libavcodec -lavcodec$(BUILDSUF) \ + -L$(BUILD_ROOT)/libavutil -lavutil$(BUILDSUF) $(EXTRALIBS) # protocols I/O OBJS+= avio.o aviobuf.o -ifeq ($(CONFIG_PROTOCOLS),yes) -OBJS+= file.o -ifeq ($(CONFIG_NETWORK),yes) -OBJS+= udp.o tcp.o http.o rtsp.o rtp.o rtpproto.o mpegts.o rtp_h264.o -endif -endif +OBJS-$(CONFIG_FILE_PROTOCOL) += file.o +OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o +OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o +OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o +OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o +OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o NAME=avformat LIBVERSION=$(LAVFVERSION) diff --git a/contrib/ffmpeg/libavformat/adtsenc.c b/contrib/ffmpeg/libavformat/adtsenc.c index 1ef683838..1949fcf54 100644 --- a/contrib/ffmpeg/libavformat/adtsenc.c +++ b/contrib/ffmpeg/libavformat/adtsenc.c @@ -1,7 +1,7 @@ /* * ADTS muxer. * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com> - * Mans Rullgard <mru@inprovide.com> + * Mans Rullgard <mans@mansr.com> * * This file is part of FFmpeg. * @@ -84,20 +84,15 @@ static int adts_write_frame_header(AVFormatContext *s, int size) put_bits(&pb, 2, 0); /* number_of_raw_data_blocks_in_frame */ flush_put_bits(&pb); - put_buffer(&s->pb, buf, ADTS_HEADER_SIZE); + put_buffer(s->pb, buf, ADTS_HEADER_SIZE); return 0; } -static int adts_write_trailer(AVFormatContext *s) -{ - return 0; -} - static int adts_write_packet(AVFormatContext *s, AVPacket *pkt) { ADTSContext *adts = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; if (!pkt->size) return 0; @@ -119,5 +114,4 @@ AVOutputFormat adts_muxer = { CODEC_ID_NONE, adts_write_header, adts_write_packet, - adts_write_trailer, }; diff --git a/contrib/ffmpeg/libavformat/aiff.c b/contrib/ffmpeg/libavformat/aiff.c index 868d55219..91be89b30 100644 --- a/contrib/ffmpeg/libavformat/aiff.c +++ b/contrib/ffmpeg/libavformat/aiff.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "allformats.h" +#include "raw.h" #include "riff.h" #include "intfloat_readwrite.h" @@ -29,13 +29,14 @@ static const AVCodecTag codec_aiff_tags[] = { { CODEC_ID_PCM_S24BE, MKTAG('N','O','N','E') }, { CODEC_ID_PCM_S32BE, MKTAG('N','O','N','E') }, { CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') }, - { CODEC_ID_PCM_ALAW, MKTAG('A','L','A','W') }, { CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') }, - { CODEC_ID_PCM_MULAW, MKTAG('U','L','A','W') }, { CODEC_ID_MACE3, MKTAG('M','A','C','3') }, { CODEC_ID_MACE6, MKTAG('M','A','C','6') }, { CODEC_ID_GSM, MKTAG('G','S','M',' ') }, { CODEC_ID_ADPCM_G726, MKTAG('G','7','2','6') }, + { CODEC_ID_PCM_S16LE, MKTAG('s','o','w','t') }, + { CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') }, + { CODEC_ID_QDM2, MKTAG('Q','D','M','2') }, { 0, 0 }, }; @@ -63,7 +64,7 @@ static int get_tag(ByteIOContext *pb, uint32_t * tag) int size; if (url_feof(pb)) - return AVERROR_IO; + return AVERROR(EIO); *tag = get_le32(pb); size = get_be32(pb); @@ -103,10 +104,8 @@ static unsigned int get_aiff_header(ByteIOContext *pb, AVCodecContext *codec, double sample_rate; unsigned int num_frames; - if (size & 1) size++; - codec->codec_type = CODEC_TYPE_AUDIO; codec->channels = get_be16(pb); num_frames = get_be32(pb); @@ -120,17 +119,28 @@ static unsigned int get_aiff_header(ByteIOContext *pb, AVCodecContext *codec, /* Got an AIFF-C? */ if (version == AIFF_C_VERSION1) { codec->codec_tag = get_le32(pb); - codec->codec_id = codec_get_id (codec_aiff_tags, codec->codec_tag); + codec->codec_id = codec_get_id(codec_aiff_tags, codec->codec_tag); - if (codec->codec_id == CODEC_ID_PCM_S16BE) { - codec->codec_id = aiff_codec_get_id (codec->bits_per_sample); + switch (codec->codec_id) { + case CODEC_ID_PCM_S16BE: + codec->codec_id = aiff_codec_get_id(codec->bits_per_sample); codec->bits_per_sample = av_get_bits_per_sample(codec->codec_id); + break; + case CODEC_ID_ADPCM_IMA_QT: + codec->block_align = 34*codec->channels; + codec->frame_size = 64; + break; + case CODEC_ID_MACE3: + case CODEC_ID_MACE6: + codec->frame_size = 6; + break; + default: + break; } - size -= 4; } else { /* Need the codec type */ - codec->codec_id = aiff_codec_get_id (codec->bits_per_sample); + codec->codec_id = aiff_codec_get_id(codec->bits_per_sample); codec->bits_per_sample = av_get_bits_per_sample(codec->codec_id); } @@ -139,7 +149,8 @@ static unsigned int get_aiff_header(ByteIOContext *pb, AVCodecContext *codec, /* Block align needs to be computed in all cases, as the definition * is specific to applications -> here we use the WAVE format definition */ - codec->block_align = (codec->bits_per_sample * codec->channels) >> 3; + if (!codec->block_align) + codec->block_align = (codec->bits_per_sample * codec->channels) >> 3; codec->bit_rate = codec->sample_rate * (codec->block_align << 3); @@ -160,16 +171,14 @@ typedef struct { static int aiff_write_header(AVFormatContext *s) { AIFFOutputContext *aiff = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[0]->codec; AVExtFloat sample_rate; int aifc = 0; /* First verify if format is ok */ - if (!enc->codec_tag) { + if (!enc->codec_tag) return -1; - } - if (enc->codec_tag != MKTAG('N','O','N','E')) aifc = 1; @@ -179,7 +188,12 @@ static int aiff_write_header(AVFormatContext *s) put_be32(pb, 0); /* file length */ put_tag(pb, aifc ? "AIFC" : "AIFF"); - if (aifc) { + if (aifc) { // compressed audio + enc->bits_per_sample = 16; + if (!enc->block_align) { + av_log(s, AV_LOG_ERROR, "block align not set\n"); + return -1; + } /* Version chunk */ put_tag(pb, "FVER"); put_be32(pb, 4); @@ -189,10 +203,10 @@ static int aiff_write_header(AVFormatContext *s) /* Common chunk */ put_tag(pb, "COMM"); put_be32(pb, aifc ? 24 : 18); /* size */ - put_be16(pb, enc->channels); /* Number of channels */ + put_be16(pb, enc->channels); /* Number of channels */ aiff->frames = url_ftell(pb); - put_be32(pb, 0); /* Number of frames */ + put_be32(pb, 0); /* Number of frames */ if (!enc->bits_per_sample) enc->bits_per_sample = av_get_bits_per_sample(enc->codec_id); @@ -230,14 +244,14 @@ static int aiff_write_header(AVFormatContext *s) static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; put_buffer(pb, pkt->data, pkt->size); return 0; } static int aiff_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AIFFOutputContext *aiff = s->priv_data; AVCodecContext *enc = s->streams[0]->codec; @@ -249,18 +263,18 @@ static int aiff_write_trailer(AVFormatContext *s) end_size++; } - if (!url_is_streamed(&s->pb)) { + if (!url_is_streamed(s->pb)) { /* File length */ url_fseek(pb, aiff->form, SEEK_SET); - put_be32(pb, (uint32_t)(file_size - aiff->form - 4)); + put_be32(pb, file_size - aiff->form - 4); /* Number of sample frames */ url_fseek(pb, aiff->frames, SEEK_SET); - put_be32(pb, ((uint32_t)(file_size-aiff->ssnd-12))/enc->block_align); + put_be32(pb, (file_size-aiff->ssnd-12)/enc->block_align); /* Sound Data chunk size */ url_fseek(pb, aiff->ssnd, SEEK_SET); - put_be32(pb, (uint32_t)(file_size - aiff->ssnd - 4)); + put_be32(pb, file_size - aiff->ssnd - 4); /* return to the end */ url_fseek(pb, end_size, SEEK_SET); @@ -275,8 +289,6 @@ static int aiff_write_trailer(AVFormatContext *s) static int aiff_probe(AVProbeData *p) { /* check file header */ - if (p->buf_size < 16) - return 0; if (p->buf[0] == 'F' && p->buf[1] == 'O' && p->buf[2] == 'R' && p->buf[3] == 'M' && p->buf[8] == 'A' && p->buf[9] == 'I' && @@ -290,10 +302,11 @@ static int aiff_probe(AVProbeData *p) static int aiff_read_header(AVFormatContext *s, AVFormatParameters *ap) { - int size, filesize, offset; + int size, filesize; + offset_t offset = 0; uint32_t tag; unsigned version = AIFF_C_VERSION1; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream * st = s->streams[0]; /* check FORM header */ @@ -312,7 +325,7 @@ static int aiff_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); while (filesize > 0) { /* parse different chunks */ @@ -323,42 +336,54 @@ static int aiff_read_header(AVFormatContext *s, filesize -= size + 8; switch (tag) { - case MKTAG('C', 'O', 'M', 'M'): /* Common chunk */ - /* Then for the complete header info */ - st->nb_frames = get_aiff_header (pb, st->codec, size, version); - if (st->nb_frames < 0) - return st->nb_frames; - break; - - case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */ - version = get_be32(pb); - break; - - case MKTAG('N', 'A', 'M', 'E'): /* Sample name chunk */ - get_meta (pb, s->title, sizeof(s->title), size); - break; - - case MKTAG('A', 'U', 'T', 'H'): /* Author chunk */ - get_meta (pb, s->author, sizeof(s->author), size); - break; - - case MKTAG('(', 'c', ')', ' '): /* Copyright chunk */ - get_meta (pb, s->copyright, sizeof(s->copyright), size); - break; - - case MKTAG('A', 'N', 'N', 'O'): /* Annotation chunk */ - get_meta (pb, s->comment, sizeof(s->comment), size); - break; - - case MKTAG('S', 'S', 'N', 'D'): /* Sampled sound chunk */ - get_be32(pb); /* Block align... don't care */ - offset = get_be32(pb); /* Offset of sound data */ + case MKTAG('C', 'O', 'M', 'M'): /* Common chunk */ + /* Then for the complete header info */ + st->nb_frames = get_aiff_header (pb, st->codec, size, version); + if (st->nb_frames < 0) + return st->nb_frames; + if (offset > 0) // COMM is after SSND goto got_sound; - - default: /* Jump */ - if (size & 1) /* Always even aligned */ - size++; - url_fskip (pb, size); + break; + case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */ + version = get_be32(pb); + break; + case MKTAG('N', 'A', 'M', 'E'): /* Sample name chunk */ + get_meta (pb, s->title, sizeof(s->title), size); + break; + case MKTAG('A', 'U', 'T', 'H'): /* Author chunk */ + get_meta (pb, s->author, sizeof(s->author), size); + break; + case MKTAG('(', 'c', ')', ' '): /* Copyright chunk */ + get_meta (pb, s->copyright, sizeof(s->copyright), size); + break; + case MKTAG('A', 'N', 'N', 'O'): /* Annotation chunk */ + get_meta (pb, s->comment, sizeof(s->comment), size); + break; + case MKTAG('S', 'S', 'N', 'D'): /* Sampled sound chunk */ + offset = get_be32(pb); /* Offset of sound data */ + get_be32(pb); /* BlockSize... don't care */ + offset += url_ftell(pb); /* Compute absolute data offset */ + if (st->codec->codec_id) /* Assume COMM already parsed */ + goto got_sound; + if (url_is_streamed(pb)) { + av_log(s, AV_LOG_ERROR, "file is not seekable\n"); + return -1; + } + url_fskip(pb, size - 8); + break; + case MKTAG('w', 'a', 'v', 'e'): + if ((uint64_t)size > (1<<30)) + return -1; + st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata_size = size; + get_buffer(pb, st->codec->extradata, size); + break; + default: /* Jump */ + if (size & 1) /* Always even aligned */ + size++; + url_fskip (pb, size); } } @@ -372,10 +397,11 @@ got_sound: av_set_pts_info(st, 64, 1, st->codec->sample_rate); st->start_time = 0; - st->duration = st->nb_frames; + st->duration = st->codec->frame_size ? + st->nb_frames * st->codec->frame_size : st->nb_frames; /* Position the stream at the first block */ - url_fskip(pb, offset); + url_fseek(pb, offset, SEEK_SET); return 0; } @@ -389,11 +415,11 @@ static int aiff_read_packet(AVFormatContext *s, int res; /* End of stream may be reached */ - if (url_feof(&s->pb)) - return AVERROR_IO; + if (url_feof(s->pb)) + return AVERROR(EIO); /* Now for that packet */ - res = av_get_packet(&s->pb, pkt, (MAX_SIZE / st->codec->block_align) * st->codec->block_align); + res = av_get_packet(s->pb, pkt, (MAX_SIZE / st->codec->block_align) * st->codec->block_align); if (res < 0) return res; @@ -402,11 +428,6 @@ static int aiff_read_packet(AVFormatContext *s, return 0; } -static int aiff_read_close(AVFormatContext *s) -{ - return 0; -} - static int aiff_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { @@ -421,7 +442,7 @@ AVInputFormat aiff_demuxer = { aiff_probe, aiff_read_header, aiff_read_packet, - aiff_read_close, + NULL, aiff_read_seek, .codec_tag= (const AVCodecTag*[]){codec_aiff_tags, 0}, }; diff --git a/contrib/ffmpeg/libavformat/allformats.c b/contrib/ffmpeg/libavformat/allformats.c index 8534a18f6..5cafd6209 100644 --- a/contrib/ffmpeg/libavformat/allformats.c +++ b/contrib/ffmpeg/libavformat/allformats.c @@ -19,13 +19,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "allformats.h" +#include "rtp_internal.h" -#define REGISTER_MUXER(X,x) \ - if(ENABLE_##X##_MUXER) av_register_output_format(&x##_muxer) -#define REGISTER_DEMUXER(X,x) \ - if(ENABLE_##X##_DEMUXER) av_register_input_format(&x##_demuxer) +#define REGISTER_MUXER(X,x) { \ + extern AVOutputFormat x##_muxer; \ + if(ENABLE_##X##_MUXER) av_register_output_format(&x##_muxer); } +#define REGISTER_DEMUXER(X,x) { \ + extern AVInputFormat x##_demuxer; \ + if(ENABLE_##X##_DEMUXER) av_register_input_format(&x##_demuxer); } #define REGISTER_MUXDEMUX(X,x) REGISTER_MUXER(X,x); REGISTER_DEMUXER(X,x) +#define REGISTER_PROTOCOL(X,x) { \ + extern URLProtocol x##_protocol; \ + if(ENABLE_##X##_PROTOCOL) register_protocol(&x##_protocol); } /* If you do not call this function, then you can select exactly which formats you want to support */ @@ -35,138 +40,140 @@ */ void av_register_all(void) { - static int inited = 0; + static int initialized; - if (inited != 0) + if (initialized) return; - inited = 1; + initialized = 1; avcodec_init(); avcodec_register_all(); - REGISTER_DEMUXER (AAC, aac); - REGISTER_MUXDEMUX(AC3, ac3); - REGISTER_MUXER (ADTS, adts); - REGISTER_MUXDEMUX(AIFF, aiff); - REGISTER_MUXDEMUX(AMR, amr); - REGISTER_MUXDEMUX(ASF, asf); - REGISTER_MUXER (ASF_STREAM, asf_stream); - REGISTER_MUXDEMUX(AU, au); - REGISTER_MUXDEMUX(AUDIO, audio); - REGISTER_MUXDEMUX(AVI, avi); -#ifdef CONFIG_AVISYNTH - av_register_input_format(&avisynth_demuxer); -#endif - REGISTER_DEMUXER (AVS, avs); - REGISTER_MUXER (CRC, crc); - REGISTER_DEMUXER (DAUD, daud); - REGISTER_DEMUXER (DC1394, dc1394); - REGISTER_DEMUXER (DSICIN, dsicin); - REGISTER_DEMUXER (DTS, dts); - REGISTER_MUXDEMUX(DV, dv); - REGISTER_DEMUXER (DV1394, dv1394); - REGISTER_DEMUXER (DXA, dxa); - REGISTER_DEMUXER (EA, ea); - REGISTER_MUXDEMUX(FFM, ffm); - REGISTER_MUXDEMUX(FLAC, flac); - REGISTER_DEMUXER (FLIC, flic); - REGISTER_MUXDEMUX(FLV, flv); - REGISTER_DEMUXER (FOURXM, fourxm); - REGISTER_MUXER (FRAMECRC, framecrc); - REGISTER_MUXDEMUX(GIF, gif); - REGISTER_DEMUXER (GXF, gxf); - REGISTER_MUXER (GXF, gxf); - REGISTER_MUXDEMUX(H261, h261); - REGISTER_MUXDEMUX(H263, h263); - REGISTER_MUXDEMUX(H264, h264); - REGISTER_DEMUXER (IDCIN, idcin); - REGISTER_MUXDEMUX(IMAGE2, image2); - REGISTER_MUXDEMUX(IMAGE2PIPE, image2pipe); - REGISTER_DEMUXER (INGENIENT, ingenient); - REGISTER_DEMUXER (IPMOVIE, ipmovie); - if (!ENABLE_NUT_DEMUXER) REGISTER_DEMUXER (LIBNUT, libnut); - REGISTER_MUXER (LIBNUT, libnut); - REGISTER_MUXDEMUX(M4V, m4v); - REGISTER_DEMUXER (MATROSKA, matroska); - REGISTER_MUXDEMUX(MJPEG, mjpeg); - REGISTER_DEMUXER (MM, mm); - REGISTER_MUXDEMUX(MMF, mmf); - REGISTER_MUXDEMUX(MOV, mov); - REGISTER_MUXER (MP2, mp2); - REGISTER_MUXDEMUX(MP3, mp3); - REGISTER_MUXER (MP4, mp4); - REGISTER_DEMUXER (MPC, mpc); - REGISTER_MUXER (MPEG1SYSTEM, mpeg1system); - REGISTER_MUXER (MPEG1VCD, mpeg1vcd); - REGISTER_MUXER (MPEG1VIDEO, mpeg1video); - REGISTER_MUXER (MPEG2DVD, mpeg2dvd); - REGISTER_MUXER (MPEG2SVCD, mpeg2svcd); - REGISTER_MUXER (MPEG2VIDEO, mpeg2video); - REGISTER_MUXER (MPEG2VOB, mpeg2vob); - REGISTER_DEMUXER (MPEGPS, mpegps); - REGISTER_MUXDEMUX(MPEGTS, mpegts); - REGISTER_DEMUXER (MPEGVIDEO, mpegvideo); - REGISTER_MUXER (MPJPEG, mpjpeg); - REGISTER_DEMUXER (MTV, mtv); - REGISTER_DEMUXER (MXF, mxf); - REGISTER_DEMUXER (NSV, nsv); - REGISTER_MUXER (NULL, null); - REGISTER_DEMUXER (NUT, nut); - REGISTER_DEMUXER (NUV, nuv); - REGISTER_DEMUXER (OGG, ogg); - REGISTER_MUXER (OGG, ogg); - REGISTER_MUXDEMUX(PCM_ALAW, pcm_alaw); - REGISTER_MUXDEMUX(PCM_MULAW, pcm_mulaw); - REGISTER_MUXDEMUX(PCM_S16BE, pcm_s16be); - REGISTER_MUXDEMUX(PCM_S16LE, pcm_s16le); - REGISTER_MUXDEMUX(PCM_S8, pcm_s8); - REGISTER_MUXDEMUX(PCM_U16BE, pcm_u16be); - REGISTER_MUXDEMUX(PCM_U16LE, pcm_u16le); - REGISTER_MUXDEMUX(PCM_U8, pcm_u8); - REGISTER_MUXER (PSP, psp); - REGISTER_MUXDEMUX(RAWVIDEO, rawvideo); - REGISTER_MUXDEMUX(RM, rm); - REGISTER_DEMUXER (ROQ, roq); - REGISTER_DEMUXER (REDIR, redir); - REGISTER_MUXER (RTP, rtp); - REGISTER_DEMUXER (RTSP, rtsp); - REGISTER_DEMUXER (SDP, sdp); -#ifdef CONFIG_NETWORK + /* (de)muxers */ + REGISTER_DEMUXER (AAC, aac); + REGISTER_MUXDEMUX (AC3, ac3); + REGISTER_MUXER (ADTS, adts); + REGISTER_MUXDEMUX (AIFF, aiff); + REGISTER_MUXDEMUX (AMR, amr); + REGISTER_DEMUXER (APC, apc); + REGISTER_DEMUXER (APE, ape); + REGISTER_MUXDEMUX (ASF, asf); + REGISTER_MUXER (ASF_STREAM, asf_stream); + REGISTER_MUXDEMUX (AU, au); + REGISTER_MUXDEMUX (AVI, avi); + REGISTER_DEMUXER (AVISYNTH, avisynth); + REGISTER_MUXER (AVM2, avm2); + REGISTER_DEMUXER (AVS, avs); + REGISTER_DEMUXER (BETHSOFTVID, bethsoftvid); + REGISTER_DEMUXER (C93, c93); + REGISTER_MUXER (CRC, crc); + REGISTER_DEMUXER (DAUD, daud); + REGISTER_DEMUXER (DSICIN, dsicin); + REGISTER_DEMUXER (DTS, dts); + REGISTER_MUXDEMUX (DV, dv); + REGISTER_DEMUXER (DXA, dxa); + REGISTER_DEMUXER (EA, ea); + REGISTER_DEMUXER (EA_CDATA, ea_cdata); + REGISTER_MUXDEMUX (FFM, ffm); + REGISTER_MUXDEMUX (FLAC, flac); + REGISTER_DEMUXER (FLIC, flic); + REGISTER_MUXDEMUX (FLV, flv); + REGISTER_DEMUXER (FOURXM, fourxm); + REGISTER_MUXER (FRAMECRC, framecrc); + REGISTER_MUXDEMUX (GIF, gif); + REGISTER_MUXDEMUX (GXF, gxf); + REGISTER_MUXDEMUX (H261, h261); + REGISTER_MUXDEMUX (H263, h263); + REGISTER_MUXDEMUX (H264, h264); + REGISTER_DEMUXER (IDCIN, idcin); + REGISTER_MUXDEMUX (IMAGE2, image2); + REGISTER_MUXDEMUX (IMAGE2PIPE, image2pipe); + REGISTER_DEMUXER (INGENIENT, ingenient); + REGISTER_DEMUXER (IPMOVIE, ipmovie); + REGISTER_DEMUXER (LMLM4, lmlm4); + REGISTER_MUXDEMUX (M4V, m4v); + REGISTER_MUXDEMUX (MATROSKA, matroska); + REGISTER_MUXER (MATROSKA_AUDIO, matroska_audio); + REGISTER_MUXDEMUX (MJPEG, mjpeg); + REGISTER_DEMUXER (MM, mm); + REGISTER_MUXDEMUX (MMF, mmf); + REGISTER_MUXDEMUX (MOV, mov); + REGISTER_MUXER (MP2, mp2); + REGISTER_MUXDEMUX (MP3, mp3); + REGISTER_MUXER (MP4, mp4); + REGISTER_DEMUXER (MPC, mpc); + REGISTER_DEMUXER (MPC8, mpc8); + REGISTER_MUXER (MPEG1SYSTEM, mpeg1system); + REGISTER_MUXER (MPEG1VCD, mpeg1vcd); + REGISTER_MUXER (MPEG1VIDEO, mpeg1video); + REGISTER_MUXER (MPEG2DVD, mpeg2dvd); + REGISTER_MUXER (MPEG2SVCD, mpeg2svcd); + REGISTER_MUXER (MPEG2VIDEO, mpeg2video); + REGISTER_MUXER (MPEG2VOB, mpeg2vob); + REGISTER_DEMUXER (MPEGPS, mpegps); + REGISTER_MUXDEMUX (MPEGTS, mpegts); + REGISTER_DEMUXER (MPEGTSRAW, mpegtsraw); + REGISTER_DEMUXER (MPEGVIDEO, mpegvideo); + REGISTER_MUXER (MPJPEG, mpjpeg); + REGISTER_DEMUXER (MTV, mtv); + REGISTER_DEMUXER (MXF, mxf); + REGISTER_DEMUXER (NSV, nsv); + REGISTER_MUXER (NULL, null); + REGISTER_MUXDEMUX (NUT, nut); + REGISTER_DEMUXER (NUV, nuv); + REGISTER_MUXDEMUX (OGG, ogg); + REGISTER_MUXDEMUX (PCM_ALAW, pcm_alaw); + REGISTER_MUXDEMUX (PCM_MULAW, pcm_mulaw); + REGISTER_MUXDEMUX (PCM_S16BE, pcm_s16be); + REGISTER_MUXDEMUX (PCM_S16LE, pcm_s16le); + REGISTER_MUXDEMUX (PCM_S8, pcm_s8); + REGISTER_MUXDEMUX (PCM_U16BE, pcm_u16be); + REGISTER_MUXDEMUX (PCM_U16LE, pcm_u16le); + REGISTER_MUXDEMUX (PCM_U8, pcm_u8); + REGISTER_MUXER (PSP, psp); + REGISTER_DEMUXER (PVA, pva); + REGISTER_MUXDEMUX (RAWVIDEO, rawvideo); + REGISTER_MUXDEMUX (RM, rm); + REGISTER_MUXDEMUX (ROQ, roq); + REGISTER_DEMUXER (REDIR, redir); + REGISTER_MUXER (RTP, rtp); + REGISTER_DEMUXER (RTSP, rtsp); + REGISTER_DEMUXER (SDP, sdp); +#ifdef CONFIG_SDP_DEMUXER av_register_rtp_dynamic_payload_handlers(); #endif - REGISTER_DEMUXER (SEGAFILM, segafilm); - REGISTER_DEMUXER (SHORTEN, shorten); - REGISTER_DEMUXER (SMACKER, smacker); - REGISTER_DEMUXER (SOL, sol); - REGISTER_DEMUXER (STR, str); - REGISTER_MUXDEMUX(SWF, swf); - REGISTER_MUXER (TG2, tg2); - REGISTER_MUXER (TGP, tgp); - REGISTER_DEMUXER (THP, thp); - REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq); - REGISTER_DEMUXER (TTA, tta); - REGISTER_DEMUXER (V4L2, v4l2); - REGISTER_DEMUXER (VC1, vc1); - REGISTER_DEMUXER (VIDEO_GRAB_DEVICE, video_grab_device); - REGISTER_DEMUXER (VMD, vmd); - REGISTER_MUXDEMUX(VOC, voc); - REGISTER_MUXDEMUX(WAV, wav); - REGISTER_DEMUXER (WC3, wc3); - REGISTER_DEMUXER (WSAUD, wsaud); - REGISTER_DEMUXER (WSVQA, wsvqa); - REGISTER_DEMUXER (WV, wv); - REGISTER_DEMUXER (X11_GRAB_DEVICE, x11_grab_device); - REGISTER_MUXDEMUX(YUV4MPEGPIPE, yuv4mpegpipe); + REGISTER_DEMUXER (SEGAFILM, segafilm); + REGISTER_DEMUXER (SHORTEN, shorten); + REGISTER_DEMUXER (SIFF, siff); + REGISTER_DEMUXER (SMACKER, smacker); + REGISTER_DEMUXER (SOL, sol); + REGISTER_DEMUXER (STR, str); + REGISTER_MUXDEMUX (SWF, swf); + REGISTER_MUXER (TG2, tg2); + REGISTER_MUXER (TGP, tgp); + REGISTER_DEMUXER (THP, thp); + REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq); + REGISTER_DEMUXER (TTA, tta); + REGISTER_DEMUXER (TXD, txd); + REGISTER_DEMUXER (VC1, vc1); + REGISTER_DEMUXER (VC1T, vc1t); + REGISTER_DEMUXER (VMD, vmd); + REGISTER_MUXDEMUX (VOC, voc); + REGISTER_MUXDEMUX (WAV, wav); + REGISTER_DEMUXER (WC3, wc3); + REGISTER_DEMUXER (WSAUD, wsaud); + REGISTER_DEMUXER (WSVQA, wsvqa); + REGISTER_DEMUXER (WV, wv); + REGISTER_MUXDEMUX (YUV4MPEGPIPE, yuv4mpegpipe); -#ifdef CONFIG_PROTOCOLS - /* file protocols */ - register_protocol(&file_protocol); - register_protocol(&pipe_protocol); -#ifdef CONFIG_NETWORK - register_protocol(&udp_protocol); - register_protocol(&rtp_protocol); - register_protocol(&tcp_protocol); - register_protocol(&http_protocol); -#endif -#endif + /* external libraries */ + REGISTER_MUXDEMUX (LIBNUT, libnut); + + /* protocols */ + REGISTER_PROTOCOL (FILE, file); + REGISTER_PROTOCOL (HTTP, http); + REGISTER_PROTOCOL (PIPE, pipe); + REGISTER_PROTOCOL (RTP, rtp); + REGISTER_PROTOCOL (TCP, tcp); + REGISTER_PROTOCOL (UDP, udp); } diff --git a/contrib/ffmpeg/libavformat/allformats.h b/contrib/ffmpeg/libavformat/allformats.h deleted file mode 100644 index 9734940d3..000000000 --- a/contrib/ffmpeg/libavformat/allformats.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Register all the formats and protocols. - * copyright (c) 2000, 2001, 2002 Fabrice Bellard - * - * 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 ALLFORMATS_H -#define ALLFORMATS_H - -extern AVInputFormat fourxm_demuxer; -extern AVOutputFormat adts_muxer; -extern AVInputFormat aiff_demuxer; -extern AVOutputFormat aiff_muxer; -extern AVInputFormat amr_demuxer; -extern AVOutputFormat amr_muxer; -extern AVInputFormat asf_demuxer; -extern AVOutputFormat asf_muxer; -extern AVOutputFormat asf_stream_muxer; -extern AVInputFormat au_demuxer; -extern AVOutputFormat au_muxer; -extern AVInputFormat audio_demuxer; -extern AVOutputFormat audio_muxer; -extern AVInputFormat avi_demuxer; -extern AVOutputFormat avi_muxer; -extern AVInputFormat avisynth_demuxer; -extern AVInputFormat avs_demuxer; -extern AVOutputFormat crc_muxer; -extern AVOutputFormat framecrc_muxer; -extern AVInputFormat daud_demuxer; -extern AVInputFormat dc1394_demuxer; -extern AVInputFormat dsicin_demuxer; -extern AVInputFormat dv1394_demuxer; -extern AVInputFormat dv_demuxer; -extern AVOutputFormat dv_muxer; -extern AVInputFormat dxa_demuxer; -extern AVInputFormat ea_demuxer; -extern AVInputFormat ffm_demuxer; -extern AVOutputFormat ffm_muxer; -extern AVInputFormat flic_demuxer; -extern AVInputFormat flv_demuxer; -extern AVOutputFormat flv_muxer; -extern AVOutputFormat gif_muxer; -extern AVInputFormat gif_demuxer; -extern AVInputFormat video_grab_device_demuxer; -extern AVInputFormat gxf_demuxer; -extern AVOutputFormat gxf_muxer; -extern AVInputFormat idcin_demuxer; -extern AVInputFormat roq_demuxer; -extern AVInputFormat image2_demuxer; -extern AVInputFormat image2pipe_demuxer; -extern AVOutputFormat image2_muxer; -extern AVOutputFormat image2pipe_muxer; -extern AVInputFormat image_demuxer; -extern AVInputFormat imagepipe_demuxer; -extern AVOutputFormat image_muxer; -extern AVOutputFormat imagepipe_muxer; -extern AVInputFormat ipmovie_demuxer; -extern AVInputFormat libnut_demuxer; -extern AVOutputFormat libnut_muxer; -extern AVInputFormat matroska_demuxer; -extern AVInputFormat mm_demuxer; -extern AVInputFormat mmf_demuxer; -extern AVOutputFormat mmf_muxer; -extern AVInputFormat mov_demuxer; -extern AVOutputFormat mov_muxer; -extern AVOutputFormat tgp_muxer; -extern AVOutputFormat mp4_muxer; -extern AVOutputFormat psp_muxer; -extern AVOutputFormat tg2_muxer; -extern AVInputFormat mp3_demuxer; -extern AVOutputFormat mp2_muxer; -extern AVOutputFormat mp3_muxer; -extern AVInputFormat mpc_demuxer; -extern AVOutputFormat mpeg1system_muxer; -extern AVOutputFormat mpeg1vcd_muxer; -extern AVOutputFormat mpeg2vob_muxer; -extern AVOutputFormat mpeg2svcd_muxer; -extern AVOutputFormat mpeg2dvd_muxer; -extern AVInputFormat mpegps_demuxer; -extern AVInputFormat mpegts_demuxer; -extern AVOutputFormat mpegts_muxer; -extern AVOutputFormat mpjpeg_muxer; -extern AVInputFormat mtv_demuxer; -extern AVInputFormat mxf_demuxer; -extern AVInputFormat nsv_demuxer; -extern AVInputFormat nut_demuxer; -extern AVInputFormat nuv_demuxer; -extern AVInputFormat ogg_demuxer; -extern AVOutputFormat ogg_muxer; -extern AVInputFormat str_demuxer; -extern AVInputFormat shorten_demuxer; -extern AVInputFormat flac_demuxer; -extern AVOutputFormat flac_muxer; -extern AVInputFormat ac3_demuxer; -extern AVOutputFormat ac3_muxer; -extern AVInputFormat dts_demuxer; -extern AVInputFormat aac_demuxer; -extern AVInputFormat h261_demuxer; -extern AVOutputFormat h261_muxer; -extern AVInputFormat h263_demuxer; -extern AVOutputFormat h263_muxer; -extern AVInputFormat m4v_demuxer; -extern AVOutputFormat m4v_muxer; -extern AVInputFormat h264_demuxer; -extern AVOutputFormat h264_muxer; -extern AVInputFormat mpegvideo_demuxer; -extern AVOutputFormat mpeg1video_muxer; -extern AVOutputFormat mpeg2video_muxer; -extern AVInputFormat mjpeg_demuxer; -extern AVInputFormat ingenient_demuxer; -extern AVOutputFormat mjpeg_muxer; -extern AVInputFormat pcm_s16le_demuxer; -extern AVOutputFormat pcm_s16le_muxer; -extern AVInputFormat pcm_s16be_demuxer; -extern AVOutputFormat pcm_s16be_muxer; -extern AVInputFormat pcm_u16le_demuxer; -extern AVOutputFormat pcm_u16le_muxer; -extern AVInputFormat pcm_u16be_demuxer; -extern AVOutputFormat pcm_u16be_muxer; -extern AVInputFormat pcm_s8_demuxer; -extern AVOutputFormat pcm_s8_muxer; -extern AVInputFormat pcm_u8_demuxer; -extern AVOutputFormat pcm_u8_muxer; -extern AVInputFormat pcm_mulaw_demuxer; -extern AVOutputFormat pcm_mulaw_muxer; -extern AVInputFormat pcm_alaw_demuxer; -extern AVOutputFormat pcm_alaw_muxer; -extern AVInputFormat rawvideo_demuxer; -extern AVOutputFormat rawvideo_muxer; -extern AVOutputFormat null_muxer; -extern AVInputFormat rm_demuxer; -extern AVOutputFormat rm_muxer; -extern AVInputFormat sdp_demuxer; -extern AVInputFormat redir_demuxer; -extern AVInputFormat segafilm_demuxer; -extern AVInputFormat vmd_demuxer; -extern AVInputFormat smacker_demuxer; -extern AVInputFormat sol_demuxer; -extern AVInputFormat swf_demuxer; -extern AVOutputFormat swf_muxer; -extern AVInputFormat tta_demuxer; -extern AVInputFormat v4l2_demuxer; -extern AVInputFormat vc1_demuxer; -extern AVInputFormat voc_demuxer; -extern AVOutputFormat voc_muxer; -extern AVInputFormat wav_demuxer; -extern AVOutputFormat wav_muxer; -extern AVInputFormat wc3_demuxer; -extern AVInputFormat wsaud_demuxer; -extern AVInputFormat wsvqa_demuxer; -extern AVInputFormat wv_demuxer; -extern AVOutputFormat yuv4mpegpipe_muxer; -extern AVInputFormat yuv4mpegpipe_demuxer; -extern AVInputFormat tiertexseq_demuxer; -extern AVInputFormat x11_grab_device_demuxer; -extern AVInputFormat thp_demuxer; - -/* raw.c */ -int pcm_read_seek(AVFormatContext *s, - int stream_index, int64_t timestamp, int flags); - -/* rtsp.c */ -int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f); -/* rtp.c */ -void av_register_rtp_dynamic_payload_handlers(); - -#endif diff --git a/contrib/ffmpeg/libavformat/amr.c b/contrib/ffmpeg/libavformat/amr.c index 635a898fa..d8c5399e3 100644 --- a/contrib/ffmpeg/libavformat/amr.c +++ b/contrib/ffmpeg/libavformat/amr.c @@ -33,7 +33,7 @@ static const char AMRWB_header [] = "#!AMR-WB\n"; #ifdef CONFIG_MUXERS static int amr_write_header(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[0]->codec; s->priv_data = NULL; @@ -56,13 +56,8 @@ static int amr_write_header(AVFormatContext *s) static int amr_write_packet(AVFormatContext *s, AVPacket *pkt) { - put_buffer(&s->pb, pkt->data, pkt->size); - put_flush_packet(&s->pb); - return 0; -} - -static int amr_write_trailer(AVFormatContext *s) -{ + put_buffer(s->pb, pkt->data, pkt->size); + put_flush_packet(s->pb); return 0; } #endif /* CONFIG_MUXERS */ @@ -73,8 +68,6 @@ static int amr_probe(AVProbeData *p) //This will also trigger multichannel files: "#!AMR_MC1.0\n" and //"#!AMR-WB_MC1.0\n" (not supported) - if (p->buf_size < 5) - return 0; if(memcmp(p->buf,AMR_header,5)==0) return AVPROBE_SCORE_MAX; else @@ -85,7 +78,7 @@ static int amr_probe(AVProbeData *p) static int amr_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; uint8_t header[9]; @@ -94,7 +87,7 @@ static int amr_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) { - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } if(memcmp(header,AMR_header,6)!=0) { @@ -125,15 +118,15 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) { AVCodecContext *enc = s->streams[0]->codec; - int read, size, toc, mode; + int read, size = 0, toc, mode; - if (url_feof(&s->pb)) + if (url_feof(s->pb)) { - return AVERROR_IO; + return AVERROR(EIO); } //FIXME this is wrong, this should rather be in a AVParset - toc=get_byte(&s->pb); + toc=get_byte(s->pb); mode = (toc >> 3) & 0x0F; if (enc->codec_id == CODEC_ID_AMR_NB) @@ -155,19 +148,19 @@ static int amr_read_packet(AVFormatContext *s, if ( (size==0) || av_new_packet(pkt, size)) { - return AVERROR_IO; + return AVERROR(EIO); } pkt->stream_index = 0; - pkt->pos= url_ftell(&s->pb); + pkt->pos= url_ftell(s->pb); pkt->data[0]=toc; pkt->duration= enc->codec_id == CODEC_ID_AMR_NB ? 160 : 320; - read = get_buffer(&s->pb, pkt->data+1, size-1); + read = get_buffer(s->pb, pkt->data+1, size-1); if (read != size-1) { av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } return 0; @@ -196,6 +189,5 @@ AVOutputFormat amr_muxer = { CODEC_ID_NONE, amr_write_header, amr_write_packet, - amr_write_trailer, }; #endif diff --git a/contrib/ffmpeg/libavformat/apc.c b/contrib/ffmpeg/libavformat/apc.c new file mode 100644 index 000000000..97de8c88e --- /dev/null +++ b/contrib/ffmpeg/libavformat/apc.c @@ -0,0 +1,90 @@ +/* + * CRYO APC audio format demuxer + * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> + * + * 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 "string.h" + +static int apc_probe(AVProbeData *p) +{ + if (!strncmp(p->buf, "CRYO_APC", 8)) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int apc_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + ByteIOContext *pb = s->pb; + AVStream *st; + + get_le32(pb); /* CRYO */ + get_le32(pb); /* _APC */ + get_le32(pb); /* 1.20 */ + + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_ADPCM_IMA_WS; + + get_le32(pb); /* number of samples */ + st->codec->sample_rate = get_le32(pb); + + st->codec->extradata_size = 2 * 4; + st->codec->extradata = av_malloc(st->codec->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + + /* initial predictor values for adpcm decoder */ + get_buffer(pb, st->codec->extradata, 2 * 4); + + st->codec->channels = 1; + if (get_le32(pb)) + st->codec->channels = 2; + + st->codec->bits_per_sample = 4; + st->codec->bit_rate = st->codec->bits_per_sample * st->codec->channels + * st->codec->sample_rate; + st->codec->block_align = 1; + + return 0; +} + +#define MAX_READ_SIZE 4096 + +static int apc_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + if (av_get_packet(s->pb, pkt, MAX_READ_SIZE) <= 0) + return AVERROR(EIO); + pkt->stream_index = 0; + return 0; +} + +AVInputFormat apc_demuxer = { + "apc", + "CRYO APC format", + 0, + apc_probe, + apc_read_header, + apc_read_packet, +}; diff --git a/contrib/ffmpeg/libavformat/ape.c b/contrib/ffmpeg/libavformat/ape.c new file mode 100644 index 000000000..a90f887e5 --- /dev/null +++ b/contrib/ffmpeg/libavformat/ape.c @@ -0,0 +1,523 @@ +/* + * Monkey's Audio APE demuxer + * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org> + * based upon libdemac from Dave Chapman. + * + * 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 "avformat.h" + +#define ENABLE_DEBUG 0 + +/* The earliest and latest file formats supported by this library */ +#define APE_MIN_VERSION 3950 +#define APE_MAX_VERSION 3990 + +#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE] +#define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection [OBSOLETE] +#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // uint32 nPeakLevel after the header [OBSOLETE] +#define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit [OBSOLETE] +#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level +#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored) + +#define MAC_SUBFRAME_SIZE 4608 + +#define APE_EXTRADATA_SIZE 6 + +/* APE tags */ +#define APE_TAG_VERSION 2000 +#define APE_TAG_FOOTER_BYTES 32 +#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) +#define APE_TAG_FLAG_IS_HEADER (1 << 29) + +#define TAG(name, field) {name, offsetof(AVFormatContext, field), sizeof(((AVFormatContext *)0)->field)} + +static const struct { + const char *name; + int offset; + int size; +} tags[] = { + TAG("Title" , title ), + TAG("Artist" , author ), + TAG("Copyright", copyright), + TAG("Comment" , comment ), + TAG("Album" , album ), + TAG("Year" , year ), + TAG("Track" , track ), + TAG("Genre" , genre ), + { NULL } +}; + +typedef struct { + int64_t pos; + int nblocks; + int size; + int skip; + int64_t pts; +} APEFrame; + +typedef struct { + /* Derived fields */ + uint32_t junklength; + uint32_t firstframe; + uint32_t totalsamples; + int currentframe; + APEFrame *frames; + + /* Info from Descriptor Block */ + char magic[4]; + int16_t fileversion; + int16_t padding1; + uint32_t descriptorlength; + uint32_t headerlength; + uint32_t seektablelength; + uint32_t wavheaderlength; + uint32_t audiodatalength; + uint32_t audiodatalength_high; + uint32_t wavtaillength; + uint8_t md5[16]; + + /* Info from Header Block */ + uint16_t compressiontype; + uint16_t formatflags; + uint32_t blocksperframe; + uint32_t finalframeblocks; + uint32_t totalframes; + uint16_t bps; + uint16_t channels; + uint32_t samplerate; + + /* Seektable */ + uint32_t *seektable; +} APEContext; + +static void ape_tag_read_field(AVFormatContext *s) +{ + ByteIOContext *pb = s->pb; + uint8_t buf[1024]; + uint32_t size; + int i; + + memset(buf, 0, 1024); + size = get_le32(pb); /* field size */ + url_fskip(pb, 4); /* skip field flags */ + + for (i=0; pb->buf_ptr[i]!='0' && pb->buf_ptr[i]>=0x20 && pb->buf_ptr[i]<=0x7E; i++); + + get_buffer(pb, buf, FFMIN(i, 1024)); + url_fskip(pb, 1); + + for (i=0; tags[i].name; i++) + if (!strcmp (buf, tags[i].name)) { + if (tags[i].size == sizeof(int)) { + char tmp[16]; + get_buffer(pb, tmp, FFMIN(sizeof(tmp), size)); + *(int *)(((char *)s)+tags[i].offset) = atoi(tmp); + } else { + get_buffer(pb, ((char *)s) + tags[i].offset, + FFMIN(tags[i].size, size)); + } + break; + } + + if (!tags[i].name) + url_fskip(pb, size); +} + +static void ape_parse_tag(AVFormatContext *s) +{ + ByteIOContext *pb = s->pb; + int file_size = url_fsize(pb); + uint32_t val, fields, tag_bytes; + uint8_t buf[8]; + int i; + + if (file_size < APE_TAG_FOOTER_BYTES) + return; + + url_fseek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET); + + get_buffer(pb, buf, 8); /* APETAGEX */ + if (strncmp(buf, "APETAGEX", 8)) { + av_log(NULL, AV_LOG_ERROR, "Invalid APE Tags\n"); + return; + } + + val = get_le32(pb); /* APE tag version */ + if (val > APE_TAG_VERSION) { + av_log(NULL, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION); + return; + } + + tag_bytes = get_le32(pb); /* tag size */ + if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) { + av_log(NULL, AV_LOG_ERROR, "Tag size is way too big\n"); + return; + } + + fields = get_le32(pb); /* number of fields */ + if (fields > 65536) { + av_log(NULL, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields); + return; + } + + val = get_le32(pb); /* flags */ + if (val & APE_TAG_FLAG_IS_HEADER) { + av_log(NULL, AV_LOG_ERROR, "APE Tag is a header\n"); + return; + } + + if (val & APE_TAG_FLAG_CONTAINS_HEADER) + tag_bytes += 2*APE_TAG_FOOTER_BYTES; + + url_fseek(pb, file_size - tag_bytes, SEEK_SET); + + for (i=0; i<fields; i++) + ape_tag_read_field(s); + +#if ENABLE_DEBUG + av_log(NULL, AV_LOG_DEBUG, "\nAPE Tags:\n\n"); + av_log(NULL, AV_LOG_DEBUG, "title = %s\n", s->title); + av_log(NULL, AV_LOG_DEBUG, "author = %s\n", s->author); + av_log(NULL, AV_LOG_DEBUG, "copyright = %s\n", s->copyright); + av_log(NULL, AV_LOG_DEBUG, "comment = %s\n", s->comment); + av_log(NULL, AV_LOG_DEBUG, "album = %s\n", s->album); + av_log(NULL, AV_LOG_DEBUG, "year = %d\n", s->year); + av_log(NULL, AV_LOG_DEBUG, "track = %d\n", s->track); + av_log(NULL, AV_LOG_DEBUG, "genre = %s\n", s->genre); +#endif +} + +static int ape_probe(AVProbeData * p) +{ + if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ') + return AVPROBE_SCORE_MAX; + + return 0; +} + +static void ape_dumpinfo(APEContext * ape_ctx) +{ +#if ENABLE_DEBUG + int i; + + av_log(NULL, AV_LOG_DEBUG, "Descriptor Block:\n\n"); + av_log(NULL, AV_LOG_DEBUG, "magic = \"%c%c%c%c\"\n", ape_ctx->magic[0], ape_ctx->magic[1], ape_ctx->magic[2], ape_ctx->magic[3]); + av_log(NULL, AV_LOG_DEBUG, "fileversion = %d\n", ape_ctx->fileversion); + av_log(NULL, AV_LOG_DEBUG, "descriptorlength = %d\n", ape_ctx->descriptorlength); + av_log(NULL, AV_LOG_DEBUG, "headerlength = %d\n", ape_ctx->headerlength); + av_log(NULL, AV_LOG_DEBUG, "seektablelength = %d\n", ape_ctx->seektablelength); + av_log(NULL, AV_LOG_DEBUG, "wavheaderlength = %d\n", ape_ctx->wavheaderlength); + av_log(NULL, AV_LOG_DEBUG, "audiodatalength = %d\n", ape_ctx->audiodatalength); + av_log(NULL, AV_LOG_DEBUG, "audiodatalength_high = %d\n", ape_ctx->audiodatalength_high); + av_log(NULL, AV_LOG_DEBUG, "wavtaillength = %d\n", ape_ctx->wavtaillength); + av_log(NULL, AV_LOG_DEBUG, "md5 = "); + for (i = 0; i < 16; i++) + av_log(NULL, AV_LOG_DEBUG, "%02x", ape_ctx->md5[i]); + av_log(NULL, AV_LOG_DEBUG, "\n"); + + av_log(NULL, AV_LOG_DEBUG, "\nHeader Block:\n\n"); + + av_log(NULL, AV_LOG_DEBUG, "compressiontype = %d\n", ape_ctx->compressiontype); + av_log(NULL, AV_LOG_DEBUG, "formatflags = %d\n", ape_ctx->formatflags); + av_log(NULL, AV_LOG_DEBUG, "blocksperframe = %d\n", ape_ctx->blocksperframe); + av_log(NULL, AV_LOG_DEBUG, "finalframeblocks = %d\n", ape_ctx->finalframeblocks); + av_log(NULL, AV_LOG_DEBUG, "totalframes = %d\n", ape_ctx->totalframes); + av_log(NULL, AV_LOG_DEBUG, "bps = %d\n", ape_ctx->bps); + av_log(NULL, AV_LOG_DEBUG, "channels = %d\n", ape_ctx->channels); + av_log(NULL, AV_LOG_DEBUG, "samplerate = %d\n", ape_ctx->samplerate); + + av_log(NULL, AV_LOG_DEBUG, "\nSeektable\n\n"); + if ((ape_ctx->seektablelength / sizeof(uint32_t)) != ape_ctx->totalframes) { + av_log(NULL, AV_LOG_DEBUG, "No seektable\n"); + } else { + for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) { + if (i < ape_ctx->totalframes - 1) { + av_log(NULL, AV_LOG_DEBUG, "%8d %d (%d bytes)\n", i, ape_ctx->seektable[i], ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]); + } else { + av_log(NULL, AV_LOG_DEBUG, "%8d %d\n", i, ape_ctx->seektable[i]); + } + } + } + + av_log(NULL, AV_LOG_DEBUG, "\nFrames\n\n"); + for (i = 0; i < ape_ctx->totalframes; i++) + av_log(NULL, AV_LOG_DEBUG, "%8d %8lld %8d (%d samples)\n", i, ape_ctx->frames[i].pos, ape_ctx->frames[i].size, ape_ctx->frames[i].nblocks); + + av_log(NULL, AV_LOG_DEBUG, "\nCalculated information:\n\n"); + av_log(NULL, AV_LOG_DEBUG, "junklength = %d\n", ape_ctx->junklength); + av_log(NULL, AV_LOG_DEBUG, "firstframe = %d\n", ape_ctx->firstframe); + av_log(NULL, AV_LOG_DEBUG, "totalsamples = %d\n", ape_ctx->totalsamples); +#endif +} + +static int ape_read_header(AVFormatContext * s, AVFormatParameters * ap) +{ + ByteIOContext *pb = s->pb; + APEContext *ape = s->priv_data; + AVStream *st; + uint32_t tag; + int i; + int total_blocks; + int64_t pts; + + /* TODO: Skip any leading junk such as id3v2 tags */ + ape->junklength = 0; + + tag = get_le32(pb); + if (tag != MKTAG('M', 'A', 'C', ' ')) + return -1; + + ape->fileversion = get_le16(pb); + + if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) { + av_log(s, AV_LOG_ERROR, "Unsupported file version - %d.%02d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10); + return -1; + } + + if (ape->fileversion >= 3980) { + ape->padding1 = get_le16(pb); + ape->descriptorlength = get_le32(pb); + ape->headerlength = get_le32(pb); + ape->seektablelength = get_le32(pb); + ape->wavheaderlength = get_le32(pb); + ape->audiodatalength = get_le32(pb); + ape->audiodatalength_high = get_le32(pb); + ape->wavtaillength = get_le32(pb); + get_buffer(pb, ape->md5, 16); + + /* Skip any unknown bytes at the end of the descriptor. + This is for future compatibility */ + if (ape->descriptorlength > 52) + url_fseek(pb, ape->descriptorlength - 52, SEEK_CUR); + + /* Read header data */ + ape->compressiontype = get_le16(pb); + ape->formatflags = get_le16(pb); + ape->blocksperframe = get_le32(pb); + ape->finalframeblocks = get_le32(pb); + ape->totalframes = get_le32(pb); + ape->bps = get_le16(pb); + ape->channels = get_le16(pb); + ape->samplerate = get_le32(pb); + } else { + ape->descriptorlength = 0; + ape->headerlength = 32; + + ape->compressiontype = get_le16(pb); + ape->formatflags = get_le16(pb); + ape->channels = get_le16(pb); + ape->samplerate = get_le32(pb); + ape->wavheaderlength = get_le32(pb); + ape->wavtaillength = get_le32(pb); + ape->totalframes = get_le32(pb); + ape->finalframeblocks = get_le32(pb); + + if (ape->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) { + url_fseek(pb, 4, SEEK_CUR); /* Skip the peak level */ + ape->headerlength += 4; + } + + if (ape->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS) { + ape->seektablelength = get_le32(pb); + ape->headerlength += 4; + ape->seektablelength *= sizeof(int32_t); + } else + ape->seektablelength = ape->totalframes * sizeof(int32_t); + + if (ape->formatflags & MAC_FORMAT_FLAG_8_BIT) + ape->bps = 8; + else if (ape->formatflags & MAC_FORMAT_FLAG_24_BIT) + ape->bps = 24; + else + ape->bps = 16; + + if (ape->fileversion >= 3950) + ape->blocksperframe = 73728 * 4; + else if (ape->fileversion >= 3900 || (ape->fileversion >= 3800 && ape->compressiontype >= 4000)) + ape->blocksperframe = 73728; + else + ape->blocksperframe = 9216; + + /* Skip any stored wav header */ + if (!(ape->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) + url_fskip(pb, ape->wavheaderlength); + } + + if(ape->totalframes > UINT_MAX / sizeof(APEFrame)){ + av_log(s, AV_LOG_ERROR, "Too many frames: %d\n", ape->totalframes); + return -1; + } + ape->frames = av_malloc(ape->totalframes * sizeof(APEFrame)); + if(!ape->frames) + return AVERROR_NOMEM; + ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength; + ape->currentframe = 0; + + + ape->totalsamples = ape->finalframeblocks; + if (ape->totalframes > 1) + ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1); + + if (ape->seektablelength > 0) { + ape->seektable = av_malloc(ape->seektablelength); + for (i = 0; i < ape->seektablelength / sizeof(uint32_t); i++) + ape->seektable[i] = get_le32(pb); + } + + ape->frames[0].pos = ape->firstframe; + ape->frames[0].nblocks = ape->blocksperframe; + ape->frames[0].skip = 0; + for (i = 1; i < ape->totalframes; i++) { + ape->frames[i].pos = ape->seektable[i]; //ape->frames[i-1].pos + ape->blocksperframe; + ape->frames[i].nblocks = ape->blocksperframe; + ape->frames[i - 1].size = ape->frames[i].pos - ape->frames[i - 1].pos; + ape->frames[i].skip = (ape->frames[i].pos - ape->frames[0].pos) & 3; + } + ape->frames[ape->totalframes - 1].size = ape->finalframeblocks * 4; + ape->frames[ape->totalframes - 1].nblocks = ape->finalframeblocks; + + for (i = 0; i < ape->totalframes; i++) { + if(ape->frames[i].skip){ + ape->frames[i].pos -= ape->frames[i].skip; + ape->frames[i].size += ape->frames[i].skip; + } + ape->frames[i].size = (ape->frames[i].size + 3) & ~3; + } + + + ape_dumpinfo(ape); + + /* try to read APE tags */ + if (!url_is_streamed(pb)) { + ape_parse_tag(s); + url_fseek(pb, 0, SEEK_SET); + } + + av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype); + + /* now we are ready: build format streams */ + st = av_new_stream(s, 0); + if (!st) + return -1; + + total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks; + + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_APE; + st->codec->codec_tag = MKTAG('A', 'P', 'E', ' '); + st->codec->channels = ape->channels; + st->codec->sample_rate = ape->samplerate; + st->codec->bits_per_sample = ape->bps; + st->codec->frame_size = MAC_SUBFRAME_SIZE; + + st->nb_frames = ape->totalframes; + s->start_time = 0; + s->duration = (int64_t) total_blocks * AV_TIME_BASE / ape->samplerate; + av_set_pts_info(st, 64, MAC_SUBFRAME_SIZE, ape->samplerate); + + st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE); + st->codec->extradata_size = APE_EXTRADATA_SIZE; + AV_WL16(st->codec->extradata + 0, ape->fileversion); + AV_WL16(st->codec->extradata + 2, ape->compressiontype); + AV_WL16(st->codec->extradata + 4, ape->formatflags); + + pts = 0; + for (i = 0; i < ape->totalframes; i++) { + ape->frames[i].pts = pts; + av_add_index_entry(st, ape->frames[i].pos, ape->frames[i].pts, 0, 0, AVINDEX_KEYFRAME); + pts += ape->blocksperframe / MAC_SUBFRAME_SIZE; + } + + return 0; +} + +static int ape_read_packet(AVFormatContext * s, AVPacket * pkt) +{ + int ret; + int nblocks; + APEContext *ape = s->priv_data; + uint32_t extra_size = 8; + + if (url_feof(s->pb)) + return AVERROR_IO; + if (ape->currentframe > ape->totalframes) + return AVERROR_IO; + + url_fseek (s->pb, ape->frames[ape->currentframe].pos, SEEK_SET); + + /* Calculate how many blocks there are in this frame */ + if (ape->currentframe == (ape->totalframes - 1)) + nblocks = ape->finalframeblocks; + else + nblocks = ape->blocksperframe; + + if (av_new_packet(pkt, ape->frames[ape->currentframe].size + extra_size) < 0) + return AVERROR_NOMEM; + + AV_WL32(pkt->data , nblocks); + AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip); + ret = get_buffer(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size); + + pkt->pts = ape->frames[ape->currentframe].pts; + pkt->stream_index = 0; + + /* note: we need to modify the packet size here to handle the last + packet */ + pkt->size = ret + extra_size; + + ape->currentframe++; + + return 0; +} + +static int ape_read_close(AVFormatContext * s) +{ + APEContext *ape = s->priv_data; + + av_freep(&ape->frames); + av_freep(&ape->seektable); + return 0; +} + +static int ape_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +{ + AVStream *st = s->streams[stream_index]; + APEContext *ape = s->priv_data; + int index = av_index_search_timestamp(st, timestamp, flags); + + if (index < 0) + return -1; + + ape->currentframe = index; + return 0; +} + +AVInputFormat ape_demuxer = { + "ape", + "Monkey's Audio", + sizeof(APEContext), + ape_probe, + ape_read_header, + ape_read_packet, + ape_read_close, + ape_read_seek, + .extensions = "ape,apl,mac" +}; diff --git a/contrib/ffmpeg/libavformat/asf-enc.c b/contrib/ffmpeg/libavformat/asf-enc.c index f1d9c6903..a12cda1e7 100644 --- a/contrib/ffmpeg/libavformat/asf-enc.c +++ b/contrib/ffmpeg/libavformat/asf-enc.c @@ -199,7 +199,7 @@ static const AVCodecTag codec_asf_bmp_tags[] = { static void put_guid(ByteIOContext *s, const GUID *g) { assert(sizeof(*g) == 16); - put_buffer(s, g, sizeof(*g)); + put_buffer(s, *g, sizeof(*g)); } static void put_str16_nolen(ByteIOContext *s, const char *tag); @@ -244,7 +244,7 @@ static void end_header(ByteIOContext *pb, int64_t pos) static void put_chunk(AVFormatContext *s, int type, int payload_length, int flags) { ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int length; length = payload_length + 8; @@ -270,7 +270,7 @@ static int64_t unix_to_file_time(int ti) static int asf_write_header1(AVFormatContext *s, int64_t file_size, int64_t data_chunk_size) { ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int header_size, n, extra_size, extra_size2, wav_extra_size, file_time; int has_title; AVCodecContext *enc; @@ -493,17 +493,20 @@ static int asf_write_header(AVFormatContext *s) asf->nb_packets = 0; asf->last_indexed_pts = 0; - asf->index_ptr = (ASFIndex*)av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK ); + asf->index_ptr = av_malloc( sizeof(ASFIndex) * ASF_INDEX_BLOCK ); asf->nb_index_memory_alloc = ASF_INDEX_BLOCK; asf->nb_index_count = 0; asf->maximum_packet = 0; - if (asf_write_header1(s, 0, 0) < 0) { + /* the data-chunk-size has to be 50, which is data_size - asf->data_offset + * at the moment this function is done. It is needed to use asf as + * streamable format. */ + if (asf_write_header1(s, 0, 50) < 0) { //av_free(asf); return -1; } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); asf->packet_nb_payloads = 0; asf->packet_timestamp_start = -1; @@ -532,7 +535,7 @@ static int put_payload_parsing_info( ) { ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int ppi_size, i; int64_t start= url_ftell(pb); @@ -581,6 +584,8 @@ static void flush_packet(AVFormatContext *s) ASFContext *asf = s->priv_data; int packet_hdr_size, packet_filled_size; + assert(asf->packet_timestamp_end >= asf->packet_timestamp_start); + if (asf->is_streamed) { put_chunk(s, 0x4424, asf->packet_size, 0); } @@ -597,9 +602,9 @@ static void flush_packet(AVFormatContext *s) assert(packet_hdr_size <= asf->packet_size_left); memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left); - put_buffer(&s->pb, asf->packet_buf, asf->packet_size - packet_hdr_size); + put_buffer(s->pb, asf->packet_buf, asf->packet_size - packet_hdr_size); - put_flush_packet(&s->pb); + put_flush_packet(s->pb); asf->nb_packets++; asf->packet_nb_payloads = 0; asf->packet_timestamp_start = -1; @@ -677,8 +682,6 @@ static void put_frame( // multi payloads frag_len1 = asf->packet_size_left - PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS - PACKET_HEADER_MIN_SIZE - 1; - asf->packet_timestamp_start = timestamp; - if(frag_len1 < payload_len && avst->codec->codec_type == CODEC_TYPE_AUDIO){ flush_packet(s); continue; @@ -763,7 +766,7 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt) // static int asf_write_index(AVFormatContext *s, ASFIndex *index, uint16_t max, uint32_t count) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int i; put_guid(pb, &simple_index_header); @@ -790,22 +793,22 @@ static int asf_write_trailer(AVFormatContext *s) flush_packet(s); /* write index */ - data_size = url_ftell(&s->pb); + data_size = url_ftell(s->pb); if ((!asf->is_streamed) && (asf->nb_index_count != 0)) { asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count); } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); - if (asf->is_streamed || url_is_streamed(&s->pb)) { + if (asf->is_streamed || url_is_streamed(s->pb)) { put_chunk(s, 0x4524, 0, 0); /* end of stream */ } else { /* rewrite an updated header */ - file_size = url_ftell(&s->pb); - url_fseek(&s->pb, 0, SEEK_SET); + file_size = url_ftell(s->pb); + url_fseek(s->pb, 0, SEEK_SET); asf_write_header1(s, file_size, data_size - asf->data_offset); } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); av_free(asf->index_ptr); return 0; } diff --git a/contrib/ffmpeg/libavformat/asf.c b/contrib/ffmpeg/libavformat/asf.c index 498f6e79e..30330c535 100644 --- a/contrib/ffmpeg/libavformat/asf.c +++ b/contrib/ffmpeg/libavformat/asf.c @@ -23,6 +23,9 @@ #include "mpegaudio.h" #include "asf.h" #include "common.h" +#include "asfcrypt.h" + +extern void ff_mms_set_stream_selection(URLContext *h, AVFormatContext *format); #undef NDEBUG #include <assert.h> @@ -84,7 +87,7 @@ static void print_guid(const GUID *g) static void get_guid(ByteIOContext *s, GUID *g) { assert(sizeof(*g) == 16); - get_buffer(s, g, sizeof(*g)); + get_buffer(s, *g, sizeof(*g)); } #if 0 @@ -119,9 +122,6 @@ static void get_str16_nolen(ByteIOContext *pb, int len, char *buf, int buf_size) static int asf_probe(AVProbeData *pd) { /* check file header */ - if (pd->buf_size <= 32) - return 0; - if (!memcmp(pd->buf, &asf_header, sizeof(GUID))) return AVPROBE_SCORE_MAX; else @@ -142,14 +142,16 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) { ASFContext *asf = s->priv_data; GUID g; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; ASFStream *asf_st; int size, i; int64_t gsize; AVRational dar[128]; + uint32_t bitrate[128]; memset(dar, 0, sizeof(dar)); + memset(bitrate, 0, sizeof(bitrate)); get_guid(pb, &g); if (memcmp(&g, &asf_header, sizeof(GUID))) @@ -197,8 +199,8 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) int type, type_specific_size, sizeX; uint64_t total_size; unsigned int tag1; - int64_t pos1, pos2; - int test_for_ext_stream_audio; + int64_t pos1, pos2, start_time; + int test_for_ext_stream_audio, is_dvr_ms_audio=0; pos1 = url_ftell(pb); @@ -210,10 +212,11 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) if (!asf_st) goto fail; st->priv_data = asf_st; - st->start_time = asf->hdr.preroll; + start_time = asf->hdr.preroll; + if(!(asf->hdr.flags & 0x01)) { // if we aren't streaming... st->duration = asf->hdr.send_time / - (10000000 / 1000) - st->start_time; + (10000000 / 1000) - start_time; } get_guid(pb, &g); @@ -244,6 +247,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_guid(pb, &g); if (!memcmp(&g, &ext_stream_audio_stream, sizeof(GUID))) { type = CODEC_TYPE_AUDIO; + is_dvr_ms_audio=1; get_guid(pb, &g); get_le32(pb); get_le32(pb); @@ -256,7 +260,13 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_type = type; if (type == CODEC_TYPE_AUDIO) { get_wav_header(pb, st->codec, type_specific_size); - st->need_parsing = 1; + 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_NONE; + st->codec->codec_tag = 0; + } + st->need_parsing = AVSTREAM_PARSE_FULL; /* We have to init the frame size at some point .... */ pos2 = url_ftell(pb); if (gsize >= (pos2 + 8 - pos1 + 24)) { @@ -333,7 +343,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_tag = tag1; st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1); if(tag1 == MKTAG('D', 'V', 'R', ' ')) - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; } pos2 = url_ftell(pb); url_fskip(pb, gsize - (pos2 - pos1 + 24)); @@ -363,7 +373,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) bitrate= get_le32(pb); stream_id= (flags & 0x7f); // av_log(NULL, AV_LOG_ERROR, "flags: 0x%x stream id %d, bitrate %d\n", flags, stream_id, bitrate); - asf->stream_bitrates[stream_id-1]= bitrate; + asf->stream_bitrates[stream_id]= bitrate; } } else if (!memcmp(&g, &extended_content_header, sizeof(GUID))) { int desc_count, i; @@ -383,12 +393,27 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) { if (!strcmp(name,"WM/AlbumTitle")) get_str16_nolen(pb, value_len, s->album, sizeof(s->album)); else if(!strcmp(name,"WM/Genre" )) get_str16_nolen(pb, value_len, s->genre, sizeof(s->genre)); + else if(!strcmp(name,"WM/Year" )) { + char year[8]; + get_str16_nolen(pb, value_len, year, sizeof(year)); + s->year = atoi(year); + } + else if(!strcmp(name,"WM/Track") && s->track == 0) { + char track[8]; + get_str16_nolen(pb, value_len, track, sizeof(track)); + s->track = strtol(track, NULL, 10) + 1; + } + else if(!strcmp(name,"WM/TrackNumber")) { + char track[8]; + get_str16_nolen(pb, value_len, track, sizeof(track)); + s->track = strtol(track, NULL, 10); + } else url_fskip(pb, value_len); } if ((value_type >= 2) && (value_type <= 5)) // boolean or DWORD or QWORD or WORD { value_num= get_value(pb, value_type); - if (!strcmp(name,"WM/Track" )) s->track = value_num + 1; + if (!strcmp(name,"WM/Track" ) && s->track == 0) s->track = value_num + 1; if (!strcmp(name,"WM/TrackNumber")) s->track = value_num; } } @@ -407,7 +432,7 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_str16_nolen(pb, name_len, name, sizeof(name)); //av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d <%s>\n", i, stream_num, name_len, value_type, value_len, name); - value_num= get_le16(pb);//we should use get_value() here but it doesnt work 2 is le16 here but le32 elsewhere + value_num= get_le16(pb);//we should use get_value() here but it does not work 2 is le16 here but le32 elsewhere url_fskip(pb, value_len - 2); if(stream_num<128){ @@ -417,13 +442,13 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) } } else if (!memcmp(&g, &ext_stream_header, sizeof(GUID))) { int ext_len, payload_ext_ct, stream_ct; - uint32_t ext_d; + uint32_t ext_d, leak_rate, stream_num; int64_t pos_ex_st; pos_ex_st = url_ftell(pb); get_le64(pb); // starttime get_le64(pb); // endtime - get_le32(pb); // leak-datarate + leak_rate = get_le32(pb); // leak-datarate get_le32(pb); // bucket-datasize get_le32(pb); // init-bucket-fullness get_le32(pb); // alt-leak-datarate @@ -431,12 +456,15 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_le32(pb); // alt-init-bucket-fullness get_le32(pb); // max-object-size get_le32(pb); // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved) - get_le16(pb); // stream-num + stream_num = get_le16(pb); // stream-num get_le16(pb); // stream-language-id-index get_le64(pb); // avg frametime in 100ns units stream_ct = get_le16(pb); //stream-name-count payload_ext_ct = get_le16(pb); //payload-extension-system-count + if (stream_num < 128) + bitrate[stream_num] = leak_rate; + for (i=0; i<stream_ct; i++){ get_le16(pb); ext_len = get_le16(pb); @@ -500,11 +528,14 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) for(i=0; i<128; i++){ int stream_num= asf->asfid2avid[i]; - if(stream_num>=0 && dar[i].num>0 && dar[i].den>0){ + if(stream_num>=0){ AVCodecContext *codec= s->streams[stream_num]->codec; - av_reduce(&codec->sample_aspect_ratio.num, - &codec->sample_aspect_ratio.den, - dar[i].num, dar[i].den, INT_MAX); + if (!codec->bit_rate) + codec->bit_rate = bitrate[i]; + if (dar[i].num > 0 && dar[i].den > 0) + av_reduce(&codec->sample_aspect_ratio.num, + &codec->sample_aspect_ratio.den, + dar[i].num, dar[i].den, INT_MAX); //av_log(NULL, AV_LOG_ERROR, "dar %d:%d sar=%d:%d\n", dar[i].num, dar[i].den, codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den); } } @@ -539,12 +570,12 @@ static int asf_read_header(AVFormatContext *s, AVFormatParameters *ap) static int asf_get_packet(AVFormatContext *s) { ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint32_t packet_length, padsize; int rsize = 8; int c, d, e, off; - off= (url_ftell(&s->pb) - s->data_offset) % asf->packet_size + 3; + off= (url_ftell(s->pb) - s->data_offset) % asf->packet_size + 3; c=d=e=-1; while(off-- > 0){ @@ -615,7 +646,7 @@ static int asf_get_packet(AVFormatContext *s) */ static int asf_read_frame_header(AVFormatContext *s){ ASFContext *asf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int rsize = 1; int num = get_byte(pb); int64_t ts0, ts1; @@ -651,7 +682,7 @@ static int asf_read_frame_header(AVFormatContext *s){ url_fskip(pb, asf->packet_replic_size - 8); rsize += asf->packet_replic_size; // FIXME - check validity } else if (asf->packet_replic_size==1){ - // multipacket - frag_offset is begining timestamp + // multipacket - frag_offset is beginning timestamp asf->packet_time_start = asf->packet_frag_offset; asf->packet_frag_offset = 0; asf->packet_frag_timestamp = asf->packet_timestamp; @@ -688,11 +719,11 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) { ASFContext *asf = s->priv_data; ASFStream *asf_st = 0; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; //static int pc = 0; for (;;) { if(url_feof(pb)) - return AVERROR_IO; + return AVERROR(EIO); if (asf->packet_size_left < FRAME_HEADER_SIZE || asf->packet_segments < 1) { //asf->packet_size_left <= asf->packet_padsize) { @@ -702,10 +733,10 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) /* fail safe */ url_fskip(pb, ret); - asf->packet_pos= url_ftell(&s->pb); + asf->packet_pos= url_ftell(s->pb); if (asf->data_object_size != (uint64_t)-1 && (asf->packet_pos - asf->data_object_offset >= asf->data_object_size)) - return AVERROR_IO; /* Do not exceed the size of the data object */ + return AVERROR(EIO); /* Do not exceed the size of the data object */ ret = asf_get_packet(s); //printf("READ ASF PACKET %d r:%d c:%d\n", ret, asf->packet_size_left, pc++); if (ret < 0) @@ -735,7 +766,7 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) asf_st = asf->asf_st; if (asf->packet_replic_size == 1) { - // frag_offset is here used as the begining timestamp + // frag_offset is here used as the beginning timestamp asf->packet_frag_timestamp = asf->packet_time_start; asf->packet_time_start += asf->packet_time_delta; asf->packet_obj_size = asf->packet_frag_size = get_byte(pb); @@ -751,6 +782,15 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) asf->packet_multi_size -= asf->packet_obj_size; //printf("COMPRESS size %d %d %d ms:%d\n", asf->packet_obj_size, asf->packet_frag_timestamp, asf->packet_size_left, asf->packet_multi_size); } + if( /*asf->packet_frag_size == asf->packet_obj_size*/ + asf_st->frag_offset + asf->packet_frag_size <= asf_st->pkt.size + && asf_st->frag_offset + asf->packet_frag_size > asf->packet_obj_size){ + av_log(s, AV_LOG_INFO, "ignoring invalid packet_obj_size (%d %d %d %d)\n", + asf_st->frag_offset, asf->packet_frag_size, + asf->packet_obj_size, asf_st->pkt.size); + asf->packet_obj_size= asf_st->pkt.size; + } + if ( asf_st->pkt.size != asf->packet_obj_size || asf_st->frag_offset + asf->packet_frag_size > asf_st->pkt.size) { //FIXME is this condition sufficient? if(asf_st->pkt.data){ @@ -791,13 +831,29 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) get_buffer(pb, asf_st->pkt.data + asf->packet_frag_offset, asf->packet_frag_size); + if (s->key && s->keylen == 20) + ff_asfcrypt_dec(s->key, asf_st->pkt.data + asf->packet_frag_offset, + asf->packet_frag_size); asf_st->frag_offset += asf->packet_frag_size; /* test if whole packet is read */ if (asf_st->frag_offset == asf_st->pkt.size) { + //workaround for macroshit radio DVR-MS files + if( s->streams[asf->stream_index]->codec->codec_id == CODEC_ID_MPEG2VIDEO + && asf_st->pkt.size > 100){ + int i; + for(i=0; i<asf_st->pkt.size && !asf_st->pkt.data[i]; i++); + if(i == asf_st->pkt.size){ + av_log(s, AV_LOG_DEBUG, "discarding ms fart\n"); + asf_st->frag_offset = 0; + av_free_packet(&asf_st->pkt); + continue; + } + } + /* return packet */ if (asf_st->ds_span > 1) { if(asf_st->pkt.size != asf_st->ds_packet_size * asf_st->ds_span){ - av_log(s, AV_LOG_ERROR, "pkt.size != ds_packet_size * ds_span\n"); + av_log(s, AV_LOG_ERROR, "pkt.size != ds_packet_size * ds_span (%d %d %d)\n", asf_st->pkt.size, asf_st->ds_packet_size, asf_st->ds_span); }else{ /* packet descrambling */ uint8_t *newdata = av_malloc(asf_st->pkt.size); @@ -833,18 +889,6 @@ static int asf_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int asf_read_close(AVFormatContext *s) -{ - int i; - - for(i=0;i<s->nb_streams;i++) { - AVStream *st = s->streams[i]; - av_free(st->priv_data); - av_free(st->codec->palctrl); - } - return 0; -} - // Added to support seeking after packets have been read // If information is not reset, read_packet fails due to // leftover information from previous reads @@ -883,6 +927,19 @@ static void asf_reset_header(AVFormatContext *s) asf->asf_st= NULL; } +static int asf_read_close(AVFormatContext *s) +{ + int i; + + asf_reset_header(s); + for(i=0;i<s->nb_streams;i++) { + AVStream *st = s->streams[i]; + av_free(st->priv_data); + av_free(st->codec->palctrl); + } + return 0; +} + static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit) { ASFContext *asf = s->priv_data; @@ -899,7 +956,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index, int64_t *ppos, pos= (pos+asf->packet_size-1-s->data_offset)/asf->packet_size*asf->packet_size+ s->data_offset; *ppos= pos; - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); //printf("asf_read_pts\n"); asf_reset_header(s); @@ -943,21 +1000,21 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) int i; int pct,ict; - current_pos = url_ftell(&s->pb); + current_pos = url_ftell(s->pb); - url_fseek(&s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET); - get_guid(&s->pb, &g); + url_fseek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET); + get_guid(s->pb, &g); if (!memcmp(&g, &index_guid, sizeof(GUID))) { - gsize = get_le64(&s->pb); - get_guid(&s->pb, &g); - itime=get_le64(&s->pb); - pct=get_le32(&s->pb); - ict=get_le32(&s->pb); + gsize = get_le64(s->pb); + get_guid(s->pb, &g); + itime=get_le64(s->pb); + pct=get_le32(s->pb); + ict=get_le32(s->pb); av_log(NULL, AV_LOG_DEBUG, "itime:0x%"PRIx64", pct:%d, ict:%d\n",itime,pct,ict); for (i=0;i<ict;i++){ - int pktnum=get_le32(&s->pb); - int pktct =get_le16(&s->pb); + int pktnum=get_le32(s->pb); + int pktct =get_le16(s->pb); av_log(NULL, AV_LOG_DEBUG, "pktnum:%d, pktct:%d\n", pktnum, pktct); pos=s->data_offset + asf->packet_size*(int64_t)pktnum; @@ -967,7 +1024,7 @@ static void asf_build_simple_index(AVFormatContext *s, int stream_index) } asf->index_read= 1; } - url_fseek(&s->pb, current_pos, SEEK_SET); + url_fseek(s->pb, current_pos, SEEK_SET); } static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags) @@ -980,6 +1037,15 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int if (asf->packet_size <= 0) return -1; + /* Try using the protocol's read_seek if available */ + if(s->pb) { + int ret = av_url_read_fseek(s->pb, stream_index, pts, flags); + if(ret >= 0) + asf_reset_header(s); + if (ret != AVERROR(ENOSYS)) + return ret; + } + if (!asf->index_read) asf_build_simple_index(s, stream_index); @@ -997,10 +1063,10 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int // various attempts to find key frame have failed so far // asf_reset_header(s); - // url_fseek(&s->pb, pos, SEEK_SET); + // url_fseek(s->pb, pos, SEEK_SET); // key_pos = pos; // for(i=0;i<16;i++){ - // pos = url_ftell(&s->pb); + // pos = url_ftell(s->pb); // if (av_read_frame(s, &pkt) < 0){ // av_log(s, AV_LOG_INFO, "seek failed\n"); // return -1; @@ -1018,7 +1084,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int /* do the seek */ av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos); - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); } asf_reset_header(s); return 0; diff --git a/contrib/ffmpeg/libavformat/asf.h b/contrib/ffmpeg/libavformat/asf.h index 6d76ebecb..2486d8a6f 100644 --- a/contrib/ffmpeg/libavformat/asf.h +++ b/contrib/ffmpeg/libavformat/asf.h @@ -17,6 +17,13 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef FFMPEG_ASF_H +#define FFMPEG_ASF_H + +#include <stdint.h> +#include "avformat.h" + #define PACKET_SIZE 3200 typedef struct { @@ -49,7 +56,7 @@ typedef struct { uint64_t send_time; /**< time to send file, in 100-nanosecond units * invalid if broadcasting (could be ignored) */ uint32_t preroll; /**< timestamp of the first packet, in milliseconds - * if nonzero - substract from time */ + * if nonzero - subtract from time */ uint32_t ignore; ///< preroll is 64bit - but let's just ignore it uint32_t flags; /**< 0x01 - broadcast * 0x02 - seekable @@ -90,7 +97,7 @@ typedef struct { uint8_t packet_buf[PACKET_SIZE]; ByteIOContext pb; /* only for reading */ - uint64_t data_offset; ///< begining of the first data packet + uint64_t data_offset; ///< beginning of the first data packet uint64_t data_object_offset; ///< data object offset (excl. GUID & size) uint64_t data_object_size; ///< size of the data object int index_read; @@ -278,3 +285,5 @@ static const GUID my_guid = { #define ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE 0xc0 //1100 0000 #define ASF_PL_FLAG_KEY_FRAME 0x80 //1000 0000 + +#endif /* FFMPEG_ASF_H */ diff --git a/contrib/ffmpeg/libavformat/asfcrypt.c b/contrib/ffmpeg/libavformat/asfcrypt.c new file mode 100644 index 000000000..10cc934b4 --- /dev/null +++ b/contrib/ffmpeg/libavformat/asfcrypt.c @@ -0,0 +1,172 @@ +/* + * ASF decryption + * Copyright (c) 2007 Reimar Doeffinger + * This is a rewrite of code contained in freeme/freeme2 + * + * 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 "common.h" +#include "intreadwrite.h" +#include "bswap.h" +#include "des.h" +#include "rc4.h" +#include "asfcrypt.h" + +/** + * \brief find multiplicative inverse modulo 2 ^ 32 + * \param v number to invert, must be odd! + * \return number so that result * v = 1 (mod 2^32) + */ +static uint32_t inverse(uint32_t v) { + // v ^ 3 gives the inverse (mod 16), could also be implemented + // as table etc. (only lowest 4 bits matter!) + uint32_t inverse = v * v * v; + // uses a fixpoint-iteration that doubles the number + // of correct lowest bits each time + inverse *= 2 - v * inverse; + inverse *= 2 - v * inverse; + inverse *= 2 - v * inverse; + return inverse; +} + +/** + * \brief read keys from keybuf into keys + * \param keybuf buffer containing the keys + * \param keys output key array containing the keys for encryption in + * native endianness + */ +static void multiswap_init(const uint8_t keybuf[48], uint32_t keys[12]) { + int i; + for (i = 0; i < 12; i++) + keys[i] = AV_RL32(keybuf + (i << 2)) | 1; +} + +/** + * \brief invert the keys so that encryption become decryption keys and + * the other way round. + * \param keys key array of ints to invert + */ +static void multiswap_invert_keys(uint32_t keys[12]) { + int i; + for (i = 0; i < 5; i++) + keys[i] = inverse(keys[i]); + for (i = 6; i < 11; i++) + keys[i] = inverse(keys[i]); +} + +static uint32_t multiswap_step(const uint32_t keys[12], uint32_t v) { + int i; + v *= keys[0]; + for (i = 1; i < 5; i++) { + v = (v >> 16) | (v << 16); + v *= keys[i]; + } + v += keys[5]; + return v; +} + +static uint32_t multiswap_inv_step(const uint32_t keys[12], uint32_t v) { + int i; + v -= keys[5]; + for (i = 4; i > 0; i--) { + v *= keys[i]; + v = (v >> 16) | (v << 16); + } + v *= keys[0]; + return v; +} + +/** + * \brief "MultiSwap" encryption + * \param keys 32 bit numbers in machine endianness, + * 0-4 and 6-10 must be inverted from decryption + * \param key another key, this one must be the same for the decryption + * \param data data to encrypt + * \return encrypted data + */ +static uint64_t multiswap_enc(const uint32_t keys[12], uint64_t key, uint64_t data) { + uint32_t a = data; + uint32_t b = data >> 32; + uint32_t c; + uint32_t tmp; + a += key; + tmp = multiswap_step(keys , a); + b += tmp; + c = (key >> 32) + tmp; + tmp = multiswap_step(keys + 6, b); + c += tmp; + return ((uint64_t)c << 32) | tmp; +} + +/** + * \brief "MultiSwap" decryption + * \param keys 32 bit numbers in machine endianness, + * 0-4 and 6-10 must be inverted from encryption + * \param key another key, this one must be the same as for the encryption + * \param data data to decrypt + * \return decrypted data + */ +static uint64_t multiswap_dec(const uint32_t keys[12], uint64_t key, uint64_t data) { + uint32_t a; + uint32_t b; + uint32_t c = data >> 32; + uint32_t tmp = data; + c -= tmp; + b = multiswap_inv_step(keys + 6, tmp); + tmp = c - (key >> 32); + b -= tmp; + a = multiswap_inv_step(keys , tmp); + a -= key; + return ((uint64_t)b << 32) | a; +} + +void ff_asfcrypt_dec(const uint8_t key[20], uint8_t *data, int len) { + int num_qwords = len >> 3; + uint64_t *qwords = (uint64_t *)data; + uint64_t rc4buff[8]; + uint64_t packetkey; + uint32_t ms_keys[12]; + uint64_t ms_state; + int i; + if (len < 16) { + for (i = 0; i < len; i++) + data[i] ^= key[i]; + return; + } + + memset(rc4buff, 0, sizeof(rc4buff)); + ff_rc4_enc(key, 12, (uint8_t *)rc4buff, sizeof(rc4buff)); + multiswap_init((uint8_t *)rc4buff, ms_keys); + + packetkey = qwords[num_qwords - 1]; + packetkey ^= rc4buff[7]; + packetkey = be2me_64(packetkey); + packetkey = ff_des_encdec(packetkey, AV_RB64(key + 12), 1); + packetkey = be2me_64(packetkey); + packetkey ^= rc4buff[6]; + + ff_rc4_enc((uint8_t *)&packetkey, 8, data, len); + + ms_state = 0; + for (i = 0; i < num_qwords - 1; i++, qwords++) + ms_state = multiswap_enc(ms_keys, ms_state, AV_RL64(qwords)); + multiswap_invert_keys(ms_keys); + packetkey = (packetkey << 32) | (packetkey >> 32); + packetkey = le2me_64(packetkey); + packetkey = multiswap_dec(ms_keys, ms_state, packetkey); + AV_WL64(qwords, packetkey); +} diff --git a/contrib/ffmpeg/libavformat/asfcrypt.h b/contrib/ffmpeg/libavformat/asfcrypt.h new file mode 100644 index 000000000..dcd9c1da7 --- /dev/null +++ b/contrib/ffmpeg/libavformat/asfcrypt.h @@ -0,0 +1,29 @@ +/* + * ASF decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * 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 FFMPEG_ASFCRYPT_H +#define FFMPEG_ASFCRYPT_H + +#include <inttypes.h> + +void ff_asfcrypt_dec(const uint8_t key[20], uint8_t *data, int len); + +#endif /* FFMPEG_ASFCRYPT_H */ diff --git a/contrib/ffmpeg/libavformat/au.c b/contrib/ffmpeg/libavformat/au.c index 9e84c9d31..c6d5026e9 100644 --- a/contrib/ffmpeg/libavformat/au.c +++ b/contrib/ffmpeg/libavformat/au.c @@ -28,7 +28,7 @@ */ #include "avformat.h" -#include "allformats.h" +#include "raw.h" #include "riff.h" /* if we don't know the size in advance */ @@ -37,6 +37,7 @@ /* The ffmpeg codecs we support, and the IDs they have in the file */ static const AVCodecTag codec_au_tags[] = { { CODEC_ID_PCM_MULAW, 1 }, + { CODEC_ID_PCM_S8, 2 }, { CODEC_ID_PCM_S16BE, 3 }, { CODEC_ID_PCM_ALAW, 27 }, { 0, 0 }, @@ -59,7 +60,7 @@ static int put_au_header(ByteIOContext *pb, AVCodecContext *enc) static int au_write_header(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; s->priv_data = NULL; @@ -75,17 +76,17 @@ static int au_write_header(AVFormatContext *s) static int au_write_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; put_buffer(pb, pkt->data, pkt->size); return 0; } static int au_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; offset_t file_size; - if (!url_is_streamed(&s->pb)) { + if (!url_is_streamed(s->pb)) { /* update file size */ file_size = url_ftell(pb); @@ -103,8 +104,6 @@ static int au_write_trailer(AVFormatContext *s) static int au_probe(AVProbeData *p) { /* check file header */ - if (p->buf_size <= 24) - return 0; if (p->buf[0] == '.' && p->buf[1] == 's' && p->buf[2] == 'n' && p->buf[3] == 'd') return AVPROBE_SCORE_MAX; @@ -118,7 +117,7 @@ static int au_read_header(AVFormatContext *s, { int size; unsigned int tag; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; unsigned int id, codec, channels, rate; AVStream *st; @@ -160,11 +159,11 @@ static int au_read_packet(AVFormatContext *s, { int ret; - if (url_feof(&s->pb)) - return AVERROR_IO; - ret= av_get_packet(&s->pb, pkt, MAX_SIZE); + if (url_feof(s->pb)) + return AVERROR(EIO); + ret= av_get_packet(s->pb, pkt, MAX_SIZE); if (ret < 0) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = 0; /* note: we need to modify the packet size here to handle the last diff --git a/contrib/ffmpeg/libavformat/audio.c b/contrib/ffmpeg/libavformat/audio.c deleted file mode 100644 index a9e5bffd5..000000000 --- a/contrib/ffmpeg/libavformat/audio.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Linux audio play and grab interface - * Copyright (c) 2000, 2001 Fabrice Bellard. - * - * 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#ifdef HAVE_SOUNDCARD_H -#include <soundcard.h> -#else -#include <sys/soundcard.h> -#endif -#include <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> - -#define AUDIO_BLOCK_SIZE 4096 - -typedef struct { - int fd; - int sample_rate; - int channels; - int frame_size; /* in bytes ! */ - int codec_id; - int flip_left : 1; - uint8_t buffer[AUDIO_BLOCK_SIZE]; - int buffer_ptr; -} AudioData; - -static int audio_open(AudioData *s, int is_output, const char *audio_device) -{ - int audio_fd; - int tmp, err; - char *flip = getenv("AUDIO_FLIP_LEFT"); - - if (is_output) - audio_fd = open(audio_device, O_WRONLY); - else - audio_fd = open(audio_device, O_RDONLY); - if (audio_fd < 0) { - perror(audio_device); - return AVERROR_IO; - } - - if (flip && *flip == '1') { - s->flip_left = 1; - } - - /* non blocking mode */ - if (!is_output) - fcntl(audio_fd, F_SETFL, O_NONBLOCK); - - s->frame_size = AUDIO_BLOCK_SIZE; -#if 0 - tmp = (NB_FRAGMENTS << 16) | FRAGMENT_BITS; - err = ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &tmp); - if (err < 0) { - perror("SNDCTL_DSP_SETFRAGMENT"); - } -#endif - - /* select format : favour native format */ - err = ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp); - -#ifdef WORDS_BIGENDIAN - if (tmp & AFMT_S16_BE) { - tmp = AFMT_S16_BE; - } else if (tmp & AFMT_S16_LE) { - tmp = AFMT_S16_LE; - } else { - tmp = 0; - } -#else - if (tmp & AFMT_S16_LE) { - tmp = AFMT_S16_LE; - } else if (tmp & AFMT_S16_BE) { - tmp = AFMT_S16_BE; - } else { - tmp = 0; - } -#endif - - switch(tmp) { - case AFMT_S16_LE: - s->codec_id = CODEC_ID_PCM_S16LE; - break; - case AFMT_S16_BE: - s->codec_id = CODEC_ID_PCM_S16BE; - break; - default: - av_log(NULL, AV_LOG_ERROR, "Soundcard does not support 16 bit sample format\n"); - close(audio_fd); - return AVERROR_IO; - } - err=ioctl(audio_fd, SNDCTL_DSP_SETFMT, &tmp); - if (err < 0) { - perror("SNDCTL_DSP_SETFMT"); - goto fail; - } - - tmp = (s->channels == 2); - err = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); - if (err < 0) { - perror("SNDCTL_DSP_STEREO"); - goto fail; - } - if (tmp) - s->channels = 2; - - tmp = s->sample_rate; - err = ioctl(audio_fd, SNDCTL_DSP_SPEED, &tmp); - if (err < 0) { - perror("SNDCTL_DSP_SPEED"); - goto fail; - } - s->sample_rate = tmp; /* store real sample rate */ - s->fd = audio_fd; - - return 0; - fail: - close(audio_fd); - return AVERROR_IO; -} - -static int audio_close(AudioData *s) -{ - close(s->fd); - return 0; -} - -/* sound output support */ -static int audio_write_header(AVFormatContext *s1) -{ - AudioData *s = s1->priv_data; - AVStream *st; - int ret; - - st = s1->streams[0]; - s->sample_rate = st->codec->sample_rate; - s->channels = st->codec->channels; - ret = audio_open(s, 1, NULL); - if (ret < 0) { - return AVERROR_IO; - } else { - return 0; - } -} - -static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt) -{ - AudioData *s = s1->priv_data; - int len, ret; - int size= pkt->size; - uint8_t *buf= pkt->data; - - while (size > 0) { - len = AUDIO_BLOCK_SIZE - s->buffer_ptr; - if (len > size) - len = size; - memcpy(s->buffer + s->buffer_ptr, buf, len); - s->buffer_ptr += len; - if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) { - for(;;) { - ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE); - if (ret > 0) - break; - if (ret < 0 && (errno != EAGAIN && errno != EINTR)) - return AVERROR_IO; - } - s->buffer_ptr = 0; - } - buf += len; - size -= len; - } - return 0; -} - -static int audio_write_trailer(AVFormatContext *s1) -{ - AudioData *s = s1->priv_data; - - audio_close(s); - return 0; -} - -/* grab support */ - -static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap) -{ - AudioData *s = s1->priv_data; - AVStream *st; - int ret; - - if (ap->sample_rate <= 0 || ap->channels <= 0) - return -1; - - st = av_new_stream(s1, 0); - if (!st) { - return AVERROR(ENOMEM); - } - s->sample_rate = ap->sample_rate; - s->channels = ap->channels; - - ret = audio_open(s, 0, s1->filename); - if (ret < 0) { - av_free(st); - return AVERROR_IO; - } - - /* take real parameters */ - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = s->codec_id; - st->codec->sample_rate = s->sample_rate; - st->codec->channels = s->channels; - - av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ - return 0; -} - -static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - AudioData *s = s1->priv_data; - int ret, bdelay; - int64_t cur_time; - struct audio_buf_info abufi; - - if (av_new_packet(pkt, s->frame_size) < 0) - return AVERROR_IO; - for(;;) { - struct timeval tv; - fd_set fds; - - tv.tv_sec = 0; - tv.tv_usec = 30 * 1000; /* 30 msecs -- a bit shorter than 1 frame at 30fps */ - - FD_ZERO(&fds); - FD_SET(s->fd, &fds); - - /* This will block until data is available or we get a timeout */ - (void) select(s->fd + 1, &fds, 0, 0, &tv); - - ret = read(s->fd, pkt->data, pkt->size); - if (ret > 0) - break; - if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { - av_free_packet(pkt); - pkt->size = 0; - pkt->pts = av_gettime(); - return 0; - } - if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) { - av_free_packet(pkt); - return AVERROR_IO; - } - } - pkt->size = ret; - - /* compute pts of the start of the packet */ - cur_time = av_gettime(); - bdelay = ret; - if (ioctl(s->fd, SNDCTL_DSP_GETISPACE, &abufi) == 0) { - bdelay += abufi.bytes; - } - /* substract time represented by the number of bytes in the audio fifo */ - cur_time -= (bdelay * 1000000LL) / (s->sample_rate * s->channels); - - /* convert to wanted units */ - pkt->pts = cur_time; - - if (s->flip_left && s->channels == 2) { - int i; - short *p = (short *) pkt->data; - - for (i = 0; i < ret; i += 4) { - *p = ~*p; - p += 2; - } - } - return 0; -} - -static int audio_read_close(AVFormatContext *s1) -{ - AudioData *s = s1->priv_data; - - audio_close(s); - return 0; -} - -#ifdef CONFIG_AUDIO_DEMUXER -AVInputFormat audio_demuxer = { - "audio_device", - "audio grab and output", - sizeof(AudioData), - NULL, - audio_read_header, - audio_read_packet, - audio_read_close, - .flags = AVFMT_NOFILE, -}; -#endif - -#ifdef CONFIG_AUDIO_MUXER -AVOutputFormat audio_muxer = { - "audio_device", - "audio grab and output", - "", - "", - sizeof(AudioData), - /* XXX: we make the assumption that the soundcard accepts this format */ - /* XXX: find better solution with "preinit" method, needed also in - other formats */ -#ifdef WORDS_BIGENDIAN - CODEC_ID_PCM_S16BE, -#else - CODEC_ID_PCM_S16LE, -#endif - CODEC_ID_NONE, - audio_write_header, - audio_write_packet, - audio_write_trailer, - .flags = AVFMT_NOFILE, -}; -#endif diff --git a/contrib/ffmpeg/libavformat/avc.c b/contrib/ffmpeg/libavformat/avc.c new file mode 100644 index 000000000..0c180c86b --- /dev/null +++ b/contrib/ffmpeg/libavformat/avc.c @@ -0,0 +1,135 @@ +/* + * AVC helper functions for muxers + * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com> + * + * 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 "avio.h" + +const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end) +{ + const uint8_t *a = p + 4 - ((long)p & 3); + + for( end -= 3; p < a && p < end; p++ ) { + if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) + return p; + } + + for( end -= 3; p < end; p += 4 ) { + uint32_t x = *(const uint32_t*)p; +// if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian +// if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian + if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic + if( p[1] == 0 ) { + if( p[0] == 0 && p[2] == 1 ) + return p-1; + if( p[2] == 0 && p[3] == 1 ) + return p; + } + if( p[3] == 0 ) { + if( p[2] == 0 && p[4] == 1 ) + return p+1; + if( p[4] == 0 && p[5] == 1 ) + return p+2; + } + } + } + + for( end += 3; p < end; p++ ) { + if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) + return p; + } + + return end + 3; +} + +int ff_avc_parse_nal_units(const uint8_t *buf_in, uint8_t **buf, int *size) +{ + ByteIOContext *pb; + const uint8_t *p = buf_in; + const uint8_t *end = p + *size; + const uint8_t *nal_start, *nal_end; + int ret = url_open_dyn_buf(&pb); + if(ret < 0) + return ret; + + nal_start = ff_avc_find_startcode(p, end); + while (nal_start < end) { + while(!*(nal_start++)); + nal_end = ff_avc_find_startcode(nal_start, end); + put_be32(pb, nal_end - nal_start); + put_buffer(pb, nal_start, nal_end - nal_start); + nal_start = nal_end; + } + av_freep(buf); + *size = url_close_dyn_buf(pb, buf); + return 0; +} + +int ff_isom_write_avcc(ByteIOContext *pb, const uint8_t *data, int len) +{ + if (len > 6) { + /* check for h264 start code */ + if (AV_RB32(data) == 0x00000001) { + uint8_t *buf=NULL, *end, *start; + uint32_t sps_size=0, pps_size=0; + uint8_t *sps=0, *pps=0; + + int ret = ff_avc_parse_nal_units(data, &buf, &len); + if (ret < 0) + return ret; + start = buf; + end = buf + len; + + /* look for sps and pps */ + while (buf < end) { + unsigned int size; + uint8_t nal_type; + size = AV_RB32(buf); + nal_type = buf[4] & 0x1f; + if (nal_type == 7) { /* SPS */ + sps = buf + 4; + sps_size = size; + } else if (nal_type == 8) { /* PPS */ + pps = buf + 4; + pps_size = size; + } + buf += size + 4; + } + assert(sps); + assert(pps); + + put_byte(pb, 1); /* version */ + put_byte(pb, sps[1]); /* profile */ + put_byte(pb, sps[2]); /* profile compat */ + put_byte(pb, sps[3]); /* level */ + put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ + put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ + + put_be16(pb, sps_size); + put_buffer(pb, sps, sps_size); + put_byte(pb, 1); /* number of pps */ + put_be16(pb, pps_size); + put_buffer(pb, pps, pps_size); + av_free(start); + } else { + put_buffer(pb, data, len); + } + } + return 0; +} diff --git a/contrib/ffmpeg/libavformat/avc.h b/contrib/ffmpeg/libavformat/avc.h new file mode 100644 index 000000000..334aa4347 --- /dev/null +++ b/contrib/ffmpeg/libavformat/avc.h @@ -0,0 +1,32 @@ +/* + * AVC helper functions for muxers + * Copyright (c) 2008 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 + */ + +#ifndef AVC_H +#define AVC_H + +#include <stdint.h> +#include "avio.h" + +int ff_avc_parse_nal_units(const uint8_t *buf_in, uint8_t **buf, int *size); +int ff_isom_write_avcc(ByteIOContext *pb, const uint8_t *data, int len); +const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end); + +#endif /* AVC_H */ diff --git a/contrib/ffmpeg/libavformat/avformat.h b/contrib/ffmpeg/libavformat/avformat.h index eb8c4e153..ad186e443 100644 --- a/contrib/ffmpeg/libavformat/avformat.h +++ b/contrib/ffmpeg/libavformat/avformat.h @@ -18,22 +18,26 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFORMAT_H -#define AVFORMAT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define LIBAVFORMAT_VERSION_INT ((51<<16)+(11<<8)+0) -#define LIBAVFORMAT_VERSION 51.11.0 +#ifndef FFMPEG_AVFORMAT_H +#define FFMPEG_AVFORMAT_H + +#define LIBAVFORMAT_VERSION_MAJOR 52 +#define LIBAVFORMAT_VERSION_MINOR 7 +#define LIBAVFORMAT_VERSION_MICRO 0 + +#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) #define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) #include <time.h> #include <stdio.h> /* FILE */ -#include "avcodec.h" +#include "libavcodec/avcodec.h" #include "avio.h" @@ -60,20 +64,15 @@ void av_destruct_packet_nofree(AVPacket *pkt); */ void av_destruct_packet(AVPacket *pkt); -/* initialize optional fields of a packet */ -static inline void av_init_packet(AVPacket *pkt) -{ - pkt->pts = AV_NOPTS_VALUE; - pkt->dts = AV_NOPTS_VALUE; - pkt->pos = -1; - pkt->duration = 0; - pkt->flags = 0; - pkt->stream_index = 0; - pkt->destruct= av_destruct_packet_nofree; -} +/** + * Initialize optional fields of a packet to default values. + * + * @param pkt packet + */ +void av_init_packet(AVPacket *pkt); /** - * Allocate the payload of a packet and intialized its fields to default values. + * Allocate the payload of a packet and initialize its fields to default values. * * @param pkt packet * @param size wanted payload size @@ -82,7 +81,7 @@ static inline void av_init_packet(AVPacket *pkt) int av_new_packet(AVPacket *pkt, int size); /** - * Allocate and read the payload of a packet and intialized its fields to default values. + * Allocate and read the payload of a packet and initialize its fields to default values. * * @param pkt packet * @param size wanted payload size @@ -111,8 +110,11 @@ static inline void av_free_packet(AVPacket *pkt) /*************************************************/ /* fractional numbers for exact pts handling */ -/* the exact value of the fractional number is: 'val + num / den'. num - is assumed to be such as 0 <= num < den */ +/** + * the exact value of the fractional number is: 'val + num / den'. + * num is assumed to be such as 0 <= num < den + * @deprecated Use AVRational instead +*/ typedef struct AVFrac { int64_t val, num, den; } AVFrac attribute_deprecated; @@ -132,6 +134,7 @@ typedef struct AVProbeData { } AVProbeData; #define AVPROBE_SCORE_MAX 100 ///< max score, half of that is used for file extension based detection +#define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer typedef struct AVFormatParameters { AVRational time_base; @@ -141,19 +144,18 @@ typedef struct AVFormatParameters { int height; enum PixelFormat pix_fmt; int channel; /**< used to select dv channel */ -#if LIBAVFORMAT_VERSION_INT < (52<<16) - const char *device; /**< video, audio or DV device */ -#endif const char *standard; /**< tv standard, NTSC, PAL, SECAM */ int mpeg2ts_raw:1; /**< force raw MPEG2 transport stream output, if possible */ int mpeg2ts_compute_pcr:1; /**< compute exact PCR for each transport stream packet (only meaningful if - mpeg2ts_raw is TRUE */ + mpeg2ts_raw is TRUE) */ int initial_pause:1; /**< do not begin to play the stream immediately (RTSP only) */ int prealloced_context:1; +#if LIBAVFORMAT_VERSION_INT < (53<<16) enum CodecID video_codec_id; enum CodecID audio_codec_id; +#endif } AVFormatParameters; //! demuxer will use url_fopen, no opened file should be provided by the caller @@ -163,7 +165,7 @@ typedef struct AVFormatParameters { #define AVFMT_RAWPICTURE 0x0020 /**< format wants AVPicture structure for raw picture data */ #define AVFMT_GLOBALHEADER 0x0040 /**< format wants global header */ -#define AVFMT_NOTIMESTAMPS 0x0080 /**< format doesnt need / has any timestamps */ +#define AVFMT_NOTIMESTAMPS 0x0080 /**< format does not need / have any timestamps */ #define AVFMT_GENERIC_INDEX 0x0100 /**< use generic index building code */ typedef struct AVOutputFormat { @@ -191,6 +193,8 @@ typedef struct AVOutputFormat { */ const struct AVCodecTag **codec_tag; + enum CodecID subtitle_codec; /**< default subtitle codec */ + /* private fields */ struct AVOutputFormat *next; } AVOutputFormat; @@ -200,11 +204,15 @@ typedef struct AVInputFormat { const char *long_name; /** size of private data so that it can be allocated in the wrapper */ int priv_data_size; - /** tell if a given file has a chance of being parsing by this format */ + /** + * Tell if a given file has a chance of being parsed by this format. + * The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes + * big so you do not have to check for that unless you need more. + */ int (*read_probe)(AVProbeData *); /** read the format header and initialize the AVFormatContext structure. Return 0 if OK. 'ap' if non NULL contains - additionnal paramters. Only used in raw format right + additional paramters. Only used in raw format right now. 'av_new_stream' should be called to create new streams. */ int (*read_header)(struct AVFormatContext *, AVFormatParameters *ap); @@ -221,11 +229,13 @@ typedef struct AVInputFormat { * @param stream_index must not be -1 * @param flags selects which direction should be preferred if no exact * match is available + * @return >= 0 on success (but not necessarily the new offset) */ int (*read_seek)(struct AVFormatContext *, int stream_index, int64_t timestamp, int flags); /** - * gets the next timestamp in AV_TIME_BASE units. + * gets the next timestamp in stream[stream_index].time_base units. + * @return the timestamp or AV_NOPTS_VALUE if an error occured */ int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, int64_t *pos, int64_t pos_limit); @@ -252,63 +262,84 @@ typedef struct AVInputFormat { struct AVInputFormat *next; } AVInputFormat; +enum AVStreamParseType { + AVSTREAM_PARSE_NONE, + AVSTREAM_PARSE_FULL, /**< full parsing and repack */ + AVSTREAM_PARSE_HEADERS, /**< only parse headers, don't repack */ + AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on packet boundary */ +}; + typedef struct AVIndexEntry { int64_t pos; int64_t timestamp; #define AVINDEX_KEYFRAME 0x0001 int flags:2; - int size:30; //yeah trying to keep the size of this small to reduce memory requirements (its 24 vs 32 byte due to possible 8byte align) + int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs 32 byte due to possible 8byte align). int min_distance; /**< min distance between this and the previous keyframe, used to avoid unneeded searching */ } AVIndexEntry; +/** + * Stream structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVStream) must not be used outside libav*. + */ typedef struct AVStream { int index; /**< stream index in AVFormatContext */ int id; /**< format specific stream id */ AVCodecContext *codec; /**< codec context */ /** - * real base frame rate of the stream. - * this is the lowest framerate with which all timestamps can be - * represented accurately (its the least common multiple of all - * framerates in the stream), Note, this value is just a guess! - * for example if the timebase is 1/90000 and all frames have either - * approximately 3600 or 1800 timer ticks then r_frame_rate will be 50/1 + * Real base frame rate of the stream. + * This is the lowest frame rate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * frame rates in the stream), Note, this value is just a guess! + * For example if the timebase is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks then r_frame_rate will be 50/1. */ AVRational r_frame_rate; void *priv_data; -#if LIBAVFORMAT_VERSION_INT < (52<<16) + /* internal data used in av_find_stream_info() */ - int64_t codec_info_duration; - int codec_info_nb_frames; -#endif + int64_t first_dts; /** encoding: PTS generation when outputing stream */ - AVFrac pts; + struct AVFrac pts; /** - * 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 + * 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/frame rate and timestamp increments should be * identically 1. */ AVRational time_base; int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ /* ffmpeg.c private use */ int stream_copy; /**< if set, just copy stream */ - enum AVDiscard discard; ///< selects which packets can be discarded at will and dont need to be demuxed + enum AVDiscard discard; ///< selects which packets can be discarded at will and do not need to be demuxed //FIXME move stuff to a flags field? /** quality, as it has been removed from AVCodecContext and put in AVVideoFrame - * MN:dunno if thats the right place, for it */ + * MN: dunno if that is the right place for it */ float quality; - /** decoding: position of the first frame of the component, in - AV_TIME_BASE fractional seconds. */ + /** + * Decoding: pts of the first frame of the stream, 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; - /** decoding: duration of the stream, in AV_TIME_BASE fractional - seconds. */ + /** + * Decoding: duration of the stream, in stream time base. + * If a source file does not specify a duration, but does specify + * a bitrate, this value will be estimates from bit rate and file size. + */ int64_t duration; char language[4]; /** ISO 639 3-letter language code (empty string if undefined) */ /* av_read_frame() support */ - int need_parsing; ///< 1->full parsing needed, 2->only parse headers dont repack + enum AVStreamParseType need_parsing; struct AVCodecParserContext *parser; int64_t cur_dts; @@ -324,21 +355,47 @@ typedef struct AVStream { #define MAX_REORDER_DELAY 4 int64_t pts_buffer[MAX_REORDER_DELAY+1]; + + char *filename; /**< source filename of the stream */ } AVStream; +#define AV_PROGRAM_RUNNING 1 + +/** + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVProgram) must not be used outside libav*. + */ +typedef struct AVProgram { + int id; + char *provider_name; ///< Network name for DVB streams + char *name; ///< Service name for DVB streams + int flags; + enum AVDiscard discard; ///< selects which program to discard and which to feed to the caller + unsigned int *stream_index; + unsigned int nb_stream_indexes; +} AVProgram; + #define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present (streams are added dynamically) */ #define MAX_STREAMS 20 -/* format I/O context */ +/** + * format I/O context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVFormatContext) must not be used outside libav*. + */ typedef struct AVFormatContext { const AVClass *av_class; /**< set by av_alloc_format_context */ /* can only be iformat or oformat, not both at the same time */ struct AVInputFormat *iformat; struct AVOutputFormat *oformat; void *priv_data; - ByteIOContext pb; + ByteIOContext *pb; unsigned int nb_streams; AVStream *streams[MAX_STREAMS]; char filename[1024]; /**< input or output filename */ @@ -398,6 +455,7 @@ typedef struct AVFormatContext { int flags; #define AVFMT_FLAG_GENPTS 0x0001 ///< generate pts if missing even if it requires parsing future frames #define AVFMT_FLAG_IGNIDX 0x0002 ///< ignore index +#define AVFMT_FLAG_NONBLOCK 0x0004 ///< do not block when reading packets from input int loop_input; /** decoding: size of data to probe; encoding unused */ @@ -410,6 +468,37 @@ typedef struct AVFormatContext { const uint8_t *key; int keylen; + + unsigned int nb_programs; + AVProgram **programs; + + /** + * Forced video codec_id. + * demuxing: set by user + */ + enum CodecID video_codec_id; + /** + * Forced audio codec_id. + * demuxing: set by user + */ + enum CodecID audio_codec_id; + /** + * Forced subtitle codec_id. + * demuxing: set by user + */ + enum CodecID subtitle_codec_id; + + /** + * Maximum amount of memory in bytes to use per stream for the index. + * If the needed index exceeds this size entries will be discarded as + * needed to maintain a smaller size. This can lead to slower or less + * accurate seeking (depends on demuxer). + * Demuxers for which a full in memory index is mandatory will ignore + * this. + * muxing : unused + * demuxing: set by user + */ + unsigned int max_index_size; } AVFormatContext; typedef struct AVPacketList { @@ -417,18 +506,19 @@ typedef struct AVPacketList { struct AVPacketList *next; } AVPacketList; +#if LIBAVFORMAT_VERSION_INT < (53<<16) extern AVInputFormat *first_iformat; extern AVOutputFormat *first_oformat; +#endif + +AVInputFormat *av_iformat_next(AVInputFormat *f); +AVOutputFormat *av_oformat_next(AVOutputFormat *f); enum CodecID av_guess_image2_codec(const char *filename); /* XXX: use automatic init with either ELF sections or C file parser */ /* modules */ -#include "rtp.h" - -#include "rtsp.h" - /* utils.c */ void av_register_input_format(AVInputFormat *format); void av_register_output_format(AVOutputFormat *format); @@ -519,21 +609,25 @@ int av_open_input_stream(AVFormatContext **ic_ptr, AVInputFormat *fmt, AVFormatParameters *ap); /** - * Open a media file as input. The codec are not opened. Only the file + * Open a media file as input. The codecs are not opened. Only the file * header (if present) is read. * * @param ic_ptr the opened media file handle is put here * @param filename filename to open. * @param fmt if non NULL, force the file format to use * @param buf_size optional buffer size (zero if default is OK) - * @param ap additionnal parameters needed when opening the file (NULL if default) + * @param ap additional parameters needed when opening the file (NULL if default) * @return 0 if OK. AVERROR_xxx otherwise. */ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap); -/** no av_open for output, so applications will need this: */ +/** + * Allocate an AVFormatContext. + * Can be freed with av_free() but do not forget to free everything you + * explicitly allocated as well! + */ AVFormatContext *av_alloc_format_context(void); /** @@ -546,14 +640,14 @@ AVFormatContext *av_alloc_format_context(void); * * @param ic media file handle * @return >=0 if OK. AVERROR_xxx if error. - * @todo let user decide somehow what information is needed so we dont waste time geting stuff the user doesnt need + * @todo Let user decide somehow what information is needed so we do not waste time getting stuff the user does not need. */ int av_find_stream_info(AVFormatContext *ic); /** * Read a transport packet from a media file. * - * This function is absolete and should never be used. + * This function is obsolete and should never be used. * Use av_read_frame() instead. * * @param s media file handle @@ -610,6 +704,12 @@ int av_read_play(AVFormatContext *s); int av_read_pause(AVFormatContext *s); /** + * Free a AVFormatContext allocated by av_open_input_stream. + * @param s context to free + */ +void av_close_input_stream(AVFormatContext *s); + +/** * Close a media file (but not its codecs). * * @param s media file handle @@ -627,6 +727,7 @@ void av_close_input_file(AVFormatContext *s); * @param id file format dependent stream id */ AVStream *av_new_stream(AVFormatContext *s, int id); +AVProgram *av_new_program(AVFormatContext *s, int id); /** * Set the pts for a given stream. @@ -657,6 +758,15 @@ int av_find_default_stream_index(AVFormatContext *s); int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); /** + * Ensures the index uses less memory than the maximum specified in + * AVFormatContext.max_index_size, by discarding entries if it grows + * too large. + * This function is not part of the public API and should only be called + * by demuxers. + */ +void ff_reduce_index(AVFormatContext *s, int stream_index); + +/** * Add a index entry into a sorted list updateing if it is already there. * * @param timestamp timestamp in the timebase of the given stream @@ -666,7 +776,7 @@ int av_add_index_entry(AVStream *st, /** * Does a binary search using av_index_search_timestamp() and AVCodec.read_timestamp(). - * this isnt supposed to be called directly by a user application, but by demuxers + * This is not supposed to be called directly by a user application, but by demuxers. * @param target_ts target timestamp in the time base of the given stream * @param stream_index stream number */ @@ -676,7 +786,7 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts * Updates cur_dts of all streams based on given timestamp and AVStream. * * Stream ref_st unchanged, others set cur_dts in their native timebase - * only needed for timestamp wrapping or if (dts not set and pts!=dts) + * only needed for timestamp wrapping or if (dts not set and pts!=dts). * @param timestamp new dts expressed in time_base of param ref_st * @param ref_st reference stream giving time_base of param timestamp */ @@ -684,7 +794,7 @@ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp); /** * Does a binary search using read_timestamp(). - * this isnt supposed to be called directly by a user application, but by demuxers + * This is not supposed to be called directly by a user application, but by demuxers. * @param target_ts target timestamp in the time base of the given stream * @param stream_index stream number */ @@ -694,8 +804,8 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, i int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap); /** - * allocate the stream private data and write the stream header to an - * output media file + * Allocate the stream private data and write the stream header to an + * output media file. * * @param s media file handle * @return 0 if OK. AVERROR_xxx if error. @@ -720,10 +830,10 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt); * * The packet must contain one audio or video frame. * If the packets are already correctly interleaved the application should - * call av_write_frame() instead as its slightly faster, its also important - * to keep in mind that completly non interleaved input will need huge amounts - * of memory to interleave with this, so its prefereable to interleave at the - * demuxer level + * call av_write_frame() instead as it is slightly faster. It is also important + * to keep in mind that completely non-interleaved input will need huge amounts + * of memory to interleave with this, so it is preferable to interleave at the + * demuxer level. * * @param s media file handle * @param pkt the packet, which contains the stream_index, buf/buf_size, dts/pts, ... @@ -763,28 +873,41 @@ void dump_format(AVFormatContext *ic, /** * parses width and height out of string str. + * @deprecated Use av_parse_video_frame_size instead. */ -int parse_image_size(int *width_ptr, int *height_ptr, const char *str); +attribute_deprecated int parse_image_size(int *width_ptr, int *height_ptr, const char *str); /** * Converts frame rate from string to a fraction. + * @deprecated Use av_parse_video_frame_rate instead. */ -int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg); +attribute_deprecated int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg); /** - * Converts date string to number of seconds since Jan 1st, 1970. - * + * Parses \p datestr and returns a corresponding number of microseconds. + * @param datestr String representing a date or a duration. + * - If a date the syntax is: * @code - * Syntax: - * - If not a duration: * [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]} - * Time is localtime unless Z is suffixed to the end. In this case GMT - * Return the date in micro seconds since 1970 - * - * - If a duration: - * HH[:MM[:SS[.m...]]] - * S+[.m...] * @endcode + * Time is localtime unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part isn't specified it takes the current + * year-month-day. + * Returns the number of microseconds since 1st of January, 1970 up to + * the time of the parsed date or INT64_MIN if \p datestr cannot be + * successfully parsed. + * - If a duration the syntax is: + * @code + * [-]HH[:MM[:SS[.m...]]] + * [-]S+[.m...] + * @endcode + * Returns the number of microseconds contained in a time interval + * with the specified duration or INT64_MIN if \p datestr cannot be + * successfully parsed. + * @param duration Flag which tells how to interpret \p datestr, if + * not zero \p datestr is interpreted as a duration, otherwise as a + * date. */ int64_t parse_date(const char *datestr, int duration); @@ -813,7 +936,7 @@ int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); * @param buf destination buffer * @param buf_size destination buffer size * @param path numbered sequence string - * @number frame number + * @param number frame number * @return 0 if OK, -1 if format error. */ int av_get_frame_filename(char *buf, int buf_size, @@ -827,23 +950,24 @@ int av_get_frame_filename(char *buf, int buf_size, */ int av_filename_number_test(const char *filename); -/* grab specific */ -int video_grab_init(void); -int audio_init(void); - -/* DV1394 */ -int dv1394_init(void); -int dc1394_init(void); +/** + * Generate an SDP for an RTP session. + * + * @param ac array of AVFormatContexts describing the RTP streams. If the + * array is composed by only one context, such context can contain + * multiple AVStreams (one AVStream per RTP stream). Otherwise, + * all the contexts in the array (an AVCodecContext per RTP stream) + * must contain only one AVStream + * @param n_files number of AVCodecContexts contained in ac + * @param buff buffer where the SDP will be stored (must be allocated by + * the caller + * @param size the size of the buffer + * @return 0 if OK. AVERROR_xxx if error. + */ +int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size); #ifdef HAVE_AV_CONFIG_H -#include "os_support.h" - -int strstart(const char *str, const char *val, const char **ptr); -int stristart(const char *str, const char *val, const char **ptr); -void pstrcpy(char *buf, int buf_size, const char *str); -char *pstrcat(char *buf, int buf_size, const char *s); - void __dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem); #ifdef __GNUC__ @@ -880,9 +1004,4 @@ int match_ext(const char *filename, const char *extensions); #endif /* HAVE_AV_CONFIG_H */ -#ifdef __cplusplus -} -#endif - -#endif /* AVFORMAT_H */ - +#endif /* FFMPEG_AVFORMAT_H */ diff --git a/contrib/ffmpeg/libavformat/avidec.c b/contrib/ffmpeg/libavformat/avidec.c index 23c130ab7..4b9bcf2a4 100644 --- a/contrib/ffmpeg/libavformat/avidec.c +++ b/contrib/ffmpeg/libavformat/avidec.c @@ -48,6 +48,7 @@ typedef struct AVIStream { typedef struct { int64_t riff_end; int64_t movi_end; + int64_t fsize; offset_t movi_list; int index_loaded; int is_odml; @@ -56,6 +57,15 @@ typedef struct { DVDemuxContext* dv_demux; } AVIContext; +static const char avi_headers[][8] = { + { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' }, + { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' }, + { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19}, + { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' }, + { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' }, + { 0 } +}; + static int avi_load_index(AVFormatContext *s); static int guess_ni_flag(AVFormatContext *s); @@ -73,27 +83,30 @@ static void print_tag(const char *str, unsigned int tag, int size) static int get_riff(AVIContext *avi, ByteIOContext *pb) { - uint32_t tag; - /* check RIFF header */ - tag = get_le32(pb); + char header[8]; + int i; - if (tag != MKTAG('R', 'I', 'F', 'F')) - return -1; + /* check RIFF header */ + get_buffer(pb, header, 4); avi->riff_end = get_le32(pb); /* RIFF chunk size */ avi->riff_end += url_ftell(pb); /* RIFF chunk end */ - tag = get_le32(pb); - if(tag == MKTAG('A', 'V', 'I', 0x19)) - av_log(NULL, AV_LOG_INFO, "file has been generated with a totally broken muxer\n"); - else - if (tag != MKTAG('A', 'V', 'I', ' ') && tag != MKTAG('A', 'V', 'I', 'X')) + get_buffer(pb, header+4, 4); + + for(i=0; avi_headers[i][0]; i++) + if(!memcmp(header, avi_headers[i], 8)) + break; + if(!avi_headers[i][0]) return -1; + if(header[7] == 0x19) + av_log(NULL, AV_LOG_INFO, "file has been generated with a totally broken muxer\n"); + return 0; } static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int longs_pre_entry= get_le16(pb); int index_sub_type = get_byte(pb); int index_type = get_byte(pb); @@ -105,7 +118,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ AVIStream *ast; int i; int64_t last_pos= -1; - int64_t filesize= url_fsize(&s->pb); + int64_t filesize= url_fsize(s->pb); #ifdef DEBUG_SEEK av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16"PRIX64"\n", @@ -212,7 +225,7 @@ static int avi_read_tag(ByteIOContext *pb, char *buf, int maxlen, unsigned int static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint32_t tag, tag1, handler; int codec_type, stream_index, frame_period, bit_rate; unsigned int size, nb_frames; @@ -220,12 +233,18 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) AVStream *st; AVIStream *ast = NULL; char str_track[4]; + int avih_width=0, avih_height=0; + int amv_file_format=0; avi->stream_index= -1; if (get_riff(avi, pb) < 0) return -1; + avi->fsize = url_fsize(pb); + if(avi->fsize<=0) + avi->fsize= avi->riff_end; + /* first list tag */ stream_index = -1; codec_type = -1; @@ -260,6 +279,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) avi->is_odml = 1; url_fskip(pb, size + (size & 1)); break; + case MKTAG('a', 'm', 'v', 'h'): + amv_file_format=1; case MKTAG('a', 'v', 'i', 'h'): /* avi header */ /* using frame_period is bad idea */ @@ -270,8 +291,11 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) url_fskip(pb, 2 * 4); get_le32(pb); + get_le32(pb); + avih_width=get_le32(pb); + avih_height=get_le32(pb); - url_fskip(pb, size - 7 * 4); + url_fskip(pb, size - 10 * 4); break; case MKTAG('s', 't', 'r', 'h'): /* stream header */ @@ -293,6 +317,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) goto fail; st->priv_data = ast; } + if(amv_file_format) + tag1 = stream_index ? MKTAG('a','u','d','s') : MKTAG('v','i','d','s'); #ifdef DEBUG print_tag("strh", tag1, -1); @@ -400,6 +426,14 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) st = s->streams[stream_index]; switch(codec_type) { case CODEC_TYPE_VIDEO: + if(amv_file_format){ + st->codec->width=avih_width; + st->codec->height=avih_height; + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_AMV; + url_fskip(pb, size); + break; + } get_le32(pb); /* size */ st->codec->width = get_le32(pb); st->codec->height = get_le32(pb); @@ -412,6 +446,13 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) get_le32(pb); /* ClrUsed */ get_le32(pb); /* ClrImportant */ + if (tag1 == MKTAG('D', 'X', 'S', 'B')) { + st->codec->codec_type = CODEC_TYPE_SUBTITLE; + st->codec->codec_tag = tag1; + st->codec->codec_id = CODEC_ID_XSUB; + break; + } + if(size > 10*4 && size<(1<<30)){ st->codec->extradata_size= size - 10*4; st->codec->extradata= av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); @@ -442,7 +483,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_tag = tag1; st->codec->codec_id = codec_get_id(codec_bmp_tags, tag1); - st->need_parsing = 2; //only parse headers dont do slower repacketization, this is needed to get the pict type which is needed for generating correct pts + st->need_parsing = AVSTREAM_PARSE_HEADERS; // this is needed to get the pict type which is needed for generating correct pts // url_fskip(pb, size - 5 * 4); break; case CODEC_TYPE_AUDIO: @@ -452,17 +493,19 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ url_fskip(pb, 1); /* Force parsing as several audio frames can be in - * one packet. */ - st->need_parsing = 1; + * one packet and timestamps refer to packet start*/ + st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; /* ADTS header is in extradata, AAC without header must be stored as exact frames, parser not needed and it will fail */ if (st->codec->codec_id == CODEC_ID_AAC && st->codec->extradata_size) - st->need_parsing = 0; + st->need_parsing = AVSTREAM_PARSE_NONE; /* AVI files with Xan DPCM audio (wrongly) declare PCM * audio in the header but have Axan as stream_code_tag. */ if (st->codec->stream_codec_tag == ff_get_fourcc("Axan")){ st->codec->codec_id = CODEC_ID_XAN_DPCM; st->codec->codec_tag = 0; } + if (amv_file_format) + st->codec->codec_id = CODEC_ID_ADPCM_IMA_AMV; break; default: st->codec->codec_type = CODEC_TYPE_DATA; @@ -480,6 +523,31 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) } url_fseek(pb, i+size, SEEK_SET); break; + case MKTAG('v', 'p', 'r', 'p'): + if(stream_index < (unsigned)s->nb_streams && size > 9*4){ + AVRational active, active_aspect; + + st = s->streams[stream_index]; + get_le32(pb); + get_le32(pb); + get_le32(pb); + get_le32(pb); + get_le32(pb); + + active_aspect.num= get_le16(pb); + active_aspect.den= get_le16(pb); + active.num = get_le32(pb); + active.den = get_le32(pb); + get_le32(pb); //nbFieldsPerFrame + + if(active_aspect.num && active_aspect.den && active.num && active.den){ + st->codec->sample_aspect_ratio= av_div_q(active_aspect, active); +//av_log(s, AV_LOG_ERROR, "vprp %d/%d %d/%d\n", active_aspect.num, active_aspect.den, active.num, active.den); + } + size -= 9*4; + } + url_fseek(pb, size, SEEK_CUR); + break; case MKTAG('I', 'N', 'A', 'M'): avi_read_tag(pb, s->title, sizeof(s->title), size); break; @@ -540,7 +608,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int n, d[8], size; offset_t i, sync; void* dstr; @@ -585,7 +653,7 @@ 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; - url_fseek(&s->pb, pos + 8, SEEK_SET); + url_fseek(s->pb, pos + 8, SEEK_SET); // av_log(NULL, AV_LOG_DEBUG, "pos=%"PRId64"\n", pos); assert(best_ast->remaining <= best_ast->packet_size); @@ -662,14 +730,6 @@ resync: for(i=sync=url_ftell(pb); !url_feof(pb); i++) { int j; - if (i >= avi->movi_end) { - if (avi->is_odml) { - url_fskip(pb, avi->riff_end - i); - avi->riff_end = avi->movi_end = url_fsize(pb); - } else - break; - } - for(j=0; j<7; j++) d[j]= d[j+1]; d[7]= get_byte(pb); @@ -683,13 +743,14 @@ resync: n= 100; //invalid stream id } //av_log(NULL, AV_LOG_DEBUG, "%X %X %X %X %X %X %X %X %"PRId64" %d %d\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n); - if(i + size > avi->movi_end || d[0]<0) + if(i + size > avi->fsize || d[0]<0) continue; //parse ix## if( (d[0] == 'i' && d[1] == 'x' && n < s->nb_streams) //parse JUNK - ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')){ + ||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K') + ||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){ url_fskip(pb, size); //av_log(NULL, AV_LOG_DEBUG, "SKIP\n"); goto resync; @@ -748,7 +809,7 @@ resync: if ( d[0] >= '0' && d[0] <= '9' && d[1] >= '0' && d[1] <= '9' && ((d[2] == 'p' && d[3] == 'c')) - && n < s->nb_streams && i + size <= avi->movi_end) { + && n < s->nb_streams && i + size <= avi->fsize) { AVStream *st; int first, clr, flags, k, p; @@ -783,7 +844,7 @@ resync: static int avi_read_idx1(AVFormatContext *s, int size) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int nb_index_entries, i; AVStream *st; AVIStream *ast; @@ -854,7 +915,7 @@ static int guess_ni_flag(AVFormatContext *s){ static int avi_load_index(AVFormatContext *s) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint32_t tag, size; offset_t pos= url_ftell(pb); @@ -929,7 +990,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp /* DV demux so it can synth correct timestamps */ dv_offset_reset(avi->dv_demux, timestamp); - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); avi->stream_index= -1; return 0; } @@ -969,7 +1030,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp } /* do the seek */ - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); avi->stream_index= -1; return 0; } @@ -994,16 +1055,15 @@ static int avi_read_close(AVFormatContext *s) static int avi_probe(AVProbeData *p) { + int i; + /* check file header */ - if (p->buf_size <= 32) - return 0; - if (p->buf[0] == 'R' && p->buf[1] == 'I' && - p->buf[2] == 'F' && p->buf[3] == 'F' && - p->buf[8] == 'A' && p->buf[9] == 'V' && - p->buf[10] == 'I' && (p->buf[11] == ' ' || p->buf[11] == 0x19)) - return AVPROBE_SCORE_MAX; - else - return 0; + for(i=0; avi_headers[i][0]; i++) + if(!memcmp(p->buf , avi_headers[i] , 4) && + !memcmp(p->buf+8, avi_headers[i]+4, 4)) + return AVPROBE_SCORE_MAX; + + return 0; } AVInputFormat avi_demuxer = { diff --git a/contrib/ffmpeg/libavformat/avienc.c b/contrib/ffmpeg/libavformat/avienc.c index ac8b2670d..6b62f76d8 100644 --- a/contrib/ffmpeg/libavformat/avienc.c +++ b/contrib/ffmpeg/libavformat/avienc.c @@ -105,7 +105,7 @@ static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *s static int avi_write_counters(AVFormatContext* s, int riff_id) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVIContext *avi = s->priv_data; int n, au_byterate, au_ssize, au_scale, nb_frames = 0; offset_t file_size; @@ -138,7 +138,7 @@ static int avi_write_counters(AVFormatContext* s, int riff_id) static int avi_write_header(AVFormatContext *s) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *stream, *video_enc; offset_t list1, list2, strh, strf; @@ -197,11 +197,6 @@ static int avi_write_header(AVFormatContext *s) stream = s->streams[i]->codec; - /* FourCC should really be set by the codec itself */ - if (! stream->codec_tag) { - stream->codec_tag = codec_get_bmp_tag(stream->codec_id); - } - /* stream generic header */ strh = start_tag(pb, "strh"); switch(stream->codec_type) { @@ -337,7 +332,7 @@ static int avi_write_header(AVFormatContext *s) static int avi_write_ix(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVIContext *avi = s->priv_data; char tag[5]; char ix_tag[] = "ix00"; @@ -394,7 +389,7 @@ static int avi_write_ix(AVFormatContext *s) static int avi_write_idx1(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVIContext *avi = s->priv_data; offset_t idx_chunk; int i; @@ -440,7 +435,7 @@ static int avi_write_idx1(AVFormatContext *s) static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; unsigned char tag[5]; unsigned int flags=0; const int stream_index= pkt->stream_index; @@ -481,7 +476,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) avi->audio_strm_length[stream_index] += size; } - if (!url_is_streamed(&s->pb)) { + if (!url_is_streamed(s->pb)) { AVIIndex* idx = &avi->indexes[stream_index]; int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE; int id = idx->entry % AVI_INDEX_CLUSTER_SIZE; @@ -514,7 +509,7 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt) static int avi_write_trailer(AVFormatContext *s) { AVIContext *avi = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int res = 0; int i, j, n, nb_frames; offset_t file_size; diff --git a/contrib/ffmpeg/libavformat/avio.c b/contrib/ffmpeg/libavformat/avio.c index a22bd22f3..5f5bff158 100644 --- a/contrib/ffmpeg/libavformat/avio.c +++ b/contrib/ffmpeg/libavformat/avio.c @@ -19,12 +19,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" +#include "avstring.h" static int default_interrupt_cb(void); URLProtocol *first_protocol = NULL; URLInterruptCB *url_interrupt_cb = default_interrupt_cb; +URLProtocol *av_protocol_next(URLProtocol *p) +{ + if(p) return p->next; + else return first_protocol; +} + int register_protocol(URLProtocol *protocol) { URLProtocol **p; @@ -75,9 +82,7 @@ int url_open(URLContext **puc, const char *filename, int flags) err = AVERROR(ENOMEM); goto fail; } -#if LIBAVFORMAT_VERSION_INT >= (52<<16) uc->filename = (char *) &uc[1]; -#endif strcpy(uc->filename, filename); uc->prot = up; uc->flags = flags; @@ -100,24 +105,22 @@ int url_read(URLContext *h, unsigned char *buf, int size) { int ret; if (h->flags & URL_WRONLY) - return AVERROR_IO; + return AVERROR(EIO); ret = h->prot->url_read(h, buf, size); return ret; } -#if defined(CONFIG_MUXERS) || defined(CONFIG_PROTOCOLS) int url_write(URLContext *h, unsigned char *buf, int size) { int ret; if (!(h->flags & (URL_WRONLY | URL_RDWR))) - return AVERROR_IO; + return AVERROR(EIO); /* avoid sending too big packets */ if (h->max_packet_size && size > h->max_packet_size) - return AVERROR_IO; + return AVERROR(EIO); ret = h->prot->url_write(h, buf, size); return ret; } -#endif //CONFIG_MUXERS || CONFIG_PROTOCOLS offset_t url_seek(URLContext *h, offset_t pos, int whence) { @@ -131,9 +134,11 @@ offset_t url_seek(URLContext *h, offset_t pos, int whence) int url_close(URLContext *h) { - int ret; + int ret = 0; + if (!h) return 0; /* can happen when url_open fails */ - ret = h->prot->url_close(h); + if (h->prot->url_close) + ret = h->prot->url_close(h); av_free(h); return ret; } @@ -169,7 +174,7 @@ int url_get_max_packet_size(URLContext *h) void url_get_filename(URLContext *h, char *buf, int buf_size) { - pstrcpy(buf, buf_size, h->filename); + av_strlcpy(buf, h->filename, buf_size); } @@ -184,3 +189,18 @@ void url_set_interrupt_cb(URLInterruptCB *interrupt_cb) interrupt_cb = default_interrupt_cb; url_interrupt_cb = interrupt_cb; } + +int av_url_read_pause(URLContext *h, int pause) +{ + if (!h->prot->url_read_pause) + return AVERROR(ENOSYS); + return h->prot->url_read_pause(h, pause); +} + +offset_t av_url_read_seek(URLContext *h, + int stream_index, int64_t timestamp, int flags) +{ + if (!h->prot->url_read_seek) + return AVERROR(ENOSYS); + return h->prot->url_read_seek(h, stream_index, timestamp, flags); +} diff --git a/contrib/ffmpeg/libavformat/avio.h b/contrib/ffmpeg/libavformat/avio.h index be78c9a7b..9443cb017 100644 --- a/contrib/ffmpeg/libavformat/avio.h +++ b/contrib/ffmpeg/libavformat/avio.h @@ -18,8 +18,10 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVIO_H -#define AVIO_H +#ifndef FFMPEG_AVIO_H +#define FFMPEG_AVIO_H + +#include <stdint.h> /* output byte stream handling */ @@ -27,17 +29,20 @@ typedef int64_t offset_t; /* unbuffered I/O */ +/** + * URL Context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(URLContext) must not be used outside libav*. + */ struct URLContext { struct URLProtocol *prot; int flags; int is_streamed; /**< true if streamed (no seek possible), default = false */ int max_packet_size; /**< if non zero, the stream is packetized with this max packet size */ void *priv_data; -#if LIBAVFORMAT_VERSION_INT >= (52<<16) char *filename; /**< specified filename */ -#else - char filename[1]; /**< specified filename */ -#endif }; typedef struct URLContext URLContext; @@ -64,7 +69,7 @@ offset_t url_filesize(URLContext *h); /** * Return the maximum packet size associated to packetized file - * handle. If the file is not packetized (stream like http or file on + * handle. If the file is not packetized (stream like HTTP or file on * disk), then 0 is returned. * * @param h file handle @@ -74,10 +79,10 @@ int url_get_max_packet_size(URLContext *h); void url_get_filename(URLContext *h, char *buf, int buf_size); /** - * the callback is called in blocking functions to test regulary if + * The callback is called in blocking functions to test regulary if * asynchronous interruption is needed. AVERROR(EINTR) is returned * in this case by the interrupted function. 'NULL' means no interrupt - * callback is given. i + * callback is given. */ void url_set_interrupt_cb(URLInterruptCB *interrupt_cb); @@ -85,9 +90,36 @@ void url_set_interrupt_cb(URLInterruptCB *interrupt_cb); int url_poll(URLPollEntry *poll_table, int n, int timeout); /** - * passing this as the "whence" parameter to a seek function causes it to - * return the filesize without seeking anywhere, supporting this is optional - * if its not supprted then the seek function will return <0 + * Pause and resume playing - only meaningful if using a network streaming + * protocol (e.g. MMS). + * @param pause 1 for pause, 0 for resume + */ +int av_url_read_pause(URLContext *h, int pause); + +/** + * Seek to a given timestamp relative to some component stream. + * Only meaningful if using a network streaming protocol (e.g. MMS.). + * @param stream_index The stream index that the timestamp is relative to. + * 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. + * @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. + * @return >= 0 on success + * @see AVInputFormat::read_seek + */ +offset_t av_url_read_seek(URLContext *h, + int stream_index, int64_t timestamp, int flags); + +/** + * Passing this as the "whence" parameter to a seek function causes it to + * return the filesize without seeking anywhere. Supporting this is optional. + * If it is not supported then the seek function will return <0. */ #define AVSEEK_SIZE 0x10000 @@ -99,13 +131,25 @@ typedef struct URLProtocol { offset_t (*url_seek)(URLContext *h, offset_t pos, int whence); int (*url_close)(URLContext *h); struct URLProtocol *next; + int (*url_read_pause)(URLContext *h, int pause); + offset_t (*url_read_seek)(URLContext *h, + int stream_index, int64_t timestamp, int flags); } URLProtocol; extern URLProtocol *first_protocol; extern URLInterruptCB *url_interrupt_cb; +URLProtocol *av_protocol_next(URLProtocol *p); + int register_protocol(URLProtocol *protocol); +/** + * Bytestream IO Context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(ByteIOContext) must not be used outside libav*. + */ typedef struct { unsigned char *buffer; int buffer_size; @@ -124,6 +168,9 @@ typedef struct { unsigned char *checksum_ptr; unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); int error; ///< contains the error code or 0 if no error happened + int (*read_pause)(void *opaque, int pause); + offset_t (*read_seek)(void *opaque, + int stream_index, int64_t timestamp, int flags); } ByteIOContext; int init_put_byte(ByteIOContext *s, @@ -134,6 +181,14 @@ int init_put_byte(ByteIOContext *s, int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), offset_t (*seek)(void *opaque, offset_t offset, int whence)); +ByteIOContext *av_alloc_put_byte( + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + offset_t (*seek)(void *opaque, offset_t offset, int whence)); void put_byte(ByteIOContext *s, int b); void put_buffer(ByteIOContext *s, const unsigned char *buf, int size); @@ -156,6 +211,10 @@ offset_t url_fsize(ByteIOContext *s); int url_feof(ByteIOContext *s); int url_ferror(ByteIOContext *s); +int av_url_read_fpause(ByteIOContext *h, int pause); +offset_t av_url_read_fseek(ByteIOContext *h, + int stream_index, int64_t timestamp, int flags); + #define URL_EOF (-1) /** @note return URL_EOF (-1) if EOF */ int url_fgetc(ByteIOContext *s); @@ -190,19 +249,28 @@ unsigned int get_be24(ByteIOContext *s); unsigned int get_be32(ByteIOContext *s); uint64_t get_be64(ByteIOContext *s); +uint64_t ff_get_v(ByteIOContext *bc); + static inline int url_is_streamed(ByteIOContext *s) { return s->is_streamed; } -int url_fdopen(ByteIOContext *s, URLContext *h); +/** @note when opened as read/write, the buffers are only used for + writing */ +int url_fdopen(ByteIOContext **s, URLContext *h); /** @warning must be called before any I/O */ int url_setbufsize(ByteIOContext *s, int buf_size); +/** Reset the buffer for reading or writing. + * @note Will drop any data currently in the buffer without transmitting it. + * @param flags URL_RDONLY to set up the buffer for reading, or URL_WRONLY + * to set up the buffer for writing. */ +int url_resetbuf(ByteIOContext *s, int flags); /** @note when opened as read/write, the buffers are only used for - reading */ -int url_fopen(ByteIOContext *s, const char *filename, int flags); + writing */ +int url_fopen(ByteIOContext **s, const char *filename, int flags); int url_fclose(ByteIOContext *s); URLContext *url_fileno(ByteIOContext *s); @@ -211,12 +279,12 @@ URLContext *url_fileno(ByteIOContext *s); * handle. If the file is not packetized (stream like http or file on * disk), then 0 is returned. * - * @param h buffered file handle + * @param s buffered file handle * @return maximum packet size in bytes */ int url_fget_max_packet_size(ByteIOContext *s); -int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags); +int url_open_buf(ByteIOContext **s, uint8_t *buf, int buf_size, int flags); /** return the written or read size */ int url_close_buf(ByteIOContext *s); @@ -227,7 +295,7 @@ int url_close_buf(ByteIOContext *s); * @param s new IO context * @return zero if no error. */ -int url_open_dyn_buf(ByteIOContext *s); +int url_open_dyn_buf(ByteIOContext **s); /** * Open a write only packetized memory stream with a maximum packet @@ -238,35 +306,24 @@ int url_open_dyn_buf(ByteIOContext *s); * @param max_packet_size maximum packet size (must be > 0) * @return zero if no error. */ -int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size); +int url_open_dyn_packet_buf(ByteIOContext **s, int max_packet_size); /** * Return the written size and a pointer to the buffer. The buffer * must be freed with av_free(). * @param s IO context - * @param pointer to a byte buffer + * @param pbuffer pointer to a byte buffer * @return the length of the byte buffer */ int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer); +unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, unsigned int len); unsigned long get_checksum(ByteIOContext *s); void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum); -/* file.c */ -extern URLProtocol file_protocol; -extern URLProtocol pipe_protocol; - /* udp.c */ -extern URLProtocol udp_protocol; int udp_set_remote_url(URLContext *h, const char *uri); int udp_get_local_port(URLContext *h); int udp_get_file_handle(URLContext *h); -/* tcp.c */ -extern URLProtocol tcp_protocol; - -/* http.c */ -extern URLProtocol http_protocol; - -#endif - +#endif /* FFMPEG_AVIO_H */ diff --git a/contrib/ffmpeg/libavformat/aviobuf.c b/contrib/ffmpeg/libavformat/aviobuf.c index 2cc247b62..3917270b1 100644 --- a/contrib/ffmpeg/libavformat/aviobuf.c +++ b/contrib/ffmpeg/libavformat/aviobuf.c @@ -20,6 +20,7 @@ */ #include "avformat.h" #include "avio.h" +#include "crc.h" #include <stdarg.h> #define IO_BUFFER_SIZE 32768 @@ -38,11 +39,7 @@ int init_put_byte(ByteIOContext *s, s->buffer = buffer; s->buffer_size = buffer_size; s->buf_ptr = buffer; - s->write_flag = write_flag; - if (!s->write_flag) - s->buf_end = buffer; - else - s->buf_end = buffer + buffer_size; + url_resetbuf(s, write_flag ? URL_WRONLY : URL_RDONLY); s->opaque = opaque; s->write_packet = write_packet; s->read_packet = read_packet; @@ -58,9 +55,25 @@ int init_put_byte(ByteIOContext *s, s->pos = buffer_size; s->buf_end = s->buffer + buffer_size; } + s->read_pause = NULL; + s->read_seek = NULL; return 0; } +ByteIOContext *av_alloc_put_byte( + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + offset_t (*seek)(void *opaque, offset_t offset, int whence)) { + ByteIOContext *s = av_mallocz(sizeof(ByteIOContext)); + init_put_byte(s, buffer, buffer_size, write_flag, opaque, + read_packet, write_packet, seek); + return s; +} + static void flush_buffer(ByteIOContext *s) { if (s->buf_ptr > s->buffer) { @@ -114,7 +127,12 @@ void put_flush_packet(ByteIOContext *s) offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence) { offset_t offset1; - offset_t pos= s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer)); + offset_t pos; + + if(!s) + return AVERROR(EINVAL); + + pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer)); if (whence != SEEK_CUR && whence != SEEK_SET) return AVERROR(EINVAL); @@ -134,6 +152,8 @@ offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence) offset1 >= 0 && offset1 < (s->buf_end - s->buffer) + (1<<16)){ while(s->pos < offset && !s->eof_reached) fill_buffer(s); + if (s->eof_reached) + return AVERROR(EPIPE); s->buf_ptr = s->buf_end + offset - s->pos; } else { offset_t res = AVERROR(EPIPE); @@ -170,6 +190,9 @@ offset_t url_fsize(ByteIOContext *s) { offset_t size; + if(!s) + return AVERROR(EINVAL); + if (!s->seek) return AVERROR(EPIPE); size = s->seek(s->opaque, 0, AVSEEK_SIZE); @@ -184,11 +207,15 @@ offset_t url_fsize(ByteIOContext *s) int url_feof(ByteIOContext *s) { + if(!s) + return 0; return s->eof_reached; } int url_ferror(ByteIOContext *s) { + if(!s) + return 0; return s->error; } @@ -263,7 +290,7 @@ void put_tag(ByteIOContext *s, const char *tag) static void fill_buffer(ByteIOContext *s) { - int len; + int len=0; /* no need to do anything if EOF already reached */ if (s->eof_reached) @@ -275,13 +302,14 @@ static void fill_buffer(ByteIOContext *s) s->checksum_ptr= s->buffer; } - len = s->read_packet(s->opaque, s->buffer, s->buffer_size); + if(s->read_packet) + len = s->read_packet(s->opaque, s->buffer, s->buffer_size); if (len <= 0) { /* do not modify buffer if EOF reached so that a seek back can be done without rereading data */ s->eof_reached = 1; - if(len<0) - s->error= len; + if(len<0) + s->error= len; } else { s->pos += len; s->buf_ptr = s->buffer; @@ -289,6 +317,10 @@ static void fill_buffer(ByteIOContext *s) } } +unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, unsigned int len){ + return av_crc(av_crc_get_table(AV_CRC_32_IEEE), checksum, buf, len); +} + unsigned long get_checksum(ByteIOContext *s){ s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr); s->update_checksum= NULL; @@ -341,7 +373,8 @@ int get_buffer(ByteIOContext *s, unsigned char *buf, int size) len = size; if (len == 0) { if(size > s->buffer_size && !s->update_checksum){ - len = s->read_packet(s->opaque, buf, size); + if(s->read_packet) + len = s->read_packet(s->opaque, buf, size); if (len <= 0) { /* do not modify buffer if EOF reached so that a seek back can be done without rereading data */ @@ -469,32 +502,18 @@ uint64_t get_be64(ByteIOContext *s) return val; } -/* link with avio functions */ - -#ifdef CONFIG_MUXERS -static int url_write_packet(void *opaque, uint8_t *buf, int buf_size) -{ - URLContext *h = opaque; - return url_write(h, buf, buf_size); -} -#else -#define url_write_packet NULL -#endif //CONFIG_MUXERS - -static int url_read_packet(void *opaque, uint8_t *buf, int buf_size) -{ - URLContext *h = opaque; - return url_read(h, buf, buf_size); -} +uint64_t ff_get_v(ByteIOContext *bc){ + uint64_t val = 0; + int tmp; -static offset_t url_seek_packet(void *opaque, offset_t offset, int whence) -{ - URLContext *h = opaque; - return url_seek(h, offset, whence); - //return 0; + do{ + tmp = get_byte(bc); + val= (val<<7) + (tmp&127); + }while(tmp&128); + return val; } -int url_fdopen(ByteIOContext *s, URLContext *h) +int url_fdopen(ByteIOContext **s, URLContext *h) { uint8_t *buffer; int buffer_size, max_packet_size; @@ -510,14 +529,25 @@ int url_fdopen(ByteIOContext *s, URLContext *h) if (!buffer) return AVERROR(ENOMEM); - if (init_put_byte(s, buffer, buffer_size, + *s = av_mallocz(sizeof(ByteIOContext)); + if(!*s) { + av_free(buffer); + return AVERROR(ENOMEM); + } + + if (init_put_byte(*s, buffer, buffer_size, (h->flags & URL_WRONLY || h->flags & URL_RDWR), h, - url_read_packet, url_write_packet, url_seek_packet) < 0) { + url_read, url_write, url_seek) < 0) { av_free(buffer); - return AVERROR_IO; + av_freep(s); + return AVERROR(EIO); + } + (*s)->is_streamed = h->is_streamed; + (*s)->max_packet_size = max_packet_size; + if(h->prot) { + (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause; + (*s)->read_seek = (offset_t (*)(void *, int, int64_t, int))h->prot->url_read_seek; } - s->is_streamed = h->is_streamed; - s->max_packet_size = max_packet_size; return 0; } @@ -532,14 +562,27 @@ int url_setbufsize(ByteIOContext *s, int buf_size) s->buffer = buffer; s->buffer_size = buf_size; s->buf_ptr = buffer; - if (!s->write_flag) - s->buf_end = buffer; - else - s->buf_end = buffer + buf_size; + url_resetbuf(s, s->write_flag ? URL_WRONLY : URL_RDONLY); + return 0; +} + +int url_resetbuf(ByteIOContext *s, int flags) +{ + URLContext *h = s->opaque; + if ((flags & URL_RDWR) || (h && h->flags != flags && !h->flags & URL_RDWR)) + return AVERROR(EINVAL); + + if (flags & URL_WRONLY) { + s->buf_end = s->buffer + s->buffer_size; + s->write_flag = 1; + } else { + s->buf_end = s->buffer; + s->write_flag = 0; + } return 0; } -int url_fopen(ByteIOContext *s, const char *filename, int flags) +int url_fopen(ByteIOContext **s, const char *filename, int flags) { URLContext *h; int err; @@ -560,7 +603,7 @@ int url_fclose(ByteIOContext *s) URLContext *h = s->opaque; av_free(s->buffer); - memset(s, 0, sizeof(ByteIOContext)); + av_free(s); return url_close(h); } @@ -610,15 +653,44 @@ int url_fget_max_packet_size(ByteIOContext *s) return s->max_packet_size; } +int av_url_read_fpause(ByteIOContext *s, int pause) +{ + if (!s->read_pause) + return AVERROR(ENOSYS); + return s->read_pause(s->opaque, pause); +} + +offset_t av_url_read_fseek(ByteIOContext *s, + int stream_index, int64_t timestamp, int flags) +{ + URLContext *h = s->opaque; + offset_t ret; + if (!s->read_seek) + return AVERROR(ENOSYS); + ret = s->read_seek(h, stream_index, timestamp, flags); + if(ret >= 0) { + s->buf_ptr = s->buf_end; // Flush buffer + s->pos = s->seek(h, 0, SEEK_CUR); + } + return ret; +} + /* url_open_dyn_buf and url_close_dyn_buf are used in rtp.c to send a response * back to the server even if CONFIG_MUXERS is not set. */ #if defined(CONFIG_MUXERS) || defined(CONFIG_NETWORK) /* buffer handling */ -int url_open_buf(ByteIOContext *s, uint8_t *buf, int buf_size, int flags) +int url_open_buf(ByteIOContext **s, uint8_t *buf, int buf_size, int flags) { - return init_put_byte(s, buf, buf_size, - (flags & URL_WRONLY || flags & URL_RDWR), - NULL, NULL, NULL, NULL); + int ret; + *s = av_mallocz(sizeof(ByteIOContext)); + if(!*s) + return AVERROR(ENOMEM); + ret = init_put_byte(*s, buf, buf_size, + (flags & URL_WRONLY || flags & URL_RDWR), + NULL, NULL, NULL, NULL); + if(ret != 0) + av_freep(s); + return ret; } int url_close_buf(ByteIOContext *s) @@ -698,7 +770,7 @@ static offset_t dyn_buf_seek(void *opaque, offset_t offset, int whence) return 0; } -static int url_open_dyn_buf_internal(ByteIOContext *s, int max_packet_size) +static int url_open_dyn_buf_internal(ByteIOContext **s, int max_packet_size) { DynBuffer *d; int io_buffer_size, ret; @@ -713,27 +785,35 @@ static int url_open_dyn_buf_internal(ByteIOContext *s, int max_packet_size) d = av_malloc(sizeof(DynBuffer) + io_buffer_size); if (!d) return -1; + *s = av_mallocz(sizeof(ByteIOContext)); + if(!*s) { + av_free(d); + return AVERROR(ENOMEM); + } d->io_buffer_size = io_buffer_size; d->buffer = NULL; d->pos = 0; d->size = 0; d->allocated_size = 0; - ret = init_put_byte(s, d->io_buffer, io_buffer_size, + ret = init_put_byte(*s, d->io_buffer, io_buffer_size, 1, d, NULL, max_packet_size ? dyn_packet_buf_write : dyn_buf_write, max_packet_size ? NULL : dyn_buf_seek); if (ret == 0) { - s->max_packet_size = max_packet_size; + (*s)->max_packet_size = max_packet_size; + } else { + av_free(d); + av_freep(s); } return ret; } -int url_open_dyn_buf(ByteIOContext *s) +int url_open_dyn_buf(ByteIOContext **s) { return url_open_dyn_buf_internal(s, 0); } -int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size) +int url_open_dyn_packet_buf(ByteIOContext **s, int max_packet_size) { if (max_packet_size <= 0) return -1; @@ -750,6 +830,7 @@ int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer) *pbuffer = d->buffer; size = d->size; av_free(d); + av_free(s); return size; } #endif /* CONFIG_MUXERS || CONFIG_NETWORK */ diff --git a/contrib/ffmpeg/libavformat/avisynth.c b/contrib/ffmpeg/libavformat/avisynth.c index 1afcdea5e..158cac1fc 100644 --- a/contrib/ffmpeg/libavformat/avisynth.c +++ b/contrib/ffmpeg/libavformat/avisynth.c @@ -156,10 +156,10 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) stream = &avs->streams[stream_id]; if (stream->read >= stream->info.dwLength) - return AVERROR_IO; + return AVERROR(EIO); if (av_new_packet(pkt, stream->chunck_size)) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = stream_id; pkt->pts = avs->streams[stream_id].read / avs->streams[stream_id].chunck_samples; diff --git a/contrib/ffmpeg/libavformat/avs.c b/contrib/ffmpeg/libavformat/avs.c index 0fa77deff..b1d6f89e0 100644 --- a/contrib/ffmpeg/libavformat/avs.c +++ b/contrib/ffmpeg/libavformat/avs.c @@ -16,7 +16,7 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" @@ -47,8 +47,6 @@ static int avs_probe(AVProbeData * p) { const uint8_t *d; - if (p->buf_size < 2) - return 0; d = p->buf; if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0) return 50; @@ -62,12 +60,12 @@ static int avs_read_header(AVFormatContext * s, AVFormatParameters * ap) s->ctx_flags |= AVFMTCTX_NOHEADER; - url_fskip(&s->pb, 4); - avs->width = get_le16(&s->pb); - avs->height = get_le16(&s->pb); - avs->bits_per_sample = get_le16(&s->pb); - avs->fps = get_le16(&s->pb); - avs->nb_frames = get_le32(&s->pb); + url_fskip(s->pb, 4); + avs->width = get_le16(s->pb); + avs->height = get_le16(s->pb); + avs->bits_per_sample = get_le16(s->pb); + avs->fps = get_le16(s->pb); + avs->nb_frames = get_le32(s->pb); avs->remaining_frame_size = 0; avs->remaining_audio_size = 0; @@ -105,10 +103,10 @@ avs_read_video_packet(AVFormatContext * s, AVPacket * pkt, pkt->data[palette_size + 1] = type; pkt->data[palette_size + 2] = size & 0xFF; pkt->data[palette_size + 3] = (size >> 8) & 0xFF; - ret = get_buffer(&s->pb, pkt->data + palette_size + 4, size - 4) + 4; + ret = get_buffer(s->pb, pkt->data + palette_size + 4, size - 4) + 4; if (ret < size) { av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } pkt->size = ret + palette_size; @@ -124,12 +122,12 @@ static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt) avs_format_t *avs = s->priv_data; int ret, size; - size = url_ftell(&s->pb); + size = url_ftell(s->pb); ret = voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size); - size = url_ftell(&s->pb) - size; + size = url_ftell(s->pb) - size; avs->remaining_audio_size -= size; - if (ret == AVERROR_IO) + if (ret == AVERROR(EIO)) return 0; /* this indicate EOS */ if (ret < 0) return ret; @@ -155,22 +153,22 @@ static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) while (1) { if (avs->remaining_frame_size <= 0) { - if (!get_le16(&s->pb)) /* found EOF */ - return AVERROR_IO; - avs->remaining_frame_size = get_le16(&s->pb) - 4; + if (!get_le16(s->pb)) /* found EOF */ + return AVERROR(EIO); + avs->remaining_frame_size = get_le16(s->pb) - 4; } while (avs->remaining_frame_size > 0) { - sub_type = get_byte(&s->pb); - type = get_byte(&s->pb); - size = get_le16(&s->pb); + sub_type = get_byte(s->pb); + type = get_byte(s->pb); + size = get_le16(s->pb); avs->remaining_frame_size -= size; switch (type) { case AVS_PALETTE: - ret = get_buffer(&s->pb, palette, size - 4); + ret = get_buffer(s->pb, palette, size - 4); if (ret < size - 4) - return AVERROR_IO; + return AVERROR(EIO); palette_size = size; break; @@ -178,7 +176,7 @@ static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) if (!avs->st_video) { avs->st_video = av_new_stream(s, AVS_VIDEO); if (avs->st_video == NULL) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); avs->st_video->codec->codec_type = CODEC_TYPE_VIDEO; avs->st_video->codec->codec_id = CODEC_ID_AVS; avs->st_video->codec->width = avs->width; @@ -195,7 +193,7 @@ static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) if (!avs->st_audio) { avs->st_audio = av_new_stream(s, AVS_AUDIO); if (avs->st_audio == NULL) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); avs->st_audio->codec->codec_type = CODEC_TYPE_AUDIO; } avs->remaining_audio_size = size - 4; @@ -205,7 +203,7 @@ static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) break; default: - url_fskip(&s->pb, size - 4); + url_fskip(s->pb, size - 4); } } } diff --git a/contrib/ffmpeg/libavformat/beosaudio.cpp b/contrib/ffmpeg/libavformat/beosaudio.cpp deleted file mode 100644 index 6c16f0048..000000000 --- a/contrib/ffmpeg/libavformat/beosaudio.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* - * BeOS audio play interface - * Copyright (c) 2000, 2001 Fabrice Bellard. - * - * 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 <signal.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/time.h> - -#include <Application.h> -#include <SoundPlayer.h> - -extern "C" { -#include "avformat.h" -} - -#ifdef HAVE_BSOUNDRECORDER -#include <SoundRecorder.h> -using namespace BPrivate::Media::Experimental; -#endif - -/* enable performance checks */ -//#define PERF_CHECK - -/* enable Media Kit latency checks */ -//#define LATENCY_CHECK - -#define AUDIO_BLOCK_SIZE 4096 -#define AUDIO_BLOCK_COUNT 8 - -#define AUDIO_BUFFER_SIZE (AUDIO_BLOCK_SIZE*AUDIO_BLOCK_COUNT) - -typedef struct { - int fd; // UNUSED - int sample_rate; - int channels; - int frame_size; /* in bytes ! */ - CodecID codec_id; - uint8_t buffer[AUDIO_BUFFER_SIZE]; - int buffer_ptr; - /* ring buffer */ - sem_id input_sem; - int input_index; - sem_id output_sem; - int output_index; - BSoundPlayer *player; -#ifdef HAVE_BSOUNDRECORDER - BSoundRecorder *recorder; -#endif - int has_quit; /* signal callbacks not to wait */ - volatile bigtime_t starve_time; -} AudioData; - -static thread_id main_thid; -static thread_id bapp_thid; -static int own_BApp_created = 0; -static int refcount = 0; - -/* create the BApplication and Run() it */ -static int32 bapp_thread(void *arg) -{ - new BApplication("application/x-vnd.ffmpeg"); - own_BApp_created = 1; - be_app->Run(); - /* kill the process group */ -// kill(0, SIGINT); -// kill(main_thid, SIGHUP); - return B_OK; -} - -/* create the BApplication only if needed */ -static void create_bapp_if_needed(void) -{ - if (refcount++ == 0) { - /* needed by libmedia */ - if (be_app == NULL) { - bapp_thid = spawn_thread(bapp_thread, "ffmpeg BApplication", B_NORMAL_PRIORITY, NULL); - resume_thread(bapp_thid); - while (!own_BApp_created) - snooze(50000); - } - } -} - -static void destroy_bapp_if_needed(void) -{ - if (--refcount == 0 && own_BApp_created) { - be_app->Lock(); - be_app->Quit(); - be_app = NULL; - } -} - -/* called back by BSoundPlayer */ -static void audioplay_callback(void *cookie, void *buffer, size_t bufferSize, const media_raw_audio_format &format) -{ - AudioData *s; - size_t len, amount; - unsigned char *buf = (unsigned char *)buffer; - - s = (AudioData *)cookie; - if (s->has_quit) - return; - while (bufferSize > 0) { -#ifdef PERF_CHECK - bigtime_t t; - t = system_time(); -#endif - len = MIN(AUDIO_BLOCK_SIZE, bufferSize); - if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) { - s->has_quit = 1; - s->player->SetHasData(false); - return; - } - amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index)); - memcpy(buf, &s->buffer[s->output_index], amount); - s->output_index += amount; - if (s->output_index >= AUDIO_BUFFER_SIZE) { - s->output_index %= AUDIO_BUFFER_SIZE; - memcpy(buf + amount, &s->buffer[s->output_index], len - amount); - s->output_index += len-amount; - s->output_index %= AUDIO_BUFFER_SIZE; - } - release_sem_etc(s->input_sem, len, 0); -#ifdef PERF_CHECK - t = system_time() - t; - s->starve_time = MAX(s->starve_time, t); -#endif - buf += len; - bufferSize -= len; - } -} - -#ifdef HAVE_BSOUNDRECORDER -/* called back by BSoundRecorder */ -static void audiorecord_callback(void *cookie, bigtime_t timestamp, void *buffer, size_t bufferSize, const media_multi_audio_format &format) -{ - AudioData *s; - size_t len, amount; - unsigned char *buf = (unsigned char *)buffer; - - s = (AudioData *)cookie; - if (s->has_quit) - return; - - while (bufferSize > 0) { - len = MIN(bufferSize, AUDIO_BLOCK_SIZE); - //printf("acquire_sem(input, %d)\n", len); - if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) { - s->has_quit = 1; - return; - } - amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index)); - memcpy(&s->buffer[s->input_index], buf, amount); - s->input_index += amount; - if (s->input_index >= AUDIO_BUFFER_SIZE) { - s->input_index %= AUDIO_BUFFER_SIZE; - memcpy(&s->buffer[s->input_index], buf + amount, len - amount); - s->input_index += len - amount; - } - release_sem_etc(s->output_sem, len, 0); - //printf("release_sem(output, %d)\n", len); - buf += len; - bufferSize -= len; - } -} -#endif - -static int audio_open(AudioData *s, int is_output, const char *audio_device) -{ - int p[2]; - int ret; - media_raw_audio_format format; - media_multi_audio_format iformat; - -#ifndef HAVE_BSOUNDRECORDER - if (!is_output) - return AVERROR(EIO); /* not for now */ -#endif - s->input_sem = create_sem(AUDIO_BUFFER_SIZE, "ffmpeg_ringbuffer_input"); - if (s->input_sem < B_OK) - return AVERROR(EIO); - s->output_sem = create_sem(0, "ffmpeg_ringbuffer_output"); - if (s->output_sem < B_OK) { - delete_sem(s->input_sem); - return AVERROR(EIO); - } - s->input_index = 0; - s->output_index = 0; - create_bapp_if_needed(); - s->frame_size = AUDIO_BLOCK_SIZE; - /* bump up the priority (avoid realtime though) */ - set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1); -#ifdef HAVE_BSOUNDRECORDER - if (!is_output) { - bool wait_for_input = false; - if (audio_device && !strcmp(audio_device, "wait:")) - wait_for_input = true; - s->recorder = new BSoundRecorder(&iformat, wait_for_input, "ffmpeg input", audiorecord_callback); - if (wait_for_input && (s->recorder->InitCheck() == B_OK)) { - s->recorder->WaitForIncomingConnection(&iformat); - } - if (s->recorder->InitCheck() != B_OK || iformat.format != media_raw_audio_format::B_AUDIO_SHORT) { - delete s->recorder; - s->recorder = NULL; - if (s->input_sem) - delete_sem(s->input_sem); - if (s->output_sem) - delete_sem(s->output_sem); - return AVERROR(EIO); - } - s->codec_id = (iformat.byte_order == B_MEDIA_LITTLE_ENDIAN)?CODEC_ID_PCM_S16LE:CODEC_ID_PCM_S16BE; - s->channels = iformat.channel_count; - s->sample_rate = (int)iformat.frame_rate; - s->frame_size = iformat.buffer_size; - s->recorder->SetCookie(s); - s->recorder->SetVolume(1.0); - s->recorder->Start(); - return 0; - } -#endif - format = media_raw_audio_format::wildcard; - format.format = media_raw_audio_format::B_AUDIO_SHORT; - format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN; - format.channel_count = s->channels; - format.buffer_size = s->frame_size; - format.frame_rate = s->sample_rate; - s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback); - if (s->player->InitCheck() != B_OK) { - delete s->player; - s->player = NULL; - if (s->input_sem) - delete_sem(s->input_sem); - if (s->output_sem) - delete_sem(s->output_sem); - return AVERROR(EIO); - } - s->player->SetCookie(s); - s->player->SetVolume(1.0); - s->player->Start(); - s->player->SetHasData(true); - return 0; -} - -static int audio_close(AudioData *s) -{ - if (s->input_sem) - delete_sem(s->input_sem); - if (s->output_sem) - delete_sem(s->output_sem); - s->has_quit = 1; - if (s->player) { - s->player->Stop(); - } - if (s->player) - delete s->player; -#ifdef HAVE_BSOUNDRECORDER - if (s->recorder) - delete s->recorder; -#endif - destroy_bapp_if_needed(); - return 0; -} - -/* sound output support */ -static int audio_write_header(AVFormatContext *s1) -{ - AudioData *s = (AudioData *)s1->priv_data; - AVStream *st; - int ret; - - st = s1->streams[0]; - s->sample_rate = st->codec->sample_rate; - s->channels = st->codec->channels; - ret = audio_open(s, 1, NULL); - if (ret < 0) - return AVERROR(EIO); - return 0; -} - -static int audio_write_packet(AVFormatContext *s1, int stream_index, - const uint8_t *buf, int size, int64_t force_pts) -{ - AudioData *s = (AudioData *)s1->priv_data; - int len, ret; -#ifdef LATENCY_CHECK -bigtime_t lat1, lat2; -lat1 = s->player->Latency(); -#endif -#ifdef PERF_CHECK - bigtime_t t = s->starve_time; - s->starve_time = 0; - printf("starve_time: %lld \n", t); -#endif - while (size > 0) { - int amount; - len = MIN(size, AUDIO_BLOCK_SIZE); - if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) - return AVERROR(EIO); - amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index)); - memcpy(&s->buffer[s->input_index], buf, amount); - s->input_index += amount; - if (s->input_index >= AUDIO_BUFFER_SIZE) { - s->input_index %= AUDIO_BUFFER_SIZE; - memcpy(&s->buffer[s->input_index], buf + amount, len - amount); - s->input_index += len - amount; - } - release_sem_etc(s->output_sem, len, 0); - buf += len; - size -= len; - } -#ifdef LATENCY_CHECK -lat2 = s->player->Latency(); -printf("#### BSoundPlayer::Latency(): before= %lld, after= %lld\n", lat1, lat2); -#endif - return 0; -} - -static int audio_write_trailer(AVFormatContext *s1) -{ - AudioData *s = (AudioData *)s1->priv_data; - - audio_close(s); - return 0; -} - -/* grab support */ - -static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap) -{ - AudioData *s = (AudioData *)s1->priv_data; - AVStream *st; - int ret; - - if (!ap || ap->sample_rate <= 0 || ap->channels <= 0) - return -1; - - st = av_new_stream(s1, 0); - if (!st) { - return AVERROR(ENOMEM); - } - s->sample_rate = ap->sample_rate; - s->channels = ap->channels; - - ret = audio_open(s, 0, s1->filename); - if (ret < 0) { - av_free(st); - return AVERROR(EIO); - } - /* take real parameters */ - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = s->codec_id; - st->codec->sample_rate = s->sample_rate; - st->codec->channels = s->channels; - return 0; - av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */ -} - -static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - AudioData *s = (AudioData *)s1->priv_data; - int size; - size_t len, amount; - unsigned char *buf; - status_t err; - - if (av_new_packet(pkt, s->frame_size) < 0) - return AVERROR(EIO); - buf = (unsigned char *)pkt->data; - size = pkt->size; - while (size > 0) { - len = MIN(AUDIO_BLOCK_SIZE, size); - //printf("acquire_sem(output, %d)\n", len); - while ((err=acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL)) == B_INTERRUPTED); - if (err < B_OK) { - av_free_packet(pkt); - return AVERROR(EIO); - } - amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index)); - memcpy(buf, &s->buffer[s->output_index], amount); - s->output_index += amount; - if (s->output_index >= AUDIO_BUFFER_SIZE) { - s->output_index %= AUDIO_BUFFER_SIZE; - memcpy(buf + amount, &s->buffer[s->output_index], len - amount); - s->output_index += len-amount; - s->output_index %= AUDIO_BUFFER_SIZE; - } - release_sem_etc(s->input_sem, len, 0); - //printf("release_sem(input, %d)\n", len); - buf += len; - size -= len; - } - //XXX: add pts info - return 0; -} - -static int audio_read_close(AVFormatContext *s1) -{ - AudioData *s = (AudioData *)s1->priv_data; - - audio_close(s); - return 0; -} - -static AVInputFormat audio_demuxer = { - "audio_device", - "audio grab and output", - sizeof(AudioData), - NULL, - audio_read_header, - audio_read_packet, - audio_read_close, - NULL, - AVFMT_NOFILE, -}; - -AVOutputFormat audio_muxer = { - "audio_device", - "audio grab and output", - "", - "", - sizeof(AudioData), -#ifdef WORDS_BIGENDIAN - CODEC_ID_PCM_S16BE, -#else - CODEC_ID_PCM_S16LE, -#endif - CODEC_ID_NONE, - audio_write_header, - audio_write_packet, - audio_write_trailer, - AVFMT_NOFILE, -}; - -extern "C" { - -int audio_init(void) -{ - main_thid = find_thread(NULL); - av_register_input_format(&audio_demuxer); - av_register_output_format(&audio_muxer); - return 0; -} - -} // "C" - diff --git a/contrib/ffmpeg/libavformat/bethsoftvid.c b/contrib/ffmpeg/libavformat/bethsoftvid.c new file mode 100644 index 000000000..594779698 --- /dev/null +++ b/contrib/ffmpeg/libavformat/bethsoftvid.c @@ -0,0 +1,233 @@ +/* + * Bethsoft VID format Demuxer + * Copyright (c) 2007 Nicholas Tung + * + * 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 bethsoftvid.c + * @brief Bethesda Softworks VID (.vid) file demuxer + * @author Nicholas Tung [ntung (at. ntung com] (2007-03) + * @sa http://wiki.multimedia.cx/index.php?title=Bethsoft_VID + * @sa http://www.svatopluk.com/andux/docs/dfvid.html + */ + +#include "avformat.h" +#include "bethsoftvideo.h" + +typedef struct BVID_DemuxContext +{ + int nframes; + /** delay value between frames, added to individual frame delay. + * custom units, which will be added to other custom units (~=16ms according + * to free, unofficial documentation) */ + int bethsoft_global_delay; + + /** video presentation time stamp. + * delay = 16 milliseconds * (global_delay + per_frame_delay) */ + int video_pts; + + int is_finished; + +} BVID_DemuxContext; + +static int vid_probe(AVProbeData *p) +{ + // little endian VID tag, file starts with "VID\0" + if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int vid_read_header(AVFormatContext *s, + AVFormatParameters *ap) +{ + BVID_DemuxContext *vid = s->priv_data; + ByteIOContext *pb = s->pb; + AVStream *stream; + + /* load main header. Contents: + * bytes: 'V' 'I' 'D' + * int16s: always_512, nframes, width, height, delay, always_14 + */ + url_fseek(pb, 5, SEEK_CUR); + vid->nframes = get_le16(pb); + + stream = av_new_stream(s, 0); + if (!stream) + return AVERROR(ENOMEM); + av_set_pts_info(stream, 32, 1, 60); // 16 ms increments, i.e. 60 fps + stream->codec->codec_type = CODEC_TYPE_VIDEO; + stream->codec->codec_id = CODEC_ID_BETHSOFTVID; + stream->codec->width = get_le16(pb); + stream->codec->height = get_le16(pb); + stream->codec->pix_fmt = PIX_FMT_PAL8; + vid->bethsoft_global_delay = get_le16(pb); + get_le16(pb); + + // done with video codec, set up audio codec + stream = av_new_stream(s, 0); + if (!stream) + return AVERROR(ENOMEM); + stream->codec->codec_type = CODEC_TYPE_AUDIO; + stream->codec->codec_id = CODEC_ID_PCM_U8; + stream->codec->channels = 1; + stream->codec->sample_rate = 11025; + stream->codec->bits_per_sample = 8; + stream->codec->bit_rate = stream->codec->channels * stream->codec->sample_rate * stream->codec->bits_per_sample; + + return 0; +} + +#define BUFFER_PADDING_SIZE 1000 +static int read_frame(BVID_DemuxContext *vid, ByteIOContext *pb, AVPacket *pkt, + uint8_t block_type, AVFormatContext *s, int npixels) +{ + uint8_t * vidbuf_start = NULL; + int vidbuf_nbytes = 0; + int code; + int bytes_copied = 0; + int position; + unsigned int vidbuf_capacity; + + vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE); + if(!vidbuf_start) + return AVERROR(ENOMEM); + + // save the file position for the packet, include block type + position = url_ftell(pb) - 1; + + vidbuf_start[vidbuf_nbytes++] = block_type; + + // get the video delay (next int16), and set the presentation time + vid->video_pts += vid->bethsoft_global_delay + get_le16(pb); + + // set the y offset if it exists (decoder header data should be in data section) + if(block_type == VIDEO_YOFF_P_FRAME){ + if(get_buffer(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) + goto fail; + vidbuf_nbytes += 2; + } + + do{ + vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE); + if(!vidbuf_start) + return AVERROR(ENOMEM); + + code = get_byte(pb); + vidbuf_start[vidbuf_nbytes++] = code; + + if(code >= 0x80){ // rle sequence + if(block_type == VIDEO_I_FRAME) + vidbuf_start[vidbuf_nbytes++] = get_byte(pb); + } else if(code){ // plain sequence + if(get_buffer(pb, &vidbuf_start[vidbuf_nbytes], code) != code) + goto fail; + vidbuf_nbytes += code; + } + bytes_copied += code & 0x7F; + if(bytes_copied == npixels){ // sometimes no stop character is given, need to keep track of bytes copied + // may contain a 0 byte even if read all pixels + if(get_byte(pb)) + url_fseek(pb, -1, SEEK_CUR); + break; + } + if(bytes_copied > npixels) + goto fail; + } while(code); + + // copy data into packet + if(av_new_packet(pkt, vidbuf_nbytes) < 0) + goto fail; + memcpy(pkt->data, vidbuf_start, vidbuf_nbytes); + av_free(vidbuf_start); + + pkt->pos = position; + pkt->stream_index = 0; // use the video decoder, which was initialized as the first stream + pkt->pts = vid->video_pts; + + vid->nframes--; // used to check if all the frames were read + return vidbuf_nbytes; +fail: + av_free(vidbuf_start); + return -1; +} + +static int vid_read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + BVID_DemuxContext *vid = s->priv_data; + ByteIOContext *pb = s->pb; + unsigned char block_type; + int audio_length; + int ret_value; + + if(vid->is_finished || url_feof(pb)) + return AVERROR(EIO); + + block_type = get_byte(pb); + switch(block_type){ + case PALETTE_BLOCK: + url_fseek(pb, -1, SEEK_CUR); // include block type + ret_value = av_get_packet(pb, pkt, 3 * 256 + 1); + if(ret_value != 3 * 256 + 1){ + av_free_packet(pkt); + return AVERROR(EIO); + } + pkt->stream_index = 0; + return ret_value; + + case FIRST_AUDIO_BLOCK: + get_le16(pb); + // soundblaster DAC used for sample rate, as on specification page (link above) + s->streams[1]->codec->sample_rate = 1000000 / (256 - get_byte(pb)); + s->streams[1]->codec->bit_rate = s->streams[1]->codec->channels * s->streams[1]->codec->sample_rate * s->streams[1]->codec->bits_per_sample; + case AUDIO_BLOCK: + audio_length = get_le16(pb); + ret_value = av_get_packet(pb, pkt, audio_length); + pkt->stream_index = 1; + return (ret_value != audio_length ? AVERROR(EIO) : ret_value); + + case VIDEO_P_FRAME: + case VIDEO_YOFF_P_FRAME: + case VIDEO_I_FRAME: + return read_frame(vid, pb, pkt, block_type, s, + s->streams[0]->codec->width * s->streams[0]->codec->height); + + case EOF_BLOCK: + if(vid->nframes != 0) + av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n"); + vid->is_finished = 1; + return AVERROR(EIO); + default: + av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n", + block_type, block_type, block_type); return -1; + } + + return 0; +} + +AVInputFormat bethsoftvid_demuxer = { + "bethsoftvid", + "Bethesda Softworks 'Daggerfall' VID format", + sizeof(BVID_DemuxContext), + vid_probe, + vid_read_header, + vid_read_packet, +}; diff --git a/contrib/ffmpeg/libavformat/c93.c b/contrib/ffmpeg/libavformat/c93.c new file mode 100644 index 000000000..996012f6e --- /dev/null +++ b/contrib/ffmpeg/libavformat/c93.c @@ -0,0 +1,198 @@ +/* + * Interplay C93 demuxer + * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> + * + * 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 "voc.h" + +typedef struct { + uint16_t index; + uint8_t length; + uint8_t frames; +} C93BlockRecord; + +typedef struct { + voc_dec_context_t voc; + + C93BlockRecord block_records[512]; + int current_block; + + uint32_t frame_offsets[32]; + int current_frame; + int next_pkt_is_audio; + + AVStream *audio; +} C93DemuxContext; + +static int probe(AVProbeData *p) +{ + if (p->buf[0] == 0x01 && p->buf[1] == 0x00 && + p->buf[4] == 0x01 + p->buf[2] && + p->buf[8] == p->buf[4] + p->buf[6] && + p->buf[12] == p->buf[8] + p->buf[10]) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int read_header(AVFormatContext *s, + AVFormatParameters *ap) +{ + AVStream *video; + ByteIOContext *pb = s->pb; + C93DemuxContext *c93 = s->priv_data; + int i; + int framecount = 0; + + for (i = 0; i < 512; i++) { + c93->block_records[i].index = get_le16(pb); + c93->block_records[i].length = get_byte(pb); + c93->block_records[i].frames = get_byte(pb); + if (c93->block_records[i].frames > 32) { + av_log(s, AV_LOG_ERROR, "too many frames in block\n"); + return AVERROR_INVALIDDATA; + } + framecount += c93->block_records[i].frames; + } + + /* Audio streams are added if audio packets are found */ + s->ctx_flags |= AVFMTCTX_NOHEADER; + + video = av_new_stream(s, 0); + if (!video) + return AVERROR(ENOMEM); + + video->codec->codec_type = CODEC_TYPE_VIDEO; + video->codec->codec_id = CODEC_ID_C93; + video->codec->width = 320; + video->codec->height = 192; + /* 4:3 320x200 with 8 empty lines */ + video->codec->sample_aspect_ratio = (AVRational) { 5, 6 }; + video->time_base = (AVRational) { 2, 25 }; + video->nb_frames = framecount; + video->duration = framecount; + video->start_time = 0; + + c93->current_block = 0; + c93->current_frame = 0; + c93->next_pkt_is_audio = 0; + return 0; +} + +#define C93_HAS_PALETTE 0x01 +#define C93_FIRST_FRAME 0x02 + +static int read_packet(AVFormatContext *s, AVPacket *pkt) +{ + ByteIOContext *pb = s->pb; + C93DemuxContext *c93 = s->priv_data; + C93BlockRecord *br = &c93->block_records[c93->current_block]; + int datasize; + int ret, i; + + if (c93->next_pkt_is_audio) { + c93->current_frame++; + c93->next_pkt_is_audio = 0; + datasize = get_le16(pb); + if (datasize > 42) { + if (!c93->audio) { + c93->audio = av_new_stream(s, 1); + if (!c93->audio) + return AVERROR(ENOMEM); + c93->audio->codec->codec_type = CODEC_TYPE_AUDIO; + } + url_fskip(pb, 26); /* VOC header */ + ret = voc_get_packet(s, pkt, c93->audio, datasize - 26); + if (ret > 0) { + pkt->stream_index = 1; + pkt->flags |= PKT_FLAG_KEY; + return ret; + } + } + } + if (c93->current_frame >= br->frames) { + if (c93->current_block >= 511 || !br[1].length) + return AVERROR(EIO); + br++; + c93->current_block++; + c93->current_frame = 0; + } + + if (c93->current_frame == 0) { + url_fseek(pb, br->index * 2048, SEEK_SET); + for (i = 0; i < 32; i++) { + c93->frame_offsets[i] = get_le32(pb); + } + } + + url_fseek(pb,br->index * 2048 + + c93->frame_offsets[c93->current_frame], SEEK_SET); + datasize = get_le16(pb); /* video frame size */ + + ret = av_new_packet(pkt, datasize + 768 + 1); + if (ret < 0) + return ret; + pkt->data[0] = 0; + pkt->size = datasize + 1; + + ret = get_buffer(pb, pkt->data + 1, datasize); + if (ret < datasize) { + ret = AVERROR(EIO); + goto fail; + } + + datasize = get_le16(pb); /* palette size */ + if (datasize) { + if (datasize != 768) { + av_log(s, AV_LOG_ERROR, "invalid palette size %u\n", datasize); + ret = AVERROR_INVALIDDATA; + goto fail; + } + pkt->data[0] |= C93_HAS_PALETTE; + ret = get_buffer(pb, pkt->data + pkt->size, datasize); + if (ret < datasize) { + ret = AVERROR(EIO); + goto fail; + } + pkt->size += 768; + } + pkt->stream_index = 0; + c93->next_pkt_is_audio = 1; + + /* only the first frame is guaranteed to not reference previous frames */ + if (c93->current_block == 0 && c93->current_frame == 0) { + pkt->flags |= PKT_FLAG_KEY; + pkt->data[0] |= C93_FIRST_FRAME; + } + return 0; + + fail: + av_free_packet(pkt); + return ret; +} + +AVInputFormat c93_demuxer = { + "c93", + "Interplay C93", + sizeof(C93DemuxContext), + probe, + read_header, + read_packet, +}; diff --git a/contrib/ffmpeg/libavformat/crc.c b/contrib/ffmpeg/libavformat/crcenc.c index bdbe8bcff..dd8803161 100644 --- a/contrib/ffmpeg/libavformat/crc.c +++ b/contrib/ffmpeg/libavformat/crcenc.c @@ -1,5 +1,5 @@ /* - * CRC decoder (for codec/format testing) + * CRC encoder (for codec/format testing) * Copyright (c) 2002 Fabrice Bellard. * * This file is part of FFmpeg. @@ -21,7 +21,6 @@ #include "avformat.h" #include "adler32.h" -#ifdef CONFIG_CRC_MUXER typedef struct CRCState { uint32_t crcval; } CRCState; @@ -49,26 +48,11 @@ static int crc_write_trailer(struct AVFormatContext *s) char buf[64]; snprintf(buf, sizeof(buf), "CRC=0x%08x\n", crc->crcval); - put_buffer(&s->pb, buf, strlen(buf)); - put_flush_packet(&s->pb); + put_buffer(s->pb, buf, strlen(buf)); + put_flush_packet(s->pb); return 0; } -#endif -#ifdef CONFIG_FRAMECRC_MUXER -static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt) -{ - uint32_t crc = av_adler32_update(0, pkt->data, pkt->size); - char buf[256]; - - snprintf(buf, sizeof(buf), "%d, %"PRId64", %d, 0x%08x\n", pkt->stream_index, pkt->dts, pkt->size, crc); - put_buffer(&s->pb, buf, strlen(buf)); - put_flush_packet(&s->pb); - return 0; -} -#endif - -#ifdef CONFIG_CRC_MUXER AVOutputFormat crc_muxer = { "crc", "crc testing format", @@ -81,18 +65,3 @@ AVOutputFormat crc_muxer = { crc_write_packet, crc_write_trailer, }; -#endif -#ifdef CONFIG_FRAMECRC_MUXER -AVOutputFormat framecrc_muxer = { - "framecrc", - "framecrc testing format", - NULL, - "", - 0, - CODEC_ID_PCM_S16LE, - CODEC_ID_RAWVIDEO, - NULL, - framecrc_write_packet, - NULL, -}; -#endif diff --git a/contrib/ffmpeg/libavformat/cutils.c b/contrib/ffmpeg/libavformat/cutils.c index 45959ec39..06c941112 100644 --- a/contrib/ffmpeg/libavformat/cutils.c +++ b/contrib/ffmpeg/libavformat/cutils.c @@ -20,96 +20,6 @@ */ #include "avformat.h" -#if !defined(CONFIG_NOCUTILS) -/** - * Return TRUE if val is a prefix of str. If it returns TRUE, ptr is - * set to the next character in 'str' after the prefix. - * - * @param str input string - * @param val prefix to test - * @param ptr updated after the prefix in str in there is a match - * @return TRUE if there is a match - */ -int strstart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (*p != *q) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - -/** - * Return TRUE if val is a prefix of str (case independent). If it - * returns TRUE, ptr is set to the next character in 'str' after the - * prefix. - * - * @param str input string - * @param val prefix to test - * @param ptr updated after the prefix in str in there is a match - * @return TRUE if there is a match */ -int stristart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (toupper(*(const unsigned char *)p) != toupper(*(const unsigned char *)q)) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - -/** - * Copy the string str to buf. If str length is bigger than buf_size - - * 1 then it is clamped to buf_size - 1. - * NOTE: this function does what strncpy should have done to be - * useful. NEVER use strncpy. - * - * @param buf destination buffer - * @param buf_size size of destination buffer - * @param str source string - */ -void pstrcpy(char *buf, int buf_size, const char *str) -{ - int c; - char *q = buf; - - if (buf_size <= 0) - return; - - for(;;) { - c = *str++; - if (c == 0 || q >= buf + buf_size - 1) - break; - *q++ = c; - } - *q = '\0'; -} - -/* strcat and truncate. */ -char *pstrcat(char *buf, int buf_size, const char *s) -{ - int len; - len = strlen(buf); - if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); - return buf; -} - -#endif - /* add one element to a dynamic array */ void __dynarray_add(unsigned long **tab_ptr, int *nb_ptr, unsigned long elem) { @@ -152,7 +62,7 @@ time_t mktimegm(struct tm *tm) #define ISLEAP(y) (((y) % 4 == 0) && (((y) % 100) != 0 || ((y) % 400) == 0)) #define LEAPS_COUNT(y) ((y)/4 - (y)/100 + (y)/400) -/* this is our own gmtime_r. it differs from its POSIX counterpart in a +/* This is our own gmtime_r. It differs from its POSIX counterpart in a couple of places, though. */ struct tm *brktimegm(time_t secs, struct tm *tm) { diff --git a/contrib/ffmpeg/libavformat/daud.c b/contrib/ffmpeg/libavformat/daud.c index ec81b7b1c..ff74d0502 100644 --- a/contrib/ffmpeg/libavformat/daud.c +++ b/contrib/ffmpeg/libavformat/daud.c @@ -1,6 +1,6 @@ /* * D-Cinema audio demuxer - * Copyright (c) 2005 Reimar Döffinger. + * Copyright (c) 2005 Reimar Döffinger * * This file is part of FFmpeg. * @@ -34,10 +34,10 @@ static int daud_header(AVFormatContext *s, AVFormatParameters *ap) { } static int daud_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int ret, size; if (url_feof(pb)) - return AVERROR_IO; + return AVERROR(EIO); size = get_be16(pb); get_be16(pb); // unknown ret = av_get_packet(pb, pkt, size); diff --git a/contrib/ffmpeg/libavformat/dc1394.c b/contrib/ffmpeg/libavformat/dc1394.c deleted file mode 100644 index bf140c466..000000000 --- a/contrib/ffmpeg/libavformat/dc1394.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * IIDC1394 grab interface (uses libdc1394 and libraw1394) - * Copyright (c) 2004 Roman Shaposhnik - * - * 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 <libraw1394/raw1394.h> -#include <libdc1394/dc1394_control.h> - -#undef free - -typedef struct dc1394_data { - raw1394handle_t handle; - dc1394_cameracapture camera; - int current_frame; - int fps; - - AVPacket packet; -} dc1394_data; - -struct dc1394_frame_format { - int width; - int height; - enum PixelFormat pix_fmt; - int frame_size_id; -} dc1394_frame_formats[] = { - { 320, 240, PIX_FMT_UYVY422, MODE_320x240_YUV422 }, - { 640, 480, PIX_FMT_UYYVYY411, MODE_640x480_YUV411 }, - { 640, 480, PIX_FMT_UYVY422, MODE_640x480_YUV422 }, - { 0, 0, 0, MODE_320x240_YUV422 } /* default -- gotta be the last one */ -}; - -struct dc1394_frame_rate { - int frame_rate; - int frame_rate_id; -} dc1394_frame_rates[] = { - { 1875, FRAMERATE_1_875 }, - { 3750, FRAMERATE_3_75 }, - { 7500, FRAMERATE_7_5 }, - { 15000, FRAMERATE_15 }, - { 30000, FRAMERATE_30 }, - { 60000, FRAMERATE_60 }, - { 0, FRAMERATE_30 } /* default -- gotta be the last one */ -}; - -static int dc1394_read_header(AVFormatContext *c, AVFormatParameters * ap) -{ - dc1394_data* dc1394 = c->priv_data; - AVStream* vst; - nodeid_t* camera_nodes; - int res; - struct dc1394_frame_format *fmt; - struct dc1394_frame_rate *fps; - - for (fmt = dc1394_frame_formats; fmt->width; fmt++) - if (fmt->pix_fmt == ap->pix_fmt && fmt->width == ap->width && fmt->height == ap->height) - break; - - for (fps = dc1394_frame_rates; fps->frame_rate; fps++) - if (fps->frame_rate == av_rescale(1000, ap->time_base.den, ap->time_base.num)) - break; - - /* create a video stream */ - vst = av_new_stream(c, 0); - if (!vst) - return -1; - av_set_pts_info(vst, 64, 1, 1000); - vst->codec->codec_type = CODEC_TYPE_VIDEO; - vst->codec->codec_id = CODEC_ID_RAWVIDEO; - vst->codec->time_base.den = fps->frame_rate; - vst->codec->time_base.num = 1000; - vst->codec->width = fmt->width; - vst->codec->height = fmt->height; - vst->codec->pix_fmt = fmt->pix_fmt; - - /* packet init */ - av_init_packet(&dc1394->packet); - dc1394->packet.size = avpicture_get_size(fmt->pix_fmt, fmt->width, fmt->height); - dc1394->packet.stream_index = vst->index; - dc1394->packet.flags |= PKT_FLAG_KEY; - - dc1394->current_frame = 0; - dc1394->fps = fps->frame_rate; - - vst->codec->bit_rate = av_rescale(dc1394->packet.size * 8, fps->frame_rate, 1000); - - /* Now lets prep the hardware */ - dc1394->handle = dc1394_create_handle(0); /* FIXME: gotta have ap->port */ - if (!dc1394->handle) { - av_log(c, AV_LOG_ERROR, "Can't acquire dc1394 handle on port %d\n", 0 /* ap->port */); - goto out; - } - camera_nodes = dc1394_get_camera_nodes(dc1394->handle, &res, 1); - if (!camera_nodes || camera_nodes[ap->channel] == DC1394_NO_CAMERA) { - av_log(c, AV_LOG_ERROR, "There's no IIDC camera on the channel %d\n", ap->channel); - goto out_handle; - } - res = dc1394_dma_setup_capture(dc1394->handle, camera_nodes[ap->channel], - 0, - FORMAT_VGA_NONCOMPRESSED, - fmt->frame_size_id, - SPEED_400, - fps->frame_rate_id, 8, 1, - c->filename, - &dc1394->camera); - dc1394_free_camera_nodes(camera_nodes); - if (res != DC1394_SUCCESS) { - av_log(c, AV_LOG_ERROR, "Can't prepare camera for the DMA capture\n"); - goto out_handle; - } - - res = dc1394_start_iso_transmission(dc1394->handle, dc1394->camera.node); - if (res != DC1394_SUCCESS) { - av_log(c, AV_LOG_ERROR, "Can't start isochronous transmission\n"); - goto out_handle_dma; - } - - return 0; - -out_handle_dma: - dc1394_dma_unlisten(dc1394->handle, &dc1394->camera); - dc1394_dma_release_camera(dc1394->handle, &dc1394->camera); -out_handle: - dc1394_destroy_handle(dc1394->handle); -out: - return -1; -} - -static int dc1394_read_packet(AVFormatContext *c, AVPacket *pkt) -{ - struct dc1394_data *dc1394 = c->priv_data; - int res; - - /* discard stale frame */ - if (dc1394->current_frame++) { - if (dc1394_dma_done_with_buffer(&dc1394->camera) != DC1394_SUCCESS) - av_log(c, AV_LOG_ERROR, "failed to release %d frame\n", dc1394->current_frame); - } - - res = dc1394_dma_single_capture(&dc1394->camera); - - if (res == DC1394_SUCCESS) { - dc1394->packet.data = (uint8_t *)(dc1394->camera.capture_buffer); - dc1394->packet.pts = (dc1394->current_frame * 1000000) / dc1394->fps; - res = dc1394->packet.size; - } else { - av_log(c, AV_LOG_ERROR, "DMA capture failed\n"); - dc1394->packet.data = NULL; - res = -1; - } - - *pkt = dc1394->packet; - return res; -} - -static int dc1394_close(AVFormatContext * context) -{ - struct dc1394_data *dc1394 = context->priv_data; - - dc1394_stop_iso_transmission(dc1394->handle, dc1394->camera.node); - dc1394_dma_unlisten(dc1394->handle, &dc1394->camera); - dc1394_dma_release_camera(dc1394->handle, &dc1394->camera); - dc1394_destroy_handle(dc1394->handle); - - return 0; -} - -AVInputFormat dc1394_demuxer = { - .name = "dc1394", - .long_name = "dc1394 A/V grab", - .priv_data_size = sizeof(struct dc1394_data), - .read_header = dc1394_read_header, - .read_packet = dc1394_read_packet, - .read_close = dc1394_close, - .flags = AVFMT_NOFILE -}; diff --git a/contrib/ffmpeg/libavformat/dsicin.c b/contrib/ffmpeg/libavformat/dsicin.c index fb9cb50df..14f2be8af 100644 --- a/contrib/ffmpeg/libavformat/dsicin.c +++ b/contrib/ffmpeg/libavformat/dsicin.c @@ -58,9 +58,6 @@ typedef struct CinDemuxContext { static int cin_probe(AVProbeData *p) { - if (p->buf_size < 18) - return 0; - /* header starts with this special marker */ if (AV_RL32(&p->buf[0]) != 0x55AA0000) return 0; @@ -95,9 +92,9 @@ static int cin_read_file_header(CinDemuxContext *cin, ByteIOContext *pb) { static int cin_read_header(AVFormatContext *s, AVFormatParameters *ap) { int rc; - CinDemuxContext *cin = (CinDemuxContext *)s->priv_data; + CinDemuxContext *cin = s->priv_data; CinFileHeader *hdr = &cin->file_header; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; rc = cin_read_file_header(cin, pb); @@ -111,7 +108,7 @@ static int cin_read_header(AVFormatContext *s, AVFormatParameters *ap) /* initialize the video decoder stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 32, 1, 12); cin->video_stream_index = st->index; @@ -124,7 +121,7 @@ static int cin_read_header(AVFormatContext *s, AVFormatParameters *ap) /* initialize the audio decoder stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 32, 1, 22050); cin->audio_stream_index = st->index; @@ -150,7 +147,7 @@ static int cin_read_frame_header(CinDemuxContext *cin, ByteIOContext *pb) { hdr->audio_frame_size = get_le32(pb); if (url_feof(pb) || url_ferror(pb)) - return AVERROR_IO; + return AVERROR(EIO); if (get_le32(pb) != 0xAA55AA55) return AVERROR_INVALIDDATA; @@ -160,8 +157,8 @@ static int cin_read_frame_header(CinDemuxContext *cin, ByteIOContext *pb) { static int cin_read_packet(AVFormatContext *s, AVPacket *pkt) { - CinDemuxContext *cin = (CinDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + CinDemuxContext *cin = s->priv_data; + ByteIOContext *pb = s->pb; CinFrameHeader *hdr = &cin->frame_header; int rc, palette_type, pkt_size; @@ -181,7 +178,7 @@ static int cin_read_packet(AVFormatContext *s, AVPacket *pkt) pkt_size = (palette_type + 3) * hdr->pal_colors_count + hdr->video_frame_size; if (av_new_packet(pkt, 4 + pkt_size)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); pkt->stream_index = cin->video_stream_index; pkt->pts = cin->video_stream_pts++; @@ -192,7 +189,7 @@ static int cin_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->data[3] = hdr->video_frame_type; if (get_buffer(pb, &pkt->data[4], pkt_size) != pkt_size) - return AVERROR_IO; + return AVERROR(EIO); /* sound buffer will be processed on next read_packet() call */ cin->audio_buffer_size = hdr->audio_frame_size; @@ -201,14 +198,14 @@ static int cin_read_packet(AVFormatContext *s, AVPacket *pkt) /* audio packet */ if (av_new_packet(pkt, cin->audio_buffer_size)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); pkt->stream_index = cin->audio_stream_index; pkt->pts = cin->audio_stream_pts; cin->audio_stream_pts += cin->audio_buffer_size * 2 / cin->file_header.audio_frame_size; if (get_buffer(pb, pkt->data, cin->audio_buffer_size) != cin->audio_buffer_size) - return AVERROR_IO; + return AVERROR(EIO); cin->audio_buffer_size = 0; return 0; diff --git a/contrib/ffmpeg/libavformat/dv.c b/contrib/ffmpeg/libavformat/dv.c index 10a306260..6fb27bfe0 100644 --- a/contrib/ffmpeg/libavformat/dv.c +++ b/contrib/ffmpeg/libavformat/dv.c @@ -347,7 +347,7 @@ static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c, // FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk) const DVprofile* sys = dv_codec_profile(c->vst->codec); int64_t offset; - int64_t size = url_fsize(&s->pb); + int64_t size = url_fsize(s->pb); int64_t max_offset = ((size-1) / sys->frame_size) * sys->frame_size; offset = sys->frame_size * timestamp; @@ -386,9 +386,9 @@ static int dv_read_header(AVFormatContext *s, if (!c->dv_demux) return -1; - if (get_buffer(&s->pb, c->buf, DV_PROFILE_BYTES) <= 0 || - url_fseek(&s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0) - return AVERROR_IO; + if (get_buffer(s->pb, c->buf, DV_PROFILE_BYTES) <= 0 || + url_fseek(s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0) + return AVERROR(EIO); c->dv_demux->sys = dv_frame_profile(c->buf); s->bit_rate = av_rescale(c->dv_demux->sys->frame_size * 8, @@ -408,8 +408,8 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) if (size < 0) { size = c->dv_demux->sys->frame_size; - if (get_buffer(&s->pb, c->buf, size) <= 0) - return AVERROR_IO; + if (get_buffer(s->pb, c->buf, size) <= 0) + return AVERROR(EIO); size = dv_produce_packet(c->dv_demux, pkt, c->buf, size); } @@ -426,7 +426,8 @@ static int dv_read_seek(AVFormatContext *s, int stream_index, dv_offset_reset(c, offset / c->sys->frame_size); - return url_fseek(&s->pb, offset, SEEK_SET); + offset = url_fseek(s->pb, offset, SEEK_SET); + return (offset < 0)?offset:0; } static int dv_read_close(AVFormatContext *s) diff --git a/contrib/ffmpeg/libavformat/dv.h b/contrib/ffmpeg/libavformat/dv.h index 2fa30036c..cfe93533a 100644 --- a/contrib/ffmpeg/libavformat/dv.h +++ b/contrib/ffmpeg/libavformat/dv.h @@ -25,6 +25,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef FFMPEG_DV_H +#define FFMPEG_DV_H + +#include "avformat.h" + typedef struct DVDemuxContext DVDemuxContext; DVDemuxContext* dv_init_demux(AVFormatContext* s); int dv_get_packet(DVDemuxContext*, AVPacket *); @@ -35,3 +40,5 @@ typedef struct DVMuxContext DVMuxContext; DVMuxContext* dv_init_mux(AVFormatContext* s); int dv_assemble_frame(DVMuxContext *c, AVStream*, const uint8_t*, int, uint8_t**); void dv_delete_mux(DVMuxContext*); + +#endif /* FFMPEG_DV_H */ diff --git a/contrib/ffmpeg/libavformat/dv1394.c b/contrib/ffmpeg/libavformat/dv1394.c deleted file mode 100644 index 3a5f479c8..000000000 --- a/contrib/ffmpeg/libavformat/dv1394.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Linux DV1394 interface - * Copyright (c) 2003 Max Krasnyansky <maxk@qualcomm.com> - * - * 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 <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/poll.h> -#include <sys/time.h> -#include <time.h> - -#include "avformat.h" - -#undef DV1394_DEBUG - -#include "dv1394.h" -#include "dv.h" - -struct dv1394_data { - int fd; - int channel; - int format; - - uint8_t *ring; /* Ring buffer */ - int index; /* Current frame index */ - int avail; /* Number of frames available for reading */ - int done; /* Number of completed frames */ - - DVDemuxContext* dv_demux; /* Generic DV muxing/demuxing context */ -}; - -/* - * The trick here is to kludge around well known problem with kernel Ooopsing - * when you try to capture PAL on a device node configure for NTSC. That's - * why we have to configure the device node for PAL, and then read only NTSC - * amount of data. - */ -static int dv1394_reset(struct dv1394_data *dv) -{ - struct dv1394_init init; - - init.channel = dv->channel; - init.api_version = DV1394_API_VERSION; - init.n_frames = DV1394_RING_FRAMES; - init.format = DV1394_PAL; - - if (ioctl(dv->fd, DV1394_INIT, &init) < 0) - return -1; - - dv->avail = dv->done = 0; - return 0; -} - -static int dv1394_start(struct dv1394_data *dv) -{ - /* Tell DV1394 driver to enable receiver */ - if (ioctl(dv->fd, DV1394_START_RECEIVE, 0) < 0) { - perror("Failed to start receiver"); - return -1; - } - return 0; -} - -static int dv1394_read_header(AVFormatContext * context, AVFormatParameters * ap) -{ - struct dv1394_data *dv = context->priv_data; - - dv->dv_demux = dv_init_demux(context); - if (!dv->dv_demux) - goto failed; - - if (ap->standard && !strcasecmp(ap->standard, "pal")) - dv->format = DV1394_PAL; - else - dv->format = DV1394_NTSC; - - if (ap->channel) - dv->channel = ap->channel; - else - dv->channel = DV1394_DEFAULT_CHANNEL; - - /* Open and initialize DV1394 device */ - dv->fd = open(context->filename, O_RDONLY); - if (dv->fd < 0) { - perror("Failed to open DV interface"); - goto failed; - } - - if (dv1394_reset(dv) < 0) { - perror("Failed to initialize DV interface"); - goto failed; - } - - dv->ring = mmap(NULL, DV1394_PAL_FRAME_SIZE * DV1394_RING_FRAMES, - PROT_READ, MAP_PRIVATE, dv->fd, 0); - if (dv->ring == MAP_FAILED) { - perror("Failed to mmap DV ring buffer"); - goto failed; - } - - if (dv1394_start(dv) < 0) - goto failed; - - return 0; - -failed: - close(dv->fd); - return AVERROR_IO; -} - -static int dv1394_read_packet(AVFormatContext *context, AVPacket *pkt) -{ - struct dv1394_data *dv = context->priv_data; - int size; - - size = dv_get_packet(dv->dv_demux, pkt); - if (size > 0) - return size; - - if (!dv->avail) { - struct dv1394_status s; - struct pollfd p; - - if (dv->done) { - /* Request more frames */ - if (ioctl(dv->fd, DV1394_RECEIVE_FRAMES, dv->done) < 0) { - /* This usually means that ring buffer overflowed. - * We have to reset :(. - */ - - av_log(context, AV_LOG_ERROR, "DV1394: Ring buffer overflow. Reseting ..\n"); - - dv1394_reset(dv); - dv1394_start(dv); - } - dv->done = 0; - } - - /* Wait until more frames are available */ -restart_poll: - p.fd = dv->fd; - p.events = POLLIN | POLLERR | POLLHUP; - if (poll(&p, 1, -1) < 0) { - if (errno == EAGAIN || errno == EINTR) - goto restart_poll; - perror("Poll failed"); - return AVERROR_IO; - } - - if (ioctl(dv->fd, DV1394_GET_STATUS, &s) < 0) { - perror("Failed to get status"); - return AVERROR_IO; - } -#ifdef DV1394_DEBUG - av_log(context, AV_LOG_DEBUG, "DV1394: status\n" - "\tactive_frame\t%d\n" - "\tfirst_clear_frame\t%d\n" - "\tn_clear_frames\t%d\n" - "\tdropped_frames\t%d\n", - s.active_frame, s.first_clear_frame, - s.n_clear_frames, s.dropped_frames); -#endif - - dv->avail = s.n_clear_frames; - dv->index = s.first_clear_frame; - dv->done = 0; - - if (s.dropped_frames) { - av_log(context, AV_LOG_ERROR, "DV1394: Frame drop detected (%d). Reseting ..\n", - s.dropped_frames); - - dv1394_reset(dv); - dv1394_start(dv); - } - } - -#ifdef DV1394_DEBUG - av_log(context, AV_LOG_DEBUG, "index %d, avail %d, done %d\n", dv->index, dv->avail, - dv->done); -#endif - - size = dv_produce_packet(dv->dv_demux, pkt, - dv->ring + (dv->index * DV1394_PAL_FRAME_SIZE), - DV1394_PAL_FRAME_SIZE); - dv->index = (dv->index + 1) % DV1394_RING_FRAMES; - dv->done++; dv->avail--; - - return size; -} - -static int dv1394_close(AVFormatContext * context) -{ - struct dv1394_data *dv = context->priv_data; - - /* Shutdown DV1394 receiver */ - if (ioctl(dv->fd, DV1394_SHUTDOWN, 0) < 0) - perror("Failed to shutdown DV1394"); - - /* Unmap ring buffer */ - if (munmap(dv->ring, DV1394_NTSC_FRAME_SIZE * DV1394_RING_FRAMES) < 0) - perror("Failed to munmap DV1394 ring buffer"); - - close(dv->fd); - av_free(dv->dv_demux); - - return 0; -} - -AVInputFormat dv1394_demuxer = { - .name = "dv1394", - .long_name = "dv1394 A/V grab", - .priv_data_size = sizeof(struct dv1394_data), - .read_header = dv1394_read_header, - .read_packet = dv1394_read_packet, - .read_close = dv1394_close, - .flags = AVFMT_NOFILE -}; diff --git a/contrib/ffmpeg/libavformat/dv1394.h b/contrib/ffmpeg/libavformat/dv1394.h deleted file mode 100644 index f7db40108..000000000 --- a/contrib/ffmpeg/libavformat/dv1394.h +++ /dev/null @@ -1,357 +0,0 @@ -/* - * dv1394.h - DV input/output over IEEE 1394 on OHCI chips - * Copyright (C)2001 Daniel Maas <dmaas@dcine.com> - * receive, proc_fs by Dan Dennedy <dan@dennedy.org> - * - * based on: - * video1394.h - driver for OHCI 1394 boards - * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> - * Peter Schlaile <udbz@rz.uni-karlsruhe.de> - * - * 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 _DV_1394_H -#define _DV_1394_H - -#define DV1394_DEFAULT_CHANNEL 63 -#define DV1394_DEFAULT_CARD 0 -#define DV1394_RING_FRAMES 20 - -#define DV1394_WIDTH 720 -#define DV1394_NTSC_HEIGHT 480 -#define DV1394_PAL_HEIGHT 576 - -/* This is the public user-space interface. Try not to break it. */ - -#define DV1394_API_VERSION 0x20011127 - -/* ******************** - ** ** - ** DV1394 API ** - ** ** - ******************** - - There are two methods of operating the DV1394 DV output device. - - 1) - - The simplest is an interface based on write(): simply write - full DV frames of data to the device, and they will be transmitted - as quickly as possible. The FD may be set for non-blocking I/O, - in which case you can use select() or poll() to wait for output - buffer space. - - To set the DV output parameters (e.g. whether you want NTSC or PAL - video), use the DV1394_INIT ioctl, passing in the parameters you - want in a struct dv1394_init. - - Example 1: - To play a raw .DV file: cat foo.DV > /dev/dv1394 - (cat will use write() internally) - - Example 2: - static struct dv1394_init init = { - 0x63, (broadcast channel) - 4, (four-frame ringbuffer) - DV1394_NTSC, (send NTSC video) - 0, 0 (default empty packet rate) - } - - ioctl(fd, DV1394_INIT, &init); - - while(1) { - read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE ); - write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE ); - } - - 2) - - For more control over buffering, and to avoid unnecessary copies - of the DV data, you can use the more sophisticated the mmap() interface. - First, call the DV1394_INIT ioctl to specify your parameters, - including the number of frames in the ringbuffer. Then, calling mmap() - on the dv1394 device will give you direct access to the ringbuffer - from which the DV card reads your frame data. - - The ringbuffer is simply one large, contiguous region of memory - containing two or more frames of packed DV data. Each frame of DV data - is 120000 bytes (NTSC) or 144000 bytes (PAL). - - Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES - ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl - or select()/poll() to wait until the frames are transmitted. Next, you'll - need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer - frames are clear (ready to be filled with new DV data). Finally, use - DV1394_SUBMIT_FRAMES again to send the new data to the DV output. - - - Example: here is what a four-frame ringbuffer might look like - during DV transmission: - - - frame 0 frame 1 frame 2 frame 3 - - *--------------------------------------* - | CLEAR | DV data | DV data | CLEAR | - *--------------------------------------* - <ACTIVE> - - transmission goes in this direction --->>> - - - The DV hardware is currently transmitting the data in frame 1. - Once frame 1 is finished, it will automatically transmit frame 2. - (if frame 2 finishes before frame 3 is submitted, the device - will continue to transmit frame 2, and will increase the dropped_frames - counter each time it repeats the transmission). - - - If you called DV1394_GET_STATUS at this instant, you would - receive the following values: - - n_frames = 4 - active_frame = 1 - first_clear_frame = 3 - n_clear_frames = 2 - - At this point, you should write new DV data into frame 3 and optionally - frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that - it may transmit the new frames. - - ERROR HANDLING - - An error (buffer underflow/overflow or a break in the DV stream due - to a 1394 bus reset) can be detected by checking the dropped_frames - field of struct dv1394_status (obtained through the - DV1394_GET_STATUS ioctl). - - The best way to recover from such an error is to re-initialize - dv1394, either by using the DV1394_INIT ioctl call, or closing the - file descriptor and opening it again. (note that you must unmap all - ringbuffer mappings when closing the file descriptor, or else - dv1394 will still be considered 'in use'). - - MAIN LOOP - - For maximum efficiency and robustness against bus errors, you are - advised to model the main loop of your application after the - following pseudo-code example: - - (checks of system call return values omitted for brevity; always - check return values in your code!) - - while( frames left ) { - - struct pollfd *pfd = ...; - - pfd->fd = dv1394_fd; - pfd->revents = 0; - pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive) - - (add other sources of I/O here) - - poll(pfd, 1, -1); (or select(); add a timeout if you want) - - if(pfd->revents) { - struct dv1394_status status; - - ioctl(dv1394_fd, DV1394_GET_STATUS, &status); - - if(status.dropped_frames > 0) { - reset_dv1394(); - } else { - for(int i = 0; i < status.n_clear_frames; i++) { - copy_DV_frame(); - } - } - } - } - - where copy_DV_frame() reads or writes on the dv1394 file descriptor - (read/write mode) or copies data to/from the mmap ringbuffer and - then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new - frames are availble (mmap mode). - - reset_dv1394() is called in the event of a buffer - underflow/overflow or a halt in the DV stream (e.g. due to a 1394 - bus reset). To guarantee recovery from the error, this function - should close the dv1394 file descriptor (and munmap() all - ringbuffer mappings, if you are using them), then re-open the - dv1394 device (and re-map the ringbuffer). - -*/ - - -/* maximum number of frames in the ringbuffer */ -#define DV1394_MAX_FRAMES 32 - -/* number of *full* isochronous packets per DV frame */ -#define DV1394_NTSC_PACKETS_PER_FRAME 250 -#define DV1394_PAL_PACKETS_PER_FRAME 300 - -/* size of one frame's worth of DV data, in bytes */ -#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME) -#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME) - - -/* ioctl() commands */ - -enum { - /* I don't like using 0 as a valid ioctl() */ - DV1394_INVALID = 0, - - - /* get the driver ready to transmit video. - pass a struct dv1394_init* as the parameter (see below), - or NULL to get default parameters */ - DV1394_INIT, - - - /* stop transmitting video and free the ringbuffer */ - DV1394_SHUTDOWN, - - - /* submit N new frames to be transmitted, where - the index of the first new frame is first_clear_buffer, - and the index of the last new frame is - (first_clear_buffer + N) % n_frames */ - DV1394_SUBMIT_FRAMES, - - - /* block until N buffers are clear (pass N as the parameter) - Because we re-transmit the last frame on underrun, there - will at most be n_frames - 1 clear frames at any time */ - DV1394_WAIT_FRAMES, - - /* capture new frames that have been received, where - the index of the first new frame is first_clear_buffer, - and the index of the last new frame is - (first_clear_buffer + N) % n_frames */ - DV1394_RECEIVE_FRAMES, - - - DV1394_START_RECEIVE, - - - /* pass a struct dv1394_status* as the parameter (see below) */ - DV1394_GET_STATUS, -}; - - - -enum pal_or_ntsc { - DV1394_NTSC = 0, - DV1394_PAL -}; - - - - -/* this is the argument to DV1394_INIT */ -struct dv1394_init { - /* DV1394_API_VERSION */ - unsigned int api_version; - - /* isochronous transmission channel to use */ - unsigned int channel; - - /* number of frames in the ringbuffer. Must be at least 2 - and at most DV1394_MAX_FRAMES. */ - unsigned int n_frames; - - /* send/receive PAL or NTSC video format */ - enum pal_or_ntsc format; - - /* the following are used only for transmission */ - - /* set these to zero unless you want a - non-default empty packet rate (see below) */ - unsigned long cip_n; - unsigned long cip_d; - - /* set this to zero unless you want a - non-default SYT cycle offset (default = 3 cycles) */ - unsigned int syt_offset; -}; - -/* NOTE: you may only allocate the DV frame ringbuffer once each time - you open the dv1394 device. DV1394_INIT will fail if you call it a - second time with different 'n_frames' or 'format' arguments (which - would imply a different size for the ringbuffer). If you need a - different buffer size, simply close and re-open the device, then - initialize it with your new settings. */ - -/* Q: What are cip_n and cip_d? */ - -/* - A: DV video streams do not utilize 100% of the potential bandwidth offered - by IEEE 1394 (FireWire). To achieve the correct rate of data transmission, - DV devices must periodically insert empty packets into the 1394 data stream. - Typically there is one empty packet per 14-16 data-carrying packets. - - Some DV devices will accept a wide range of empty packet rates, while others - require a precise rate. If the dv1394 driver produces empty packets at - a rate that your device does not accept, you may see ugly patterns on the - DV output, or even no output at all. - - The default empty packet insertion rate seems to work for many people; if - your DV output is stable, you can simply ignore this discussion. However, - we have exposed the empty packet rate as a parameter to support devices that - do not work with the default rate. - - The decision to insert an empty packet is made with a numerator/denominator - algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D. - You can alter the empty packet rate by passing non-zero values for cip_n - and cip_d to the INIT ioctl. - - */ - - - -struct dv1394_status { - /* this embedded init struct returns the current dv1394 - parameters in use */ - struct dv1394_init init; - - /* the ringbuffer frame that is currently being - displayed. (-1 if the device is not transmitting anything) */ - int active_frame; - - /* index of the first buffer (ahead of active_frame) that - is ready to be filled with data */ - unsigned int first_clear_frame; - - /* how many buffers, including first_clear_buffer, are - ready to be filled with data */ - unsigned int n_clear_frames; - - /* how many times the DV stream has underflowed, overflowed, - or otherwise encountered an error, since the previous call - to DV1394_GET_STATUS */ - unsigned int dropped_frames; - - /* N.B. The dropped_frames counter is only a lower bound on the actual - number of dropped frames, with the special case that if dropped_frames - is zero, then it is guaranteed that NO frames have been dropped - since the last call to DV1394_GET_STATUS. - */ -}; - - -#endif /* _DV_1394_H */ diff --git a/contrib/ffmpeg/libavformat/dvenc.c b/contrib/ffmpeg/libavformat/dvenc.c index bdac43784..0d6002818 100644 --- a/contrib/ffmpeg/libavformat/dvenc.c +++ b/contrib/ffmpeg/libavformat/dvenc.c @@ -77,100 +77,100 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu buf[0] = (uint8_t)pack_id; switch (pack_id) { case dv_timecode: - ct = (time_t)(c->frames / ((float)c->sys->frame_rate / - (float)c->sys->frame_rate_base)); - 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 fame: 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 */ - break; + ct = (time_t)(c->frames / ((float)c->sys->frame_rate / + (float)c->sys->frame_rate_base)); + 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 fame: 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 */ + break; case dv_audio_source: /* AAUX source pack */ - va_start(ap, buf); - buf[1] = (1 << 7) | /* locked mode -- SMPTE only supports locked mode */ - (1 << 6) | /* reserved -- always 1 */ - (dv_audio_frame_size(c->sys, c->frames) - - c->sys->audio_min_samples[0]); - /* # of samples */ - buf[2] = (0 << 7) | /* multi-stereo */ - (0 << 5) | /* #of audio channels per block: 0 -- 1 channel */ - (0 << 4) | /* pair bit: 0 -- one pair of channels */ - !!va_arg(ap, int); /* audio mode */ - buf[3] = (1 << 7) | /* res */ - (1 << 6) | /* multi-language flag */ - (c->sys->dsf << 5) | /* system: 60fields/50fields */ - (c->sys->n_difchan & 2); /* definition: 0 -- 25Mbps, 2 -- 50Mbps */ - buf[4] = (1 << 7) | /* emphasis: 1 -- off */ - (0 << 6) | /* emphasis time constant: 0 -- reserved */ - (0 << 3) | /* frequency: 0 -- 48Khz, 1 -- 44,1Khz, 2 -- 32Khz */ - 0; /* quantization: 0 -- 16bit linear, 1 -- 12bit nonlinear */ - va_end(ap); - break; + va_start(ap, buf); + buf[1] = (1 << 7) | /* locked mode -- SMPTE only supports locked mode */ + (1 << 6) | /* reserved -- always 1 */ + (dv_audio_frame_size(c->sys, c->frames) - + c->sys->audio_min_samples[0]); + /* # of samples */ + buf[2] = (0 << 7) | /* multi-stereo */ + (0 << 5) | /* #of audio channels per block: 0 -- 1 channel */ + (0 << 4) | /* pair bit: 0 -- one pair of channels */ + !!va_arg(ap, int); /* audio mode */ + buf[3] = (1 << 7) | /* res */ + (1 << 6) | /* multi-language flag */ + (c->sys->dsf << 5) | /* system: 60fields/50fields */ + (c->sys->n_difchan & 2); /* definition: 0 -- 25Mbps, 2 -- 50Mbps */ + buf[4] = (1 << 7) | /* emphasis: 1 -- off */ + (0 << 6) | /* emphasis time constant: 0 -- reserved */ + (0 << 3) | /* frequency: 0 -- 48Khz, 1 -- 44,1Khz, 2 -- 32Khz */ + 0; /* quantization: 0 -- 16bit linear, 1 -- 12bit nonlinear */ + va_end(ap); + break; case dv_audio_control: - buf[1] = (0 << 6) | /* copy protection: 0 -- unrestricted */ - (1 << 4) | /* input source: 1 -- digital input */ - (3 << 2) | /* compression: 3 -- no information */ - 0; /* misc. info/SMPTE emphasis off */ - buf[2] = (1 << 7) | /* recording start point: 1 -- no */ - (1 << 6) | /* recording end point: 1 -- no */ - (1 << 3) | /* recording mode: 1 -- original */ - 7; - buf[3] = (1 << 7) | /* direction: 1 -- forward */ - (c->sys->pix_fmt == PIX_FMT_YUV420P ? 0x20 : /* speed */ - c->sys->ltc_divisor*4); - buf[4] = (1 << 7) | /* reserved -- always 1 */ - 0x7f; /* genre category */ - break; + buf[1] = (0 << 6) | /* copy protection: 0 -- unrestricted */ + (1 << 4) | /* input source: 1 -- digital input */ + (3 << 2) | /* compression: 3 -- no information */ + 0; /* misc. info/SMPTE emphasis off */ + buf[2] = (1 << 7) | /* recording start point: 1 -- no */ + (1 << 6) | /* recording end point: 1 -- no */ + (1 << 3) | /* recording mode: 1 -- original */ + 7; + buf[3] = (1 << 7) | /* direction: 1 -- forward */ + (c->sys->pix_fmt == PIX_FMT_YUV420P ? 0x20 : /* speed */ + c->sys->ltc_divisor*4); + buf[4] = (1 << 7) | /* reserved -- always 1 */ + 0x7f; /* genre category */ + break; case dv_audio_recdate: case dv_video_recdate: /* VAUX recording date */ - ct = c->start_time + (time_t)(c->frames / - ((float)c->sys->frame_rate / (float)c->sys->frame_rate_base)); - brktimegm(ct, &tc); - buf[1] = 0xff; /* ds, tm, tens of time zone, units of time zone */ - /* 0xff is very likely to be "unknown" */ - buf[2] = (3 << 6) | /* reserved -- always 1 */ - ((tc.tm_mday / 10) << 4) | /* Tens of day */ - (tc.tm_mday % 10); /* Units of day */ - buf[3] = /* we set high 4 bits to 0, shouldn't we set them to week? */ - ((tc.tm_mon / 10) << 4) | /* Tens of month */ - (tc.tm_mon % 10); /* Units of month */ - buf[4] = (((tc.tm_year % 100) / 10) << 4) | /* Tens of year */ - (tc.tm_year % 10); /* Units of year */ - break; + ct = c->start_time + (time_t)(c->frames / + ((float)c->sys->frame_rate / (float)c->sys->frame_rate_base)); + brktimegm(ct, &tc); + buf[1] = 0xff; /* ds, tm, tens of time zone, units of time zone */ + /* 0xff is very likely to be "unknown" */ + buf[2] = (3 << 6) | /* reserved -- always 1 */ + ((tc.tm_mday / 10) << 4) | /* Tens of day */ + (tc.tm_mday % 10); /* Units of day */ + buf[3] = /* we set high 4 bits to 0, shouldn't we set them to week? */ + ((tc.tm_mon / 10) << 4) | /* Tens of month */ + (tc.tm_mon % 10); /* Units of month */ + buf[4] = (((tc.tm_year % 100) / 10) << 4) | /* Tens of year */ + (tc.tm_year % 10); /* Units of year */ + break; case dv_audio_rectime: /* AAUX recording time */ case dv_video_rectime: /* VAUX recording time */ - ct = c->start_time + (time_t)(c->frames / - ((float)c->sys->frame_rate / (float)c->sys->frame_rate_base)); - brktimegm(ct, &tc); - buf[1] = (3 << 6) | /* reserved -- always 1 */ - 0x3f; /* tens of frame, units of frame: 0x3f - "unknown" ? */ - buf[2] = (1 << 7) | /* reserved -- always 1 */ - ((tc.tm_sec / 10) << 4) | /* Tens of seconds */ - (tc.tm_sec % 10); /* Units of seconds */ - buf[3] = (1 << 7) | /* reserved -- always 1 */ - ((tc.tm_min / 10) << 4) | /* Tens of minutes */ - (tc.tm_min % 10); /* Units of minutes */ - buf[4] = (3 << 6) | /* reserved -- always 1 */ - ((tc.tm_hour / 10) << 4) | /* Tens of hours */ - (tc.tm_hour % 10); /* Units of hours */ - break; + ct = c->start_time + (time_t)(c->frames / + ((float)c->sys->frame_rate / (float)c->sys->frame_rate_base)); + brktimegm(ct, &tc); + buf[1] = (3 << 6) | /* reserved -- always 1 */ + 0x3f; /* tens of frame, units of frame: 0x3f - "unknown" ? */ + buf[2] = (1 << 7) | /* reserved -- always 1 */ + ((tc.tm_sec / 10) << 4) | /* Tens of seconds */ + (tc.tm_sec % 10); /* Units of seconds */ + buf[3] = (1 << 7) | /* reserved -- always 1 */ + ((tc.tm_min / 10) << 4) | /* Tens of minutes */ + (tc.tm_min % 10); /* Units of minutes */ + buf[4] = (3 << 6) | /* reserved -- always 1 */ + ((tc.tm_hour / 10) << 4) | /* Tens of hours */ + (tc.tm_hour % 10); /* Units of hours */ + break; default: - buf[1] = buf[2] = buf[3] = buf[4] = 0xff; + buf[1] = buf[2] = buf[3] = buf[4] = 0xff; } return 5; } @@ -181,19 +181,19 @@ static void dv_inject_audio(DVMuxContext *c, int channel, uint8_t* frame_ptr) size = 4 * dv_audio_frame_size(c->sys, c->frames); frame_ptr += channel * c->sys->difseg_size * 150 * 80; for (i = 0; i < c->sys->difseg_size; i++) { - frame_ptr += 6 * 80; /* skip DIF segment header */ - for (j = 0; j < 9; j++) { - dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], i >= c->sys->difseg_size/2); - for (d = 8; d < 80; d+=2) { - of = c->sys->audio_shuffle[i][j] + (d - 8)/2 * c->sys->audio_stride; - if (of*2 >= size) - continue; - - frame_ptr[d] = av_fifo_peek(&c->audio_data[channel], of*2+1); // FIXME: may be we have to admit - frame_ptr[d+1] = av_fifo_peek(&c->audio_data[channel], of*2); // that DV is a big endian PCM - } - frame_ptr += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */ - } + frame_ptr += 6 * 80; /* skip DIF segment header */ + for (j = 0; j < 9; j++) { + dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], i >= c->sys->difseg_size/2); + for (d = 8; d < 80; d+=2) { + of = c->sys->audio_shuffle[i][j] + (d - 8)/2 * c->sys->audio_stride; + if (of*2 >= size) + continue; + + frame_ptr[d] = av_fifo_peek(&c->audio_data[channel], of*2+1); // FIXME: may be we have to admit + frame_ptr[d+1] = av_fifo_peek(&c->audio_data[channel], of*2); // that DV is a big endian PCM + } + frame_ptr += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */ + } } } @@ -240,39 +240,41 @@ int dv_assemble_frame(DVMuxContext *c, AVStream* st, switch (st->codec->codec_type) { case CODEC_TYPE_VIDEO: - /* FIXME: we have to have more sensible approach than this one */ - if (c->has_video) - av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient audio data or severe sync problem.\n", c->frames); + /* FIXME: we have to have more sensible approach than this one */ + if (c->has_video) + av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient audio data or severe sync problem.\n", c->frames); - memcpy(*frame, data, c->sys->frame_size); - c->has_video = 1; - break; + memcpy(*frame, data, c->sys->frame_size); + c->has_video = 1; + break; case CODEC_TYPE_AUDIO: - for (i = 0; i < c->n_ast && st != c->ast[i]; i++); + for (i = 0; i < c->n_ast && st != c->ast[i]; i++); /* FIXME: we have to have more sensible approach than this one */ - if (av_fifo_size(&c->audio_data[i]) + data_size >= 100*AVCODEC_MAX_AUDIO_FRAME_SIZE) - av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient video data or severe sync problem.\n", c->frames); - av_fifo_write(&c->audio_data[i], data, data_size); + if (av_fifo_size(&c->audio_data[i]) + data_size >= 100*AVCODEC_MAX_AUDIO_FRAME_SIZE) + av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient video data or severe sync problem.\n", c->frames); + av_fifo_write(&c->audio_data[i], data, data_size); - /* Lets see if we've got enough audio for one DV frame */ - c->has_audio |= ((reqasize <= av_fifo_size(&c->audio_data[i])) << i); + /* Lets see if we've got enough audio for one DV frame */ + c->has_audio |= ((reqasize <= av_fifo_size(&c->audio_data[i])) << i); - break; + break; default: - break; + break; } /* Lets see if we have enough data to construct one DV frame */ if (c->has_video == 1 && c->has_audio + 1 == 1<<c->n_ast) { dv_inject_metadata(c, *frame); + c->has_audio = 0; for (i=0; i<c->n_ast; i++) { - dv_inject_audio(c, i, *frame); - av_fifo_drain(&c->audio_data[i], reqasize); + dv_inject_audio(c, i, *frame); + av_fifo_drain(&c->audio_data[i], reqasize); + c->has_audio |= ((reqasize <= av_fifo_size(&c->audio_data[i])) << i); } c->has_video = 0; - c->has_audio = 0; + c->frames++; return c->sys->frame_size; @@ -283,7 +285,7 @@ int dv_assemble_frame(DVMuxContext *c, AVStream* st, DVMuxContext* dv_init_mux(AVFormatContext* s) { - DVMuxContext *c = (DVMuxContext *)s->priv_data; + DVMuxContext *c = s->priv_data; AVStream *vst = NULL; int i; @@ -296,16 +298,18 @@ DVMuxContext* dv_init_mux(AVFormatContext* s) /* We have to sort out where audio and where video stream is */ for (i=0; i<s->nb_streams; i++) { - switch (s->streams[i]->codec->codec_type) { - case CODEC_TYPE_VIDEO: - vst = s->streams[i]; - break; - case CODEC_TYPE_AUDIO: - c->ast[c->n_ast++] = s->streams[i]; - break; - default: - goto bail_out; - } + switch (s->streams[i]->codec->codec_type) { + case CODEC_TYPE_VIDEO: + if (vst) return NULL; + vst = s->streams[i]; + break; + case CODEC_TYPE_AUDIO: + if (c->n_ast > 1) return NULL; + c->ast[c->n_ast++] = s->streams[i]; + break; + default: + goto bail_out; + } } /* Some checks -- DV format is very picky about its incoming streams */ @@ -373,11 +377,11 @@ static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt) uint8_t* frame; int fsize; - fsize = dv_assemble_frame((DVMuxContext *)s->priv_data, s->streams[pkt->stream_index], + fsize = dv_assemble_frame(s->priv_data, s->streams[pkt->stream_index], pkt->data, pkt->size, &frame); if (fsize > 0) { - put_buffer(&s->pb, frame, fsize); - put_flush_packet(&s->pb); + put_buffer(s->pb, frame, fsize); + put_flush_packet(s->pb); } return 0; } @@ -390,7 +394,7 @@ static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt) */ static int dv_write_trailer(struct AVFormatContext *s) { - dv_delete_mux((DVMuxContext *)s->priv_data); + dv_delete_mux(s->priv_data); return 0; } #endif /* CONFIG_MUXERS */ diff --git a/contrib/ffmpeg/libavformat/dxa.c b/contrib/ffmpeg/libavformat/dxa.c index f49d3d4ac..2df73c7dd 100644 --- a/contrib/ffmpeg/libavformat/dxa.c +++ b/contrib/ffmpeg/libavformat/dxa.c @@ -36,8 +36,6 @@ typedef struct{ static int dxa_probe(AVProbeData *p) { /* check file header */ - if (p->buf_size <= 4) - return 0; if (p->buf[0] == 'D' && p->buf[1] == 'E' && p->buf[2] == 'X' && p->buf[3] == 'A') return AVPROBE_SCORE_MAX; @@ -47,7 +45,7 @@ static int dxa_probe(AVProbeData *p) static int dxa_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; DXAContext *c = s->priv_data; AVStream *st, *ast; uint32_t tag; @@ -146,54 +144,54 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) if(!c->readvid && c->has_sound && c->bytes_left){ c->readvid = 1; - url_fseek(&s->pb, c->wavpos, SEEK_SET); + url_fseek(s->pb, c->wavpos, SEEK_SET); size = FFMIN(c->bytes_left, c->bpc); - ret = av_get_packet(&s->pb, pkt, size); + ret = av_get_packet(s->pb, pkt, size); pkt->stream_index = 1; if(ret != size) - return AVERROR_IO; + return AVERROR(EIO); c->bytes_left -= size; - c->wavpos = url_ftell(&s->pb); + c->wavpos = url_ftell(s->pb); return 0; } - url_fseek(&s->pb, c->vidpos, SEEK_SET); - while(!url_feof(&s->pb) && c->frames){ - get_buffer(&s->pb, buf, 4); + url_fseek(s->pb, c->vidpos, SEEK_SET); + while(!url_feof(s->pb) && c->frames){ + get_buffer(s->pb, buf, 4); switch(AV_RL32(buf)){ case MKTAG('N', 'U', 'L', 'L'): if(av_new_packet(pkt, 4 + pal_size) < 0) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); pkt->stream_index = 0; if(pal_size) memcpy(pkt->data, pal, pal_size); memcpy(pkt->data + pal_size, buf, 4); c->frames--; - c->vidpos = url_ftell(&s->pb); + c->vidpos = url_ftell(s->pb); c->readvid = 0; return 0; case MKTAG('C', 'M', 'A', 'P'): pal_size = 768+4; memcpy(pal, buf, 4); - get_buffer(&s->pb, pal + 4, 768); + get_buffer(s->pb, pal + 4, 768); break; case MKTAG('F', 'R', 'A', 'M'): - get_buffer(&s->pb, buf + 4, DXA_EXTRA_SIZE - 4); + get_buffer(s->pb, buf + 4, DXA_EXTRA_SIZE - 4); size = AV_RB32(buf + 5); if(size > 0xFFFFFF){ av_log(s, AV_LOG_ERROR, "Frame size is too big: %d\n", size); return -1; } if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); memcpy(pkt->data + pal_size, buf, DXA_EXTRA_SIZE); - ret = get_buffer(&s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size); + ret = get_buffer(s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size); if(ret != size){ av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } if(pal_size) memcpy(pkt->data, pal, pal_size); pkt->stream_index = 0; c->frames--; - c->vidpos = url_ftell(&s->pb); + c->vidpos = url_ftell(s->pb); c->readvid = 0; return 0; default: diff --git a/contrib/ffmpeg/libavformat/eacdata.c b/contrib/ffmpeg/libavformat/eacdata.c new file mode 100644 index 000000000..ffaf85e0e --- /dev/null +++ b/contrib/ffmpeg/libavformat/eacdata.c @@ -0,0 +1,100 @@ +/* + * Electronic Arts .cdata file Demuxer + * Copyright (c) 2007 Peter Ross + * + * 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 eacdata.c + * Electronic Arts cdata Format Demuxer + * by Peter Ross (suxen_drol at hotmail dot com) + * + * Technical details here: + * http://wiki.multimedia.cx/index.php?title=EA_Command_And_Conquer_3_Audio_Codec + */ + +#include "avformat.h" + +typedef struct { + unsigned int channels; + unsigned int audio_pts; +} CdataDemuxContext; + +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)) + return AVPROBE_SCORE_MAX/8; + return 0; +} + +static int cdata_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + CdataDemuxContext *cdata = s->priv_data; + ByteIOContext *pb = s->pb; + unsigned int sample_rate, header; + AVStream *st; + + header = get_be16(pb); + switch (header) { + case 0x0400: cdata->channels = 1; break; + case 0x0404: cdata->channels = 2; break; + case 0x040C: cdata->channels = 4; break; + default: + av_log(s, AV_LOG_INFO, "unknown header 0x%04x\n", header); + return -1; + }; + + sample_rate = get_be16(pb); + url_fskip(pb, 12); + + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_tag = 0; /* no fourcc */ + st->codec->codec_id = CODEC_ID_ADPCM_EA_XAS; + st->codec->channels = cdata->channels; + st->codec->sample_rate = sample_rate; + av_set_pts_info(st, 64, 1, sample_rate); + + cdata->audio_pts = 0; + return 0; +} + +static int cdata_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + CdataDemuxContext *cdata = s->priv_data; + int packet_size = 76*cdata->channels; + + if (av_get_packet(s->pb, pkt, packet_size) != packet_size) + return AVERROR(EIO); + pkt->pts = cdata->audio_pts++; + return 1; +} + +AVInputFormat ea_cdata_demuxer = { + "ea_cdata", + "Electronic Arts cdata", + sizeof(CdataDemuxContext), + cdata_probe, + cdata_read_header, + cdata_read_packet, + .extensions = "cdata", +}; diff --git a/contrib/ffmpeg/libavformat/electronicarts.c b/contrib/ffmpeg/libavformat/electronicarts.c index 762d658ab..0201e8200 100644 --- a/contrib/ffmpeg/libavformat/electronicarts.c +++ b/contrib/ffmpeg/libavformat/electronicarts.c @@ -27,33 +27,42 @@ #include "avformat.h" #define SCHl_TAG MKTAG('S', 'C', 'H', 'l') +#define SEAD_TAG MKTAG('S', 'E', 'A', 'D') /* Sxxx header */ +#define SNDC_TAG MKTAG('S', 'N', 'D', 'C') /* Sxxx data */ +#define SEND_TAG MKTAG('S', 'E', 'N', 'D') /* Sxxx end */ +#define ISNh_TAG MKTAG('1', 'S', 'N', 'h') /* 1SNx header */ +#define EACS_TAG MKTAG('E', 'A', 'C', 'S') +#define ISNd_TAG MKTAG('1', 'S', 'N', 'd') /* 1SNx data */ +#define ISNe_TAG MKTAG('1', 'S', 'N', 'e') /* 1SNx end */ #define PT00_TAG MKTAG('P', 'T', 0x0, 0x0) +#define GSTR_TAG MKTAG('G', 'S', 'T', 'R') #define SCDl_TAG MKTAG('S', 'C', 'D', 'l') -#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T') #define SCEl_TAG MKTAG('S', 'C', 'E', 'l') -#define _TAG MKTAG('', '', '', '') - -#define EA_SAMPLE_RATE 22050 -#define EA_BITS_PER_SAMPLE 16 -#define EA_PREAMBLE_SIZE 8 +#define kVGT_TAG MKTAG('k', 'V', 'G', 'T') /* TGV i-frame */ +#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD i-frame */ +#define MPCh_TAG MKTAG('M', 'P', 'C', 'h') /* MPEG2 */ +#define MVhd_TAG MKTAG('M', 'V', 'h', 'd') +#define MV0K_TAG MKTAG('M', 'V', '0', 'K') +#define MV0F_TAG MKTAG('M', 'V', '0', 'F') +#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */ typedef struct EaDemuxContext { - int width; - int height; + int big_endian; + + int video_codec; + AVRational time_base; int video_stream_index; - int track_count; + int audio_codec; int audio_stream_index; int audio_frame_counter; int64_t audio_pts; - int64_t video_pts; - int video_pts_inc; - float fps; + int bytes; + int sample_rate; int num_channels; int num_samples; - int compression_type; } EaDemuxContext; static uint32_t read_arbitary(ByteIOContext *pb) { @@ -74,40 +83,24 @@ static uint32_t read_arbitary(ByteIOContext *pb) { } /* - * Process WVE file header - * Returns 1 if the WVE file is valid and successfully opened, 0 otherwise + * Process PT/GSTR sound header + * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx */ -static int process_ea_header(AVFormatContext *s) { - int inHeader; - uint32_t blockid, size; - EaDemuxContext *ea = (EaDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; - - if (get_buffer(pb, (void*)&blockid, 4) != 4) { - return 0; - } - if (le2me_32(blockid) != SCHl_TAG) { - return 0; - } - - if (get_buffer(pb, (void*)&size, 4) != 4) { - return 0; - } - size = le2me_32(size); +static int process_audio_header_elements(AVFormatContext *s) +{ + int inHeader = 1; + EaDemuxContext *ea = s->priv_data; + ByteIOContext *pb = s->pb; + int compression_type = -1, revision = -1, revision2 = -1; - if (get_buffer(pb, (void*)&blockid, 4) != 4) { - return 0; - } - if (le2me_32(blockid) != PT00_TAG) { - av_log (s, AV_LOG_ERROR, "PT header missing\n"); - return 0; - } + ea->bytes = 2; + ea->sample_rate = -1; + ea->num_channels = 1; - inHeader = 1; while (inHeader) { int inSubheader; uint8_t byte; - byte = get_byte(pb) & 0xFF; + byte = get_byte(pb); switch (byte) { case 0xFD: @@ -115,16 +108,24 @@ static int process_ea_header(AVFormatContext *s) { inSubheader = 1; while (inSubheader) { uint8_t subbyte; - subbyte = get_byte(pb) & 0xFF; + subbyte = get_byte(pb); switch (subbyte) { + case 0x80: + revision = read_arbitary(pb); + av_log (s, AV_LOG_INFO, "revision (element 0x80) set to 0x%08x\n", revision); + break; case 0x82: ea->num_channels = read_arbitary(pb); av_log (s, AV_LOG_INFO, "num_channels (element 0x82) set to 0x%08x\n", ea->num_channels); break; case 0x83: - ea->compression_type = read_arbitary(pb); - av_log (s, AV_LOG_INFO, "compression_type (element 0x83) set to 0x%08x\n", ea->compression_type); + compression_type = read_arbitary(pb); + av_log (s, AV_LOG_INFO, "compression_type (element 0x83) set to 0x%08x\n", compression_type); + break; + case 0x84: + ea->sample_rate = read_arbitary(pb); + av_log (s, AV_LOG_INFO, "sample_rate (element 0x84) set to %i\n", ea->sample_rate); break; case 0x85: ea->num_samples = read_arbitary(pb); @@ -135,6 +136,15 @@ static int process_ea_header(AVFormatContext *s) { av_log (s, AV_LOG_INFO, "exited audio subheader\n"); inSubheader = 0; break; + case 0xA0: + revision2 = read_arbitary(pb); + av_log (s, AV_LOG_INFO, "revision2 (element 0xA0) set to 0x%08x\n", revision2); + break; + case 0xFF: + av_log (s, AV_LOG_INFO, "end of header block reached (within audio subheader)\n"); + inSubheader = 0; + inHeader = 0; + break; default: av_log (s, AV_LOG_INFO, "element 0x%02x set to 0x%08x\n", subbyte, read_arbitary(pb)); break; @@ -151,67 +161,218 @@ static int process_ea_header(AVFormatContext *s) { } } - if ((ea->num_channels != 2) || (ea->compression_type != 7)) { - av_log (s, AV_LOG_ERROR, "unsupported stream type\n"); + switch (compression_type) { + case 0: ea->audio_codec = CODEC_ID_PCM_S16LE; break; + case 7: ea->audio_codec = CODEC_ID_ADPCM_EA; break; + case -1: + switch (revision) { + case 1: ea->audio_codec = CODEC_ID_ADPCM_EA_R1; break; + case 2: ea->audio_codec = CODEC_ID_ADPCM_EA_R2; break; + case 3: ea->audio_codec = CODEC_ID_ADPCM_EA_R3; break; + case -1: break; + default: + av_log(s, AV_LOG_ERROR, "unsupported stream type; revision=%i\n", revision); + return 0; + } + switch (revision2) { + case 8: ea->audio_codec = CODEC_ID_PCM_S16LE_PLANAR; break; + default: + av_log(s, AV_LOG_ERROR, "unsupported stream type; revision2=%i\n", revision2); + return 0; + } + break; + default: + av_log(s, AV_LOG_ERROR, "unsupported stream type; compression_type=%i\n", compression_type); return 0; } - /* skip to the start of the data */ - url_fseek(pb, size, SEEK_SET); + if (ea->sample_rate == -1) + ea->sample_rate = revision==3 ? 48000 : 22050; return 1; } +/* + * Process EACS sound header + * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx + */ +static int process_audio_header_eacs(AVFormatContext *s) +{ + EaDemuxContext *ea = s->priv_data; + ByteIOContext *pb = s->pb; + int compression_type; -static int ea_probe(AVProbeData *p) + ea->sample_rate = ea->big_endian ? get_be32(pb) : get_le32(pb); + ea->bytes = get_byte(pb); /* 1=8-bit, 2=16-bit */ + ea->num_channels = get_byte(pb); + compression_type = get_byte(pb); + url_fskip(pb, 13); + + switch (compression_type) { + case 0: + switch (ea->bytes) { + case 1: ea->audio_codec = CODEC_ID_PCM_S8; break; + case 2: ea->audio_codec = CODEC_ID_PCM_S16LE; break; + } + break; + case 1: ea->audio_codec = CODEC_ID_PCM_MULAW; ea->bytes = 1; break; + case 2: ea->audio_codec = CODEC_ID_ADPCM_IMA_EA_EACS; break; + default: + av_log (s, AV_LOG_ERROR, "unsupported stream type; audio compression_type=%i\n", compression_type); + } + + return 1; +} + +/* + * Process SEAD sound header + * return 1 if success, 0 if invalid format, otherwise AVERROR_xxx + */ +static int process_audio_header_sead(AVFormatContext *s) { - if (p->buf_size < 4) - return 0; + EaDemuxContext *ea = s->priv_data; + ByteIOContext *pb = s->pb; - if (AV_RL32(&p->buf[0]) != SCHl_TAG) - return 0; + ea->sample_rate = get_le32(pb); + ea->bytes = get_le32(pb); /* 1=8-bit, 2=16-bit */ + ea->num_channels = get_le32(pb); + ea->audio_codec = CODEC_ID_ADPCM_IMA_EA_SEAD; + + return 1; +} + +static int process_video_header_vp6(AVFormatContext *s) +{ + EaDemuxContext *ea = s->priv_data; + ByteIOContext *pb = s->pb; - return AVPROBE_SCORE_MAX; + url_fskip(pb, 16); + ea->time_base.den = get_le32(pb); + ea->time_base.num = get_le32(pb); + ea->video_codec = CODEC_ID_VP6; + + return 1; +} + +/* + * Process EA file header + * Returns 1 if the EA file is valid and successfully opened, 0 otherwise + */ +static int process_ea_header(AVFormatContext *s) { + uint32_t blockid, size = 0; + EaDemuxContext *ea = s->priv_data; + ByteIOContext *pb = s->pb; + int i; + + for (i=0; i<5 && (!ea->audio_codec || !ea->video_codec); i++) { + unsigned int startpos = url_ftell(pb); + int err = 0; + + blockid = get_le32(pb); + size = get_le32(pb); + if (i == 0) + ea->big_endian = size > 0x000FFFFF; + if (ea->big_endian) + size = bswap_32(size); + + switch (blockid) { + case ISNh_TAG: + if (get_le32(pb) != EACS_TAG) { + av_log (s, AV_LOG_ERROR, "unknown 1SNh headerid\n"); + return 0; + } + err = process_audio_header_eacs(s); + break; + + case SCHl_TAG : + blockid = get_le32(pb); + if (blockid == GSTR_TAG) { + url_fskip(pb, 4); + } else if (blockid != PT00_TAG) { + av_log (s, AV_LOG_ERROR, "unknown SCHl headerid\n"); + return 0; + } + err = process_audio_header_elements(s); + break; + + case SEAD_TAG: + err = process_audio_header_sead(s); + break; + + case MVhd_TAG : + err = process_video_header_vp6(s); + break; + } + + if (err < 0) { + av_log(s, AV_LOG_ERROR, "error parsing header: %i\n", err); + return err; + } + + url_fseek(pb, startpos + size, SEEK_SET); + } + + url_fseek(pb, 0, SEEK_SET); + + return 1; +} + + +static int ea_probe(AVProbeData *p) +{ + switch (AV_RL32(&p->buf[0])) { + case ISNh_TAG: + case SCHl_TAG: + case SEAD_TAG: + case kVGT_TAG: + case MADk_TAG: + case MPCh_TAG: + case MVhd_TAG: + case MVIh_TAG: + return AVPROBE_SCORE_MAX; + } + return 0; } static int ea_read_header(AVFormatContext *s, AVFormatParameters *ap) { - EaDemuxContext *ea = (EaDemuxContext *)s->priv_data; + EaDemuxContext *ea = s->priv_data; AVStream *st; if (!process_ea_header(s)) - return AVERROR_IO; - -#if 0 - /* initialize the video decoder stream */ - st = av_new_stream(s, 0); - if (!st) - return AVERROR_NOMEM; - av_set_pts_info(st, 33, 1, 90000); - ea->video_stream_index = st->index; - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = CODEC_ID_EA_MJPEG; - st->codec->codec_tag = 0; /* no fourcc */ -#endif - - /* initialize the audio decoder stream */ - st = av_new_stream(s, 0); - if (!st) - return AVERROR_NOMEM; - av_set_pts_info(st, 33, 1, EA_SAMPLE_RATE); - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = CODEC_ID_ADPCM_EA; - st->codec->codec_tag = 0; /* no tag */ - st->codec->channels = ea->num_channels; - st->codec->sample_rate = EA_SAMPLE_RATE; - st->codec->bits_per_sample = EA_BITS_PER_SAMPLE; - st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * - st->codec->bits_per_sample / 4; - st->codec->block_align = st->codec->channels * st->codec->bits_per_sample; - - ea->audio_stream_index = st->index; - ea->audio_frame_counter = 0; + return AVERROR(EIO); + + if (ea->video_codec) { + /* initialize the video decoder stream */ + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + ea->video_stream_index = st->index; + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = ea->video_codec; + st->codec->codec_tag = 0; /* no fourcc */ + st->codec->time_base = ea->time_base; + } + + if (ea->audio_codec) { + /* initialize the audio decoder stream */ + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + av_set_pts_info(st, 33, 1, ea->sample_rate); + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = ea->audio_codec; + st->codec->codec_tag = 0; /* no tag */ + st->codec->channels = ea->num_channels; + st->codec->sample_rate = ea->sample_rate; + st->codec->bits_per_sample = ea->bytes * 8; + st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * + st->codec->bits_per_sample / 4; + st->codec->block_align = st->codec->channels*st->codec->bits_per_sample; + ea->audio_stream_index = st->index; + ea->audio_frame_counter = 0; + } return 1; } @@ -220,43 +381,76 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt) { EaDemuxContext *ea = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int ret = 0; int packet_read = 0; - unsigned char preamble[EA_PREAMBLE_SIZE]; unsigned int chunk_type, chunk_size; + int key = 0; while (!packet_read) { - - if (get_buffer(pb, preamble, EA_PREAMBLE_SIZE) != EA_PREAMBLE_SIZE) - return AVERROR_IO; - chunk_type = AV_RL32(&preamble[0]); - chunk_size = AV_RL32(&preamble[4]) - EA_PREAMBLE_SIZE; + chunk_type = get_le32(pb); + chunk_size = (ea->big_endian ? get_be32(pb) : get_le32(pb)) - 8; switch (chunk_type) { /* audio data */ + case ISNh_TAG: + /* header chunk also contains data; skip over the header portion*/ + url_fskip(pb, 32); + chunk_size -= 32; + case ISNd_TAG: case SCDl_TAG: + case SNDC_TAG: + if (!ea->audio_codec) { + url_fskip(pb, chunk_size); + break; + } else if (ea->audio_codec == CODEC_ID_PCM_S16LE_PLANAR) { + url_fskip(pb, 12); /* planar header */ + chunk_size -= 12; + } ret = av_get_packet(pb, pkt, chunk_size); if (ret != chunk_size) - ret = AVERROR_IO; + ret = AVERROR(EIO); else { pkt->stream_index = ea->audio_stream_index; pkt->pts = 90000; pkt->pts *= ea->audio_frame_counter; - pkt->pts /= EA_SAMPLE_RATE; + pkt->pts /= ea->sample_rate; + switch (ea->audio_codec) { + case CODEC_ID_ADPCM_EA: /* 2 samples/byte, 1 or 2 samples per frame depending * on stereo; chunk also has 12-byte header */ ea->audio_frame_counter += ((chunk_size - 12) * 2) / ea->num_channels; + break; + default: + ea->audio_frame_counter += chunk_size / + (ea->bytes * ea->num_channels); + } } packet_read = 1; break; /* ending tag */ + case 0: + case ISNe_TAG: case SCEl_TAG: - ret = AVERROR_IO; + case SEND_TAG: + ret = AVERROR(EIO); + packet_read = 1; + break; + + case MV0K_TAG: + key = PKT_FLAG_KEY; + case MV0F_TAG: + ret = av_get_packet(pb, pkt, chunk_size); + if (ret != chunk_size) + ret = AVERROR_IO; + else { + pkt->stream_index = ea->video_stream_index; + pkt->flags |= key; + } packet_read = 1; break; @@ -264,22 +458,11 @@ static int ea_read_packet(AVFormatContext *s, url_fseek(pb, chunk_size, SEEK_CUR); break; } - - /* ending packet */ - if (chunk_type == SCEl_TAG) { - } } return ret; } -static int ea_read_close(AVFormatContext *s) -{ -// EaDemuxContext *ea = (EaDemuxContext *)s->priv_data; - - return 0; -} - AVInputFormat ea_demuxer = { "ea", "Electronic Arts Multimedia Format", @@ -287,5 +470,4 @@ AVInputFormat ea_demuxer = { ea_probe, ea_read_header, ea_read_packet, - ea_read_close, }; diff --git a/contrib/ffmpeg/libavformat/ffm.c b/contrib/ffmpeg/libavformat/ffm.c index a2970ae42..872e6f0ba 100644 --- a/contrib/ffmpeg/libavformat/ffm.c +++ b/contrib/ffmpeg/libavformat/ffm.c @@ -64,7 +64,7 @@ static void flush_packet(AVFormatContext *s) { FFMContext *ffm = s->priv_data; int fill_size, h; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; fill_size = ffm->packet_end - ffm->packet_ptr; memset(ffm->packet_ptr, 0, fill_size); @@ -128,7 +128,7 @@ static int ffm_write_header(AVFormatContext *s) FFMContext *ffm = s->priv_data; AVStream *st; FFMStream *fst; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *codec; int bit_rate, i; @@ -278,7 +278,7 @@ static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt) static int ffm_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; FFMContext *ffm = s->priv_data; /* flush packets */ @@ -314,7 +314,7 @@ static int ffm_is_avail_data(AVFormatContext *s, int size) if (size <= len) return 1; } - pos = url_ftell(&s->pb); + pos = url_ftell(s->pb); if (pos == ffm->write_index) { /* exactly at the end of stream */ return 0; @@ -335,7 +335,7 @@ static int ffm_read_data(AVFormatContext *s, uint8_t *buf, int size, int first) { FFMContext *ffm = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int len, fill_size, size1, frame_offset; size1 = size; @@ -393,7 +393,7 @@ static int ffm_read_data(AVFormatContext *s, static void adjust_write_index(AVFormatContext *s) { FFMContext *ffm = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int64_t pts; //offset_t orig_write_index = ffm->write_index; offset_t pos_min, pos_max; @@ -452,7 +452,7 @@ static int ffm_read_header(AVFormatContext *s, AVFormatParameters *ap) FFMContext *ffm = s->priv_data; AVStream *st; FFMStream *fst; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *codec; int i, nb_streams; uint32_t tag; @@ -585,7 +585,7 @@ static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) } #if 0 printf("pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n", - url_ftell(&s->pb), s->pb.pos, ffm->write_index, ffm->file_size); + url_ftell(s->pb), s->pb.pos, ffm->write_index, ffm->file_size); #endif if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != FRAME_HEADER_SIZE) @@ -601,16 +601,16 @@ static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) ffm->read_state = READ_DATA; /* fall thru */ case READ_DATA: - size = (ffm->header[2] << 16) | (ffm->header[3] << 8) | ffm->header[4]; + size = AV_RB24(ffm->header + 2); if (!ffm_is_avail_data(s, size)) { return AVERROR(EAGAIN); } - duration = (ffm->header[5] << 16) | (ffm->header[6] << 8) | ffm->header[7]; + duration = AV_RB24(ffm->header + 5); av_new_packet(pkt, size); pkt->stream_index = ffm->header[0]; - pkt->pos = url_ftell(&s->pb); + pkt->pos = url_ftell(s->pb); if (ffm->header[1] & FLAG_KEY_FRAME) pkt->flags |= PKT_FLAG_KEY; @@ -638,7 +638,7 @@ static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) static void ffm_seek1(AVFormatContext *s, offset_t pos1) { FFMContext *ffm = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; offset_t pos; pos = pos1 + ffm->write_index; @@ -652,7 +652,7 @@ static void ffm_seek1(AVFormatContext *s, offset_t pos1) static int64_t get_pts(AVFormatContext *s, offset_t pos) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int64_t pts; ffm_seek1(s, pos); @@ -665,7 +665,7 @@ static int64_t get_pts(AVFormatContext *s, offset_t pos) } /* seek to a given time in the file. The file read pointer is - positionned at or before pts. XXX: the following code is quite + positioned at or before pts. XXX: the following code is quite approximative */ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags) { @@ -714,15 +714,10 @@ static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, in offset_t ffm_read_write_index(int fd) { uint8_t buf[8]; - offset_t pos; - int i; lseek(fd, 8, SEEK_SET); read(fd, buf, 8); - pos = 0; - for(i=0;i<8;i++) - pos |= (int64_t)buf[i] << (56 - i * 8); - return pos; + return AV_RB64(buf); } void ffm_write_write_index(int fd, offset_t pos) @@ -758,7 +753,7 @@ static int ffm_read_close(AVFormatContext *s) static int ffm_probe(AVProbeData *p) { - if (p->buf_size >= 4 && + if ( p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && p->buf[3] == '1') return AVPROBE_SCORE_MAX + 1; diff --git a/contrib/ffmpeg/libavformat/file.c b/contrib/ffmpeg/libavformat/file.c index 3caf80a61..6285c1bba 100644 --- a/contrib/ffmpeg/libavformat/file.c +++ b/contrib/ffmpeg/libavformat/file.c @@ -19,9 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" +#include "avstring.h" #include <fcntl.h> #include <unistd.h> #include <sys/time.h> +#include <stdlib.h> +#include "os_support.h" /* standard file protocol */ @@ -31,7 +34,7 @@ static int file_open(URLContext *h, const char *filename, int flags) int access; int fd; - strstart(filename, "file:", &filename); + av_strstart(filename, "file:", &filename); if (flags & URL_RDWR) { access = O_CREAT | O_TRUNC | O_RDWR; @@ -40,7 +43,7 @@ static int file_open(URLContext *h, const char *filename, int flags) } else { access = O_RDONLY; } -#if defined(__MINGW32__) || defined(CONFIG_OS2) || defined(__CYGWIN__) +#ifdef O_BINARY access |= O_BINARY; #endif fd = open(filename, access, 0666); @@ -89,13 +92,18 @@ URLProtocol file_protocol = { static int pipe_open(URLContext *h, const char *filename, int flags) { int fd; - - if (flags & URL_WRONLY) { - fd = 1; - } else { - fd = 0; + const char * final; + av_strstart(filename, "pipe:", &filename); + + fd = strtol(filename, &final, 10); + if((filename == final) || *final ) {/* No digits found, or something like 10ab */ + if (flags & URL_WRONLY) { + fd = 1; + } else { + fd = 0; + } } -#if defined(__MINGW32__) || defined(CONFIG_OS2) || defined(__CYGWIN__) +#ifdef O_BINARY setmode(fd, O_BINARY); #endif h->priv_data = (void *)(size_t)fd; @@ -103,28 +111,9 @@ static int pipe_open(URLContext *h, const char *filename, int flags) return 0; } -static int pipe_read(URLContext *h, unsigned char *buf, int size) -{ - int fd = (size_t)h->priv_data; - return read(fd, buf, size); -} - -static int pipe_write(URLContext *h, unsigned char *buf, int size) -{ - int fd = (size_t)h->priv_data; - return write(fd, buf, size); -} - -static int pipe_close(URLContext *h) -{ - return 0; -} - URLProtocol pipe_protocol = { "pipe", pipe_open, - pipe_read, - pipe_write, - NULL, - pipe_close, + file_read, + file_write, }; diff --git a/contrib/ffmpeg/libavformat/flic.c b/contrib/ffmpeg/libavformat/flic.c index 0c3a7f01f..b422fb09a 100644 --- a/contrib/ffmpeg/libavformat/flic.c +++ b/contrib/ffmpeg/libavformat/flic.c @@ -39,25 +39,21 @@ originated in Dave's Targa Animator (DTA) */ #define FLIC_CHUNK_MAGIC_1 0xF1FA #define FLIC_CHUNK_MAGIC_2 0xF5FA -#define FLIC_MC_PTS_INC 6000 /* pts increment for Magic Carpet game FLIs */ -#define FLIC_DEFAULT_PTS_INC 6000 /* for FLIs that have 0 speed */ +#define FLIC_MC_SPEED 5 /* speed for Magic Carpet game FLIs */ +#define FLIC_DEFAULT_SPEED 5 /* for FLIs that have 0 speed */ #define FLIC_HEADER_SIZE 128 #define FLIC_PREAMBLE_SIZE 6 typedef struct FlicDemuxContext { - int frame_pts_inc; - int64_t pts; int video_stream_index; + int frame_number; } FlicDemuxContext; static int flic_probe(AVProbeData *p) { int magic_number; - if (p->buf_size < 6) - return 0; - magic_number = AV_RL16(&p->buf[4]); if ((magic_number != FLIC_FILE_MAGIC_1) && (magic_number != FLIC_FILE_MAGIC_2) && @@ -70,26 +66,28 @@ static int flic_probe(AVProbeData *p) static int flic_read_header(AVFormatContext *s, AVFormatParameters *ap) { - FlicDemuxContext *flic = (FlicDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + FlicDemuxContext *flic = s->priv_data; + ByteIOContext *pb = s->pb; unsigned char header[FLIC_HEADER_SIZE]; AVStream *st; int speed; int magic_number; - flic->pts = 0; + flic->frame_number = 0; /* load the whole header and pull out the width and height */ if (get_buffer(pb, header, FLIC_HEADER_SIZE) != FLIC_HEADER_SIZE) - return AVERROR_IO; + return AVERROR(EIO); magic_number = AV_RL16(&header[4]); speed = AV_RL32(&header[0x10]); + if (speed == 0) + speed = FLIC_DEFAULT_SPEED; /* initialize the decoder streams */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); flic->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_FLIC; @@ -97,22 +95,26 @@ static int flic_read_header(AVFormatContext *s, st->codec->width = AV_RL16(&header[0x08]); st->codec->height = AV_RL16(&header[0x0A]); - if (!st->codec->width || !st->codec->height) - return AVERROR_INVALIDDATA; + if (!st->codec->width || !st->codec->height) { + /* Ugly hack needed for the following sample: */ + /* 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; + st->codec->height = 480; + } /* send over the whole 128-byte FLIC header */ st->codec->extradata_size = FLIC_HEADER_SIZE; st->codec->extradata = av_malloc(FLIC_HEADER_SIZE); memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE); - av_set_pts_info(st, 33, 1, 90000); - /* Time to figure out the framerate: If there is a FLIC chunk magic * number at offset 0x10, assume this is from the Bullfrog game, * Magic Carpet. */ if (AV_RL16(&header[0x10]) == FLIC_CHUNK_MAGIC_1) { - flic->frame_pts_inc = FLIC_MC_PTS_INC; + av_set_pts_info(st, 64, FLIC_MC_SPEED, 70); /* rewind the stream since the first chunk is at offset 12 */ url_fseek(pb, 12, SEEK_SET); @@ -124,44 +126,23 @@ static int flic_read_header(AVFormatContext *s, memcpy(st->codec->extradata, header, 12); } else if (magic_number == FLIC_FILE_MAGIC_1) { - /* - * in this case, the speed (n) is number of 1/70s ticks between frames: - * - * pts n * frame # - * -------- = ----------- => pts = n * (90000/70) * frame # - * 90000 70 - * - * therefore, the frame pts increment = n * 1285.7 - */ - flic->frame_pts_inc = speed * 1285.7; + av_set_pts_info(st, 64, speed, 70); } else if ((magic_number == FLIC_FILE_MAGIC_2) || (magic_number == FLIC_FILE_MAGIC_3)) { - /* - * in this case, the speed (n) is number of milliseconds between frames: - * - * pts n * frame # - * -------- = ----------- => pts = n * 90 * frame # - * 90000 1000 - * - * therefore, the frame pts increment = n * 90 - */ - flic->frame_pts_inc = speed * 90; + av_set_pts_info(st, 64, speed, 1000); } else { av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n"); return AVERROR_INVALIDDATA; } - if (flic->frame_pts_inc == 0) - flic->frame_pts_inc = FLIC_DEFAULT_PTS_INC; - return 0; } static int flic_read_packet(AVFormatContext *s, AVPacket *pkt) { - FlicDemuxContext *flic = (FlicDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + FlicDemuxContext *flic = s->priv_data; + ByteIOContext *pb = s->pb; int packet_read = 0; unsigned int size; int magic; @@ -172,7 +153,7 @@ static int flic_read_packet(AVFormatContext *s, if ((ret = get_buffer(pb, preamble, FLIC_PREAMBLE_SIZE)) != FLIC_PREAMBLE_SIZE) { - ret = AVERROR_IO; + ret = AVERROR(EIO); break; } @@ -181,20 +162,19 @@ static int flic_read_packet(AVFormatContext *s, if (((magic == FLIC_CHUNK_MAGIC_1) || (magic == FLIC_CHUNK_MAGIC_2)) && size > FLIC_PREAMBLE_SIZE) { if (av_new_packet(pkt, size)) { - ret = AVERROR_IO; + ret = AVERROR(EIO); break; } pkt->stream_index = flic->video_stream_index; - pkt->pts = flic->pts; + pkt->pts = flic->frame_number++; pkt->pos = url_ftell(pb); memcpy(pkt->data, preamble, FLIC_PREAMBLE_SIZE); ret = get_buffer(pb, pkt->data + FLIC_PREAMBLE_SIZE, size - FLIC_PREAMBLE_SIZE); if (ret != size - FLIC_PREAMBLE_SIZE) { av_free_packet(pkt); - ret = AVERROR_IO; + ret = AVERROR(EIO); } - flic->pts += flic->frame_pts_inc; packet_read = 1; } else { /* not interested in this chunk */ @@ -207,7 +187,7 @@ static int flic_read_packet(AVFormatContext *s, static int flic_read_close(AVFormatContext *s) { -// FlicDemuxContext *flic = (FlicDemuxContext *)s->priv_data; +// FlicDemuxContext *flic = s->priv_data; return 0; } diff --git a/contrib/ffmpeg/libavformat/flv.h b/contrib/ffmpeg/libavformat/flv.h index 1484ac15d..4501527aa 100644 --- a/contrib/ffmpeg/libavformat/flv.h +++ b/contrib/ffmpeg/libavformat/flv.h @@ -21,8 +21,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef FLV_H -#define FLV_H +#ifndef FFMPEG_FLV_H +#define FFMPEG_FLV_H /* offsets for packed values */ #define FLV_AUDIO_SAMPLESSIZE_OFFSET 1 @@ -71,7 +71,7 @@ enum { }; enum { - FLV_CODECID_PCM_BE = 0, + FLV_CODECID_PCM = 0, FLV_CODECID_ADPCM = 1 << FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_MP3 = 2 << FLV_AUDIO_CODECID_OFFSET, FLV_CODECID_PCM_LE = 3 << FLV_AUDIO_CODECID_OFFSET, @@ -107,4 +107,4 @@ typedef enum { AMF_DATA_TYPE_UNSUPPORTED = 0x0d, } AMFDataType; -#endif /* FLV_H */ +#endif /* FFMPEG_FLV_H */ diff --git a/contrib/ffmpeg/libavformat/flvdec.c b/contrib/ffmpeg/libavformat/flvdec.c index bf91fbbc7..f21f35296 100644 --- a/contrib/ffmpeg/libavformat/flvdec.c +++ b/contrib/ffmpeg/libavformat/flvdec.c @@ -2,6 +2,11 @@ * FLV demuxer * 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 FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -17,12 +22,6 @@ * 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 - * - * - * 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 */ #include "avformat.h" #include "flv.h" @@ -31,8 +30,6 @@ static int flv_probe(AVProbeData *p) { const uint8_t *d; - if (p->buf_size < 6) - return 0; d = p->buf; if (d[0] == 'F' && d[1] == 'L' && d[2] == 'V' && d[3] < 5 && d[5]==0) { return AVPROBE_SCORE_MAX; @@ -44,15 +41,23 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream, int flv_c AVCodecContext *acodec = astream->codec; switch(flv_codecid) { //no distinction between S16 and S8 PCM codec flags - case FLV_CODECID_PCM_BE: - acodec->codec_id = acodec->bits_per_sample == 8 ? CODEC_ID_PCM_S8 : CODEC_ID_PCM_S16BE; break; + case FLV_CODECID_PCM: + acodec->codec_id = acodec->bits_per_sample == 8 ? CODEC_ID_PCM_S8 : +#ifdef WORDS_BIGENDIAN + CODEC_ID_PCM_S16BE; +#else + CODEC_ID_PCM_S16LE; +#endif + break; case FLV_CODECID_PCM_LE: acodec->codec_id = acodec->bits_per_sample == 8 ? CODEC_ID_PCM_S8 : CODEC_ID_PCM_S16LE; break; case FLV_CODECID_ADPCM: acodec->codec_id = CODEC_ID_ADPCM_SWF; break; - case FLV_CODECID_MP3 : acodec->codec_id = CODEC_ID_MP3 ; astream->need_parsing = 1 ; break; + case FLV_CODECID_MP3 : acodec->codec_id = CODEC_ID_MP3 ; astream->need_parsing = AVSTREAM_PARSE_FULL; break; case FLV_CODECID_NELLYMOSER_8HZ_MONO: acodec->sample_rate = 8000; //in case metadata does not otherwise declare samplerate case FLV_CODECID_NELLYMOSER: + acodec->codec_id = CODEC_ID_NELLYMOSER; + break; default: av_log(s, AV_LOG_INFO, "Unsupported audio codec (%x)\n", flv_codecid >> FLV_AUDIO_CODECID_OFFSET); acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET; @@ -65,11 +70,14 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, int flv_co case FLV_CODECID_H263 : vcodec->codec_id = CODEC_ID_FLV1 ; break; case FLV_CODECID_SCREEN: vcodec->codec_id = CODEC_ID_FLASHSV; break; case FLV_CODECID_VP6 : vcodec->codec_id = CODEC_ID_VP6F ; + case FLV_CODECID_VP6A : + if(flv_codecid == FLV_CODECID_VP6A) + vcodec->codec_id = CODEC_ID_VP6A; if(vcodec->extradata_size != 1) { vcodec->extradata_size = 1; vcodec->extradata = av_malloc(1); } - vcodec->extradata[0] = get_byte(&s->pb); + vcodec->extradata[0] = get_byte(s->pb); return 1; // 1 byte body size adjustment for flv_read_packet() default: av_log(s, AV_LOG_INFO, "Unsupported video codec (%x)\n", flv_codecid); @@ -101,7 +109,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst double num_val; num_val = 0; - ioc = &s->pb; + ioc = s->pb; amf_type = get_byte(ioc); @@ -177,12 +185,14 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vst } else if(!strcmp(key, "audiosamplerate") && acodec && num_val >= 0) { //some tools, like FLVTool2, write consistently approximate metadata sample rates - switch((int)num_val) { - case 44000: acodec->sample_rate = 44100 ; break; - case 22000: acodec->sample_rate = 22050 ; break; - case 11000: acodec->sample_rate = 11025 ; break; - case 5000 : acodec->sample_rate = 5512 ; break; - default : acodec->sample_rate = num_val; + if (!acodec->sample_rate) { + switch((int)num_val) { + case 44000: acodec->sample_rate = 44100 ; break; + case 22000: acodec->sample_rate = 22050 ; break; + case 11000: acodec->sample_rate = 11025 ; break; + case 5000 : acodec->sample_rate = 5512 ; break; + default : acodec->sample_rate = num_val; + } } } } @@ -201,7 +211,7 @@ static int flv_read_metabody(AVFormatContext *s, unsigned int next_pos) { astream = NULL; vstream = NULL; keylen = 0; - ioc = &s->pb; + ioc = s->pb; //first object needs to be "onMetaData" string type = get_byte(ioc); @@ -222,14 +232,22 @@ static int flv_read_metabody(AVFormatContext *s, unsigned int next_pos) { return 0; } +static AVStream *create_stream(AVFormatContext *s, int is_audio){ + AVStream *st = av_new_stream(s, is_audio); + if (!st) + return NULL; + st->codec->codec_type = is_audio ? CODEC_TYPE_AUDIO : CODEC_TYPE_VIDEO; + av_set_pts_info(st, 24, 1, 1000); /* 24 bit pts in ms */ + return st; +} + static int flv_read_header(AVFormatContext *s, AVFormatParameters *ap) { int offset, flags; - AVStream *st; - url_fskip(&s->pb, 4); - flags = get_byte(&s->pb); + url_fskip(s->pb, 4); + flags = get_byte(s->pb); /* old flvtool cleared this field */ /* FIXME: better fix needed */ if (!flags) { @@ -238,22 +256,16 @@ static int flv_read_header(AVFormatContext *s, } if(flags & FLV_HEADER_FLAG_HASVIDEO){ - st = av_new_stream(s, 0); - if (!st) - return AVERROR_NOMEM; - st->codec->codec_type = CODEC_TYPE_VIDEO; - av_set_pts_info(st, 24, 1, 1000); /* 24 bit pts in ms */ + if(!create_stream(s, 0)) + return AVERROR(ENOMEM); } if(flags & FLV_HEADER_FLAG_HASAUDIO){ - st = av_new_stream(s, 1); - if (!st) - return AVERROR_NOMEM; - st->codec->codec_type = CODEC_TYPE_AUDIO; - av_set_pts_info(st, 24, 1, 1000); /* 24 bit pts in ms */ + if(!create_stream(s, 1)) + return AVERROR(ENOMEM); } - offset = get_be32(&s->pb); - url_fseek(&s->pb, offset, SEEK_SET); + offset = get_be32(s->pb); + url_fseek(s->pb, offset, SEEK_SET); s->start_time = 0; @@ -266,34 +278,35 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) AVStream *st = NULL; for(;;){ - pos = url_ftell(&s->pb); - url_fskip(&s->pb, 4); /* size of previous packet */ - type = get_byte(&s->pb); - size = get_be24(&s->pb); - pts = get_be24(&s->pb); + pos = url_ftell(s->pb); + url_fskip(s->pb, 4); /* size of previous packet */ + type = get_byte(s->pb); + size = get_be24(s->pb); + pts = get_be24(s->pb); + pts |= get_byte(s->pb) << 24; // av_log(s, AV_LOG_DEBUG, "type:%d, size:%d, pts:%d\n", type, size, pts); - if (url_feof(&s->pb)) - return AVERROR_IO; - url_fskip(&s->pb, 4); /* reserved */ + if (url_feof(s->pb)) + return AVERROR(EIO); + url_fskip(s->pb, 3); /* stream id, always 0 */ flags = 0; if(size == 0) continue; - next= size + url_ftell(&s->pb); + next= size + url_ftell(s->pb); if (type == FLV_TAG_TYPE_AUDIO) { is_audio=1; - flags = get_byte(&s->pb); + flags = get_byte(s->pb); } else if (type == FLV_TAG_TYPE_VIDEO) { is_audio=0; - flags = get_byte(&s->pb); + flags = get_byte(s->pb); } else { if (type == FLV_TAG_TYPE_META && size > 13+1+4) flv_read_metabody(s, next); else /* skip packet */ av_log(s, AV_LOG_ERROR, "skipping flv packet: type %d, size %d, flags %d\n", type, size, flags); - url_fseek(&s->pb, next, SEEK_SET); + url_fseek(s->pb, next, SEEK_SET); continue; } @@ -305,15 +318,14 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) } if(i == s->nb_streams){ av_log(NULL, AV_LOG_ERROR, "invalid stream\n"); - url_fseek(&s->pb, next, SEEK_SET); - continue; + st= create_stream(s, is_audio); } // av_log(NULL, AV_LOG_DEBUG, "%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)) || st->discard >= AVDISCARD_ALL ){ - url_fseek(&s->pb, next, SEEK_SET); + url_fseek(s->pb, next, SEEK_SET); continue; } if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) @@ -322,17 +334,17 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) } // if not streamed and no duration from metadata then seek to end to find the duration from the timestamps - if(!url_is_streamed(&s->pb) && s->duration==AV_NOPTS_VALUE){ + if(!url_is_streamed(s->pb) && s->duration==AV_NOPTS_VALUE){ int size; - const int pos= url_ftell(&s->pb); - const int fsize= url_fsize(&s->pb); - url_fseek(&s->pb, fsize-4, SEEK_SET); - size= get_be32(&s->pb); - url_fseek(&s->pb, fsize-3-size, SEEK_SET); - if(size == get_be24(&s->pb) + 11){ - s->duration= get_be24(&s->pb) * (int64_t)AV_TIME_BASE / 1000; + const int pos= url_ftell(s->pb); + const int fsize= url_fsize(s->pb); + url_fseek(s->pb, fsize-4, SEEK_SET); + size= get_be32(s->pb); + url_fseek(s->pb, fsize-3-size, SEEK_SET); + if(size == get_be24(s->pb) + 11){ + s->duration= get_be24(s->pb) * (int64_t)AV_TIME_BASE / 1000; } - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); } if(is_audio){ @@ -349,9 +361,9 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) size -= flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK); } - ret= av_get_packet(&s->pb, pkt, size - 1); + ret= av_get_packet(s->pb, pkt, size - 1); if (ret <= 0) { - return AVERROR_IO; + return AVERROR(EIO); } /* note: we need to modify the packet size here to handle the last packet */ @@ -376,7 +388,7 @@ static int flv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp int index = av_index_search_timestamp(st, timestamp, flags); if (index < 0) return -1; - url_fseek(&s->pb, st->index_entries[index].pos, SEEK_SET); + url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); return 0; } diff --git a/contrib/ffmpeg/libavformat/flvenc.c b/contrib/ffmpeg/libavformat/flvenc.c index ece585d77..e5270ca32 100644 --- a/contrib/ffmpeg/libavformat/flvenc.c +++ b/contrib/ffmpeg/libavformat/flvenc.c @@ -35,8 +35,8 @@ static const AVCodecTag flv_video_codec_ids[] = { static const AVCodecTag flv_audio_codec_ids[] = { {CODEC_ID_MP3, FLV_CODECID_MP3 >> FLV_AUDIO_CODECID_OFFSET}, - {CODEC_ID_PCM_S8, FLV_CODECID_PCM_BE >> FLV_AUDIO_CODECID_OFFSET}, - {CODEC_ID_PCM_S16BE, FLV_CODECID_PCM_BE >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_PCM_S8, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET}, + {CODEC_ID_PCM_S16BE, FLV_CODECID_PCM >> FLV_AUDIO_CODECID_OFFSET}, {CODEC_ID_PCM_S16LE, FLV_CODECID_PCM_LE >> FLV_AUDIO_CODECID_OFFSET}, {CODEC_ID_ADPCM_SWF, FLV_CODECID_ADPCM >> FLV_AUDIO_CODECID_OFFSET}, {CODEC_ID_NONE, 0} @@ -66,10 +66,12 @@ static int get_audio_flags(AVCodecContext *enc){ break; case 8000: //nellymoser only case 5512: //not mp3 - flags |= FLV_SAMPLERATE_SPECIAL; - break; + if(enc->codec_id != CODEC_ID_MP3){ + flags |= FLV_SAMPLERATE_SPECIAL; + break; + } default: - av_log(enc, AV_LOG_ERROR, "flv doesnt support that sample rate, choose from (44100, 22050, 11025)\n"); + av_log(enc, AV_LOG_ERROR, "flv does not support that sample rate, choose from (44100, 22050, 11025).\n"); return -1; } @@ -82,10 +84,10 @@ static int get_audio_flags(AVCodecContext *enc){ flags |= FLV_CODECID_MP3 | FLV_SAMPLESSIZE_16BIT; break; case CODEC_ID_PCM_S8: - flags |= FLV_CODECID_PCM_BE | FLV_SAMPLESSIZE_8BIT; + flags |= FLV_CODECID_PCM | FLV_SAMPLESSIZE_8BIT; break; case CODEC_ID_PCM_S16BE: - flags |= FLV_CODECID_PCM_BE | FLV_SAMPLESSIZE_16BIT; + flags |= FLV_CODECID_PCM | FLV_SAMPLESSIZE_16BIT; break; case CODEC_ID_PCM_S16LE: flags |= FLV_CODECID_PCM_LE | FLV_SAMPLESSIZE_16BIT; @@ -124,7 +126,7 @@ static void put_amf_bool(ByteIOContext *pb, int b) { static int flv_write_header(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; FLVContext *flv = s->priv_data; int i, width, height, samplerate, samplesize, channels, audiocodecid, videocodecid; double framerate = 0.0; @@ -254,7 +256,7 @@ static int flv_write_trailer(AVFormatContext *s) { int64_t file_size; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; FLVContext *flv = s->priv_data; file_size = url_ftell(pb); @@ -271,14 +273,19 @@ static int flv_write_trailer(AVFormatContext *s) static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[pkt->stream_index]->codec; FLVContext *flv = s->priv_data; int size= pkt->size; - int flags; + int flags, flags_size; // av_log(s, AV_LOG_DEBUG, "type:%d pts: %"PRId64" size:%d\n", enc->codec_type, timestamp, size); + if(enc->codec_id == CODEC_ID_VP6 || enc->codec_id == CODEC_ID_VP6F) + flags_size= 2; + else + flags_size= 1; + if (enc->codec_type == CODEC_TYPE_VIDEO) { put_byte(pb, FLV_TAG_TYPE_VIDEO); @@ -298,19 +305,17 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) put_byte(pb, FLV_TAG_TYPE_AUDIO); } - if ((enc->codec_id == CODEC_ID_VP6) || (enc->codec_id == CODEC_ID_VP6F)) - put_be24(pb,size+2); // include the extra byte needed for VP6 in flv and flags - else - put_be24(pb,size+1); // include flags + put_be24(pb,size + flags_size); put_be24(pb,pkt->pts); - put_be32(pb,flv->reserved); + put_byte(pb,pkt->pts >> 24); + put_be24(pb,flv->reserved); put_byte(pb,flags); if (enc->codec_id == CODEC_ID_VP6) put_byte(pb,0); if (enc->codec_id == CODEC_ID_VP6F) put_byte(pb, enc->extradata_size ? enc->extradata[0] : 0); put_buffer(pb, pkt->data, size); - put_be32(pb,size+1+11); // previous tag size + put_be32(pb,size+flags_size+11); // previous tag size flv->duration = pkt->pts + pkt->duration; put_flush_packet(pb); @@ -326,7 +331,7 @@ AVOutputFormat flv_muxer = { #ifdef CONFIG_LIBMP3LAME CODEC_ID_MP3, #else // CONFIG_LIBMP3LAME - CODEC_ID_NONE, + CODEC_ID_ADPCM_SWF, #endif // CONFIG_LIBMP3LAME CODEC_ID_FLV1, flv_write_header, diff --git a/contrib/ffmpeg/libavformat/framecrcenc.c b/contrib/ffmpeg/libavformat/framecrcenc.c new file mode 100644 index 000000000..c0133017c --- /dev/null +++ b/contrib/ffmpeg/libavformat/framecrcenc.c @@ -0,0 +1,46 @@ +/* + * frame CRC encoder (for codec/format testing) + * Copyright (c) 2002 Fabrice Bellard. + * + * 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 "adler32.h" + +static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt) +{ + uint32_t crc = av_adler32_update(0, pkt->data, pkt->size); + char buf[256]; + + snprintf(buf, sizeof(buf), "%d, %"PRId64", %d, 0x%08x\n", pkt->stream_index, pkt->dts, pkt->size, crc); + put_buffer(s->pb, buf, strlen(buf)); + put_flush_packet(s->pb); + return 0; +} + +AVOutputFormat framecrc_muxer = { + "framecrc", + "framecrc testing format", + NULL, + "", + 0, + CODEC_ID_PCM_S16LE, + CODEC_ID_RAWVIDEO, + NULL, + framecrc_write_packet, + NULL, +}; diff --git a/contrib/ffmpeg/libavformat/framehook.c b/contrib/ffmpeg/libavformat/framehook.c index 8738f8030..eb5184f02 100644 --- a/contrib/ffmpeg/libavformat/framehook.c +++ b/contrib/ffmpeg/libavformat/framehook.c @@ -28,8 +28,8 @@ #endif -typedef struct _FrameHookEntry { - struct _FrameHookEntry *next; +typedef struct FrameHookEntry { + struct FrameHookEntry *next; FrameHookConfigureFn Configure; FrameHookProcessFn Process; FrameHookReleaseFn Release; diff --git a/contrib/ffmpeg/libavformat/framehook.h b/contrib/ffmpeg/libavformat/framehook.h index 06ed4f889..5568c138e 100644 --- a/contrib/ffmpeg/libavformat/framehook.h +++ b/contrib/ffmpeg/libavformat/framehook.h @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _FRAMEHOOK_H -#define _FRAMEHOOK_H +#ifndef FFMPEG_FRAMEHOOK_H +#define FFMPEG_FRAMEHOOK_H -#warning VHOOK is deprecated please help porting libmpcodecs or a better filter system to ffmpeg instead of wasting your time writing new fiters for this crappy one +#warning VHOOK is deprecated. Please help finishing libavfilter instead of wasting your time writing new filters for this crappy filter system. /* * Prototypes for interface to .so that implement a video processing hook @@ -49,4 +49,4 @@ extern int frame_hook_add(int argc, char *argv[]); extern void frame_hook_process(struct AVPicture *pict, enum PixelFormat pix_fmt, int width, int height, int64_t pts); extern void frame_hook_release(void); -#endif +#endif /* FFMPEG_FRAMEHOOK_H */ diff --git a/contrib/ffmpeg/libavformat/gif.c b/contrib/ffmpeg/libavformat/gif.c index 1083710d5..7b71faea9 100644 --- a/contrib/ffmpeg/libavformat/gif.c +++ b/contrib/ffmpeg/libavformat/gif.c @@ -137,7 +137,7 @@ static void gif_put_bits_rev(PutBitContext *s, int n, unsigned int value) //printf("bitbuf = %08x\n", bit_buf); s->buf_ptr+=4; if (s->buf_ptr >= s->buf_end) - puts("bit buffer overflow !!"); // should never happen ! who got rid of the callback ??? + abort(); // flush_buffer_rev(s); bit_cnt=bit_cnt + n - 32; if (bit_cnt == 0) { @@ -313,7 +313,7 @@ typedef struct { static int gif_write_header(AVFormatContext *s) { GIFContext *gif = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *enc, *video_enc; int i, width, height, loop_count /*, rate*/; @@ -343,19 +343,19 @@ static int gif_write_header(AVFormatContext *s) if (video_enc->pix_fmt != PIX_FMT_RGB24) { av_log(s, AV_LOG_ERROR, "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n"); - return AVERROR_IO; + return AVERROR(EIO); } gif_image_write_header(pb, width, height, loop_count, NULL); - put_flush_packet(&s->pb); + put_flush_packet(s->pb); return 0; } static int gif_write_video(AVFormatContext *s, AVCodecContext *enc, const uint8_t *buf, int size) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; GIFContext *gif = s->priv_data; int jiffies; int64_t delay; @@ -383,7 +383,7 @@ static int gif_write_video(AVFormatContext *s, gif_image_write_image(pb, 0, 0, enc->width, enc->height, buf, enc->width * 3, PIX_FMT_RGB24); - put_flush_packet(&s->pb); + put_flush_packet(s->pb); return 0; } @@ -398,10 +398,10 @@ static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) static int gif_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; put_byte(pb, 0x3b); - put_flush_packet(&s->pb); + put_flush_packet(s->pb); return 0; } diff --git a/contrib/ffmpeg/libavformat/gifdec.c b/contrib/ffmpeg/libavformat/gifdec.c index 1d31211f6..5803e5e5d 100644 --- a/contrib/ffmpeg/libavformat/gifdec.c +++ b/contrib/ffmpeg/libavformat/gifdec.c @@ -500,21 +500,21 @@ static int gif_parse_next_image(GifState *s) switch (code) { case ',': if (gif_read_image(s) < 0) - return AVERROR_IO; + return AVERROR(EIO); ret = 0; goto the_end; case ';': /* end of image */ - ret = AVERROR_IO; + ret = AVERROR(EIO); goto the_end; case '!': if (gif_read_extension(s) < 0) - return AVERROR_IO; + return AVERROR(EIO); break; case EOF: default: /* error or errneous EOF */ - ret = AVERROR_IO; + ret = AVERROR(EIO); goto the_end; } } @@ -526,7 +526,7 @@ static int gif_read_header(AVFormatContext * s1, AVFormatParameters * ap) { GifState *s = s1->priv_data; - ByteIOContext *f = &s1->pb; + ByteIOContext *f = s1->pb; AVStream *st; s->f = f; @@ -567,7 +567,7 @@ static int gif_read_packet(AVFormatContext * s1, /* XXX: avoid copying */ if (av_new_packet(pkt, s->screen_width * s->screen_height * 3)) { - return AVERROR_IO; + return AVERROR(EIO); } pkt->stream_index = 0; memcpy(pkt->data, s->image_buf, s->screen_width * s->screen_height * 3); diff --git a/contrib/ffmpeg/libavformat/grab.c b/contrib/ffmpeg/libavformat/grab.c deleted file mode 100644 index 5e778ecc0..000000000 --- a/contrib/ffmpeg/libavformat/grab.c +++ /dev/null @@ -1,860 +0,0 @@ -/* - * Linux video grab interface - * Copyright (c) 2000,2001 Fabrice Bellard. - * - * 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 <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#define _LINUX_TIME_H 1 -#include <linux/videodev.h> -#include <time.h> - -typedef struct { - int fd; - int frame_format; /* see VIDEO_PALETTE_xxx */ - int use_mmap; - int width, height; - int frame_rate; - int frame_rate_base; - int64_t time_frame; - int frame_size; - struct video_capability video_cap; - struct video_audio audio_saved; - uint8_t *video_buf; - struct video_mbuf gb_buffers; - struct video_mmap gb_buf; - int gb_frame; - - /* ATI All In Wonder specific stuff */ - /* XXX: remove and merge in libavcodec/imgconvert.c */ - int aiw_enabled; - int deint; - int halfw; - uint8_t *src_mem; - uint8_t *lum_m4_mem; -} VideoData; - -static int aiw_init(VideoData *s); -static int aiw_read_picture(VideoData *s, uint8_t *data); -static int aiw_close(VideoData *s); - -static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) -{ - VideoData *s = s1->priv_data; - AVStream *st; - int width, height; - int video_fd, frame_size; - int ret, frame_rate, frame_rate_base; - int desired_palette, desired_depth; - struct video_tuner tuner; - struct video_audio audio; - struct video_picture pict; - int j; - - if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) { - av_log(s1, AV_LOG_ERROR, "Bad capture size (%dx%d) or wrong time base (%d)\n", - ap->width, ap->height, ap->time_base.den); - - return -1; - } - - width = ap->width; - height = ap->height; - frame_rate = ap->time_base.den; - frame_rate_base = ap->time_base.num; - - if((unsigned)width > 32767 || (unsigned)height > 32767) { - av_log(s1, AV_LOG_ERROR, "Capture size is out of range: %dx%d\n", - width, height); - - return -1; - } - - st = av_new_stream(s1, 0); - if (!st) - return AVERROR(ENOMEM); - av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ - - s->width = width; - s->height = height; - s->frame_rate = frame_rate; - s->frame_rate_base = frame_rate_base; - - video_fd = open(s1->filename, O_RDWR); - if (video_fd < 0) { - perror(s1->filename); - goto fail; - } - - if (ioctl(video_fd,VIDIOCGCAP, &s->video_cap) < 0) { - perror("VIDIOCGCAP"); - goto fail; - } - - if (!(s->video_cap.type & VID_TYPE_CAPTURE)) { - av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not handle capture\n"); - goto fail; - } - - desired_palette = -1; - desired_depth = -1; - if (ap->pix_fmt == PIX_FMT_YUV420P) { - desired_palette = VIDEO_PALETTE_YUV420P; - desired_depth = 12; - } else if (ap->pix_fmt == PIX_FMT_YUYV422) { - desired_palette = VIDEO_PALETTE_YUV422; - desired_depth = 16; - } else if (ap->pix_fmt == PIX_FMT_BGR24) { - desired_palette = VIDEO_PALETTE_RGB24; - desired_depth = 24; - } - - /* set tv standard */ - if (ap->standard && !ioctl(video_fd, VIDIOCGTUNER, &tuner)) { - if (!strcasecmp(ap->standard, "pal")) - tuner.mode = VIDEO_MODE_PAL; - else if (!strcasecmp(ap->standard, "secam")) - tuner.mode = VIDEO_MODE_SECAM; - else - tuner.mode = VIDEO_MODE_NTSC; - ioctl(video_fd, VIDIOCSTUNER, &tuner); - } - - /* unmute audio */ - audio.audio = 0; - ioctl(video_fd, VIDIOCGAUDIO, &audio); - memcpy(&s->audio_saved, &audio, sizeof(audio)); - audio.flags &= ~VIDEO_AUDIO_MUTE; - ioctl(video_fd, VIDIOCSAUDIO, &audio); - - ioctl(video_fd, VIDIOCGPICT, &pict); -#if 0 - printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n", - pict.colour, - pict.hue, - pict.brightness, - pict.contrast, - pict.whiteness); -#endif - /* try to choose a suitable video format */ - pict.palette = desired_palette; - pict.depth= desired_depth; - if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCSPICT, &pict)) < 0) { - pict.palette=VIDEO_PALETTE_YUV420P; - pict.depth=12; - ret = ioctl(video_fd, VIDIOCSPICT, &pict); - if (ret < 0) { - pict.palette=VIDEO_PALETTE_YUV422; - pict.depth=16; - ret = ioctl(video_fd, VIDIOCSPICT, &pict); - if (ret < 0) { - pict.palette=VIDEO_PALETTE_RGB24; - pict.depth=24; - ret = ioctl(video_fd, VIDIOCSPICT, &pict); - if (ret < 0) { - pict.palette=VIDEO_PALETTE_GREY; - pict.depth=8; - ret = ioctl(video_fd, VIDIOCSPICT, &pict); - if (ret < 0) - goto fail1; - } - } - } - } - - ret = ioctl(video_fd,VIDIOCGMBUF,&s->gb_buffers); - if (ret < 0) { - /* try to use read based access */ - struct video_window win; - int val; - - win.x = 0; - win.y = 0; - win.width = width; - win.height = height; - win.chromakey = -1; - win.flags = 0; - - ioctl(video_fd, VIDIOCSWIN, &win); - - s->frame_format = pict.palette; - - val = 1; - ioctl(video_fd, VIDIOCCAPTURE, &val); - - s->time_frame = av_gettime() * s->frame_rate / s->frame_rate_base; - s->use_mmap = 0; - - /* ATI All In Wonder automatic activation */ - if (!strcmp(s->video_cap.name, "Km")) { - if (aiw_init(s) < 0) - goto fail; - s->aiw_enabled = 1; - /* force 420P format because convertion from YUV422 to YUV420P - is done in this driver (ugly) */ - s->frame_format = VIDEO_PALETTE_YUV420P; - } - } else { - s->video_buf = mmap(0,s->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0); - if ((unsigned char*)-1 == s->video_buf) { - s->video_buf = mmap(0,s->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_PRIVATE,video_fd,0); - if ((unsigned char*)-1 == s->video_buf) { - perror("mmap"); - goto fail; - } - } - s->gb_frame = 0; - s->time_frame = av_gettime() * s->frame_rate / s->frame_rate_base; - - /* start to grab the first frame */ - s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames; - s->gb_buf.height = height; - s->gb_buf.width = width; - s->gb_buf.format = pict.palette; - - ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf); - if (ret < 0) { - if (errno != EAGAIN) { - fail1: - av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not support suitable format\n"); - } else { - av_log(s1, AV_LOG_ERROR,"Fatal: grab device does not receive any video signal\n"); - } - goto fail; - } - for (j = 1; j < s->gb_buffers.frames; j++) { - s->gb_buf.frame = j; - ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf); - } - s->frame_format = s->gb_buf.format; - s->use_mmap = 1; - } - - switch(s->frame_format) { - case VIDEO_PALETTE_YUV420P: - frame_size = (width * height * 3) / 2; - st->codec->pix_fmt = PIX_FMT_YUV420P; - break; - case VIDEO_PALETTE_YUV422: - frame_size = width * height * 2; - st->codec->pix_fmt = PIX_FMT_YUYV422; - break; - case VIDEO_PALETTE_RGB24: - frame_size = width * height * 3; - st->codec->pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */ - break; - case VIDEO_PALETTE_GREY: - frame_size = width * height * 1; - st->codec->pix_fmt = PIX_FMT_GRAY8; - break; - default: - goto fail; - } - s->fd = video_fd; - s->frame_size = frame_size; - - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = CODEC_ID_RAWVIDEO; - st->codec->width = width; - st->codec->height = height; - st->codec->time_base.den = frame_rate; - st->codec->time_base.num = frame_rate_base; - st->codec->bit_rate = frame_size * 1/av_q2d(st->codec->time_base) * 8; - - return 0; - fail: - if (video_fd >= 0) - close(video_fd); - av_free(st); - return AVERROR_IO; -} - -static int v4l_mm_read_picture(VideoData *s, uint8_t *buf) -{ - uint8_t *ptr; - - while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 && - (errno == EAGAIN || errno == EINTR)); - - ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame]; - memcpy(buf, ptr, s->frame_size); - - /* Setup to capture the next frame */ - s->gb_buf.frame = s->gb_frame; - if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) { - if (errno == EAGAIN) - av_log(NULL, AV_LOG_ERROR, "Cannot Sync\n"); - else - perror("VIDIOCMCAPTURE"); - return AVERROR_IO; - } - - /* This is now the grabbing frame */ - s->gb_frame = (s->gb_frame + 1) % s->gb_buffers.frames; - - return s->frame_size; -} - -static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - VideoData *s = s1->priv_data; - int64_t curtime, delay; - struct timespec ts; - - /* Calculate the time of the next frame */ - s->time_frame += INT64_C(1000000); - - /* wait based on the frame rate */ - for(;;) { - curtime = av_gettime(); - delay = s->time_frame * s->frame_rate_base / s->frame_rate - curtime; - if (delay <= 0) { - if (delay < INT64_C(-1000000) * s->frame_rate_base / s->frame_rate) { - /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */ - s->time_frame += INT64_C(1000000); - } - break; - } - ts.tv_sec = delay / 1000000; - ts.tv_nsec = (delay % 1000000) * 1000; - nanosleep(&ts, NULL); - } - - if (av_new_packet(pkt, s->frame_size) < 0) - return AVERROR_IO; - - pkt->pts = curtime; - - /* read one frame */ - if (s->aiw_enabled) { - return aiw_read_picture(s, pkt->data); - } else if (s->use_mmap) { - return v4l_mm_read_picture(s, pkt->data); - } else { - if (read(s->fd, pkt->data, pkt->size) != pkt->size) - return AVERROR_IO; - return s->frame_size; - } -} - -static int grab_read_close(AVFormatContext *s1) -{ - VideoData *s = s1->priv_data; - - if (s->aiw_enabled) - aiw_close(s); - - if (s->use_mmap) - munmap(s->video_buf, s->gb_buffers.size); - - /* mute audio. we must force it because the BTTV driver does not - return its state correctly */ - s->audio_saved.flags |= VIDEO_AUDIO_MUTE; - ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved); - - close(s->fd); - return 0; -} - -AVInputFormat video_grab_device_demuxer = { - "video4linux", - "video grab", - sizeof(VideoData), - NULL, - grab_read_header, - grab_read_packet, - grab_read_close, - .flags = AVFMT_NOFILE, -}; - -/* All in Wonder specific stuff */ -/* XXX: remove and merge in libavcodec/imgconvert.c */ - -static int aiw_init(VideoData *s) -{ - int width, height; - - width = s->width; - height = s->height; - - if ((width == s->video_cap.maxwidth && height == s->video_cap.maxheight) || - (width == s->video_cap.maxwidth && height == s->video_cap.maxheight*2) || - (width == s->video_cap.maxwidth/2 && height == s->video_cap.maxheight)) { - - s->deint=0; - s->halfw=0; - if (height == s->video_cap.maxheight*2) s->deint=1; - if (width == s->video_cap.maxwidth/2) s->halfw=1; - } else { - av_log(NULL, AV_LOG_ERROR, "\nIncorrect Grab Size Supplied - Supported Sizes Are:\n"); - av_log(NULL, AV_LOG_ERROR, " %dx%d %dx%d %dx%d\n\n", - s->video_cap.maxwidth,s->video_cap.maxheight, - s->video_cap.maxwidth,s->video_cap.maxheight*2, - s->video_cap.maxwidth/2,s->video_cap.maxheight); - goto fail; - } - - if (s->halfw == 0) { - s->src_mem = av_malloc(s->width*2); - } else { - s->src_mem = av_malloc(s->width*4); - } - if (!s->src_mem) goto fail; - - s->lum_m4_mem = av_malloc(s->width); - if (!s->lum_m4_mem) - goto fail; - return 0; - fail: - av_freep(&s->src_mem); - av_freep(&s->lum_m4_mem); - return -1; -} - -#ifdef HAVE_MMX -#include "libavcodec/i386/mmx.h" - -#define LINE_WITH_UV \ - movq_m2r(ptr[0],mm0); \ - movq_m2r(ptr[8],mm1); \ - movq_r2r(mm0, mm4); \ - punpcklbw_r2r(mm1,mm0); \ - punpckhbw_r2r(mm1,mm4); \ - movq_r2r(mm0,mm5); \ - punpcklbw_r2r(mm4,mm0); \ - punpckhbw_r2r(mm4,mm5); \ - movq_r2r(mm0,mm1); \ - punpcklbw_r2r(mm5,mm1); \ - movq_r2m(mm1,lum[0]); \ - movq_m2r(ptr[16],mm2); \ - movq_m2r(ptr[24],mm1); \ - movq_r2r(mm2,mm4); \ - punpcklbw_r2r(mm1,mm2); \ - punpckhbw_r2r(mm1,mm4); \ - movq_r2r(mm2,mm3); \ - punpcklbw_r2r(mm4,mm2); \ - punpckhbw_r2r(mm4,mm3); \ - movq_r2r(mm2,mm1); \ - punpcklbw_r2r(mm3,mm1); \ - movq_r2m(mm1,lum[8]); \ - punpckhdq_r2r(mm2,mm0); \ - punpckhdq_r2r(mm3,mm5); \ - movq_r2m(mm0,cb[0]); \ - movq_r2m(mm5,cr[0]); - -#define LINE_NO_UV \ - movq_m2r(ptr[0],mm0);\ - movq_m2r(ptr[8],mm1);\ - movq_r2r(mm0, mm4);\ - punpcklbw_r2r(mm1,mm0); \ - punpckhbw_r2r(mm1,mm4);\ - movq_r2r(mm0,mm5);\ - punpcklbw_r2r(mm4,mm0);\ - punpckhbw_r2r(mm4,mm5);\ - movq_r2r(mm0,mm1);\ - punpcklbw_r2r(mm5,mm1);\ - movq_r2m(mm1,lum[0]);\ - movq_m2r(ptr[16],mm2);\ - movq_m2r(ptr[24],mm1);\ - movq_r2r(mm2,mm4);\ - punpcklbw_r2r(mm1,mm2);\ - punpckhbw_r2r(mm1,mm4);\ - movq_r2r(mm2,mm3);\ - punpcklbw_r2r(mm4,mm2);\ - punpckhbw_r2r(mm4,mm3);\ - movq_r2r(mm2,mm1);\ - punpcklbw_r2r(mm3,mm1);\ - movq_r2m(mm1,lum[8]); - -#define LINE_WITHUV_AVG \ - movq_m2r(ptr[0], mm0);\ - movq_m2r(ptr[8], mm1);\ - movq_r2r(mm0, mm4);\ - punpcklbw_r2r(mm1,mm0);\ - punpckhbw_r2r(mm1,mm4);\ - movq_r2r(mm0,mm5);\ - punpcklbw_r2r(mm4,mm0);\ - punpckhbw_r2r(mm4,mm5);\ - movq_r2r(mm0,mm1);\ - movq_r2r(mm5,mm2);\ - punpcklbw_r2r(mm7,mm1);\ - punpcklbw_r2r(mm7,mm2);\ - paddw_r2r(mm6,mm1);\ - paddw_r2r(mm2,mm1);\ - psraw_i2r(1,mm1);\ - packuswb_r2r(mm7,mm1);\ - movd_r2m(mm1,lum[0]);\ - movq_m2r(ptr[16],mm2);\ - movq_m2r(ptr[24],mm1);\ - movq_r2r(mm2,mm4);\ - punpcklbw_r2r(mm1,mm2);\ - punpckhbw_r2r(mm1,mm4);\ - movq_r2r(mm2,mm3);\ - punpcklbw_r2r(mm4,mm2);\ - punpckhbw_r2r(mm4,mm3);\ - movq_r2r(mm2,mm1);\ - movq_r2r(mm3,mm4);\ - punpcklbw_r2r(mm7,mm1);\ - punpcklbw_r2r(mm7,mm4);\ - paddw_r2r(mm6,mm1);\ - paddw_r2r(mm4,mm1);\ - psraw_i2r(1,mm1);\ - packuswb_r2r(mm7,mm1);\ - movd_r2m(mm1,lum[4]);\ - punpckhbw_r2r(mm7,mm0);\ - punpckhbw_r2r(mm7,mm2);\ - paddw_r2r(mm6,mm0);\ - paddw_r2r(mm2,mm0);\ - psraw_i2r(1,mm0);\ - packuswb_r2r(mm7,mm0);\ - punpckhbw_r2r(mm7,mm5);\ - punpckhbw_r2r(mm7,mm3);\ - paddw_r2r(mm6,mm5);\ - paddw_r2r(mm3,mm5);\ - psraw_i2r(1,mm5);\ - packuswb_r2r(mm7,mm5);\ - movd_r2m(mm0,cb[0]);\ - movd_r2m(mm5,cr[0]); - -#define LINE_NOUV_AVG \ - movq_m2r(ptr[0],mm0);\ - movq_m2r(ptr[8],mm1);\ - pand_r2r(mm5,mm0);\ - pand_r2r(mm5,mm1);\ - pmaddwd_r2r(mm6,mm0);\ - pmaddwd_r2r(mm6,mm1);\ - packssdw_r2r(mm1,mm0);\ - paddw_r2r(mm6,mm0);\ - psraw_i2r(1,mm0);\ - movq_m2r(ptr[16],mm2);\ - movq_m2r(ptr[24],mm3);\ - pand_r2r(mm5,mm2);\ - pand_r2r(mm5,mm3);\ - pmaddwd_r2r(mm6,mm2);\ - pmaddwd_r2r(mm6,mm3);\ - packssdw_r2r(mm3,mm2);\ - paddw_r2r(mm6,mm2);\ - psraw_i2r(1,mm2);\ - packuswb_r2r(mm2,mm0);\ - movq_r2m(mm0,lum[0]); - -#define DEINT_LINE_LUM(ptroff) \ - movd_m2r(lum_m4[(ptroff)],mm0);\ - movd_m2r(lum_m3[(ptroff)],mm1);\ - movd_m2r(lum_m2[(ptroff)],mm2);\ - movd_m2r(lum_m1[(ptroff)],mm3);\ - movd_m2r(lum[(ptroff)],mm4);\ - punpcklbw_r2r(mm7,mm0);\ - movd_r2m(mm2,lum_m4[(ptroff)]);\ - punpcklbw_r2r(mm7,mm1);\ - punpcklbw_r2r(mm7,mm2);\ - punpcklbw_r2r(mm7,mm3);\ - punpcklbw_r2r(mm7,mm4);\ - psllw_i2r(2,mm1);\ - psllw_i2r(1,mm2);\ - paddw_r2r(mm6,mm1);\ - psllw_i2r(2,mm3);\ - paddw_r2r(mm2,mm1);\ - paddw_r2r(mm4,mm0);\ - paddw_r2r(mm3,mm1);\ - psubusw_r2r(mm0,mm1);\ - psrlw_i2r(3,mm1);\ - packuswb_r2r(mm7,mm1);\ - movd_r2m(mm1,lum_m2[(ptroff)]); - -#else -#include "libavcodec/dsputil.h" - -#define LINE_WITH_UV \ - lum[0]=ptr[0];lum[1]=ptr[2];lum[2]=ptr[4];lum[3]=ptr[6];\ - cb[0]=ptr[1];cb[1]=ptr[5];\ - cr[0]=ptr[3];cr[1]=ptr[7];\ - lum[4]=ptr[8];lum[5]=ptr[10];lum[6]=ptr[12];lum[7]=ptr[14];\ - cb[2]=ptr[9];cb[3]=ptr[13];\ - cr[2]=ptr[11];cr[3]=ptr[15];\ - lum[8]=ptr[16];lum[9]=ptr[18];lum[10]=ptr[20];lum[11]=ptr[22];\ - cb[4]=ptr[17];cb[5]=ptr[21];\ - cr[4]=ptr[19];cr[5]=ptr[23];\ - lum[12]=ptr[24];lum[13]=ptr[26];lum[14]=ptr[28];lum[15]=ptr[30];\ - cb[6]=ptr[25];cb[7]=ptr[29];\ - cr[6]=ptr[27];cr[7]=ptr[31]; - -#define LINE_NO_UV \ - lum[0]=ptr[0];lum[1]=ptr[2];lum[2]=ptr[4];lum[3]=ptr[6];\ - lum[4]=ptr[8];lum[5]=ptr[10];lum[6]=ptr[12];lum[7]=ptr[14];\ - lum[8]=ptr[16];lum[9]=ptr[18];lum[10]=ptr[20];lum[11]=ptr[22];\ - lum[12]=ptr[24];lum[13]=ptr[26];lum[14]=ptr[28];lum[15]=ptr[30]; - -#define LINE_WITHUV_AVG \ - sum=(ptr[0]+ptr[2]+1) >> 1;lum[0]=sum; \ - sum=(ptr[4]+ptr[6]+1) >> 1;lum[1]=sum; \ - sum=(ptr[1]+ptr[5]+1) >> 1;cb[0]=sum; \ - sum=(ptr[3]+ptr[7]+1) >> 1;cr[0]=sum; \ - sum=(ptr[8]+ptr[10]+1) >> 1;lum[2]=sum; \ - sum=(ptr[12]+ptr[14]+1) >> 1;lum[3]=sum; \ - sum=(ptr[9]+ptr[13]+1) >> 1;cb[1]=sum; \ - sum=(ptr[11]+ptr[15]+1) >> 1;cr[1]=sum; \ - sum=(ptr[16]+ptr[18]+1) >> 1;lum[4]=sum; \ - sum=(ptr[20]+ptr[22]+1) >> 1;lum[5]=sum; \ - sum=(ptr[17]+ptr[21]+1) >> 1;cb[2]=sum; \ - sum=(ptr[19]+ptr[23]+1) >> 1;cr[2]=sum; \ - sum=(ptr[24]+ptr[26]+1) >> 1;lum[6]=sum; \ - sum=(ptr[28]+ptr[30]+1) >> 1;lum[7]=sum; \ - sum=(ptr[25]+ptr[29]+1) >> 1;cb[3]=sum; \ - sum=(ptr[27]+ptr[31]+1) >> 1;cr[3]=sum; - -#define LINE_NOUV_AVG \ - sum=(ptr[0]+ptr[2]+1) >> 1;lum[0]=sum; \ - sum=(ptr[4]+ptr[6]+1) >> 1;lum[1]=sum; \ - sum=(ptr[8]+ptr[10]+1) >> 1;lum[2]=sum; \ - sum=(ptr[12]+ptr[14]+1) >> 1;lum[3]=sum; \ - sum=(ptr[16]+ptr[18]+1) >> 1;lum[4]=sum; \ - sum=(ptr[20]+ptr[22]+1) >> 1;lum[5]=sum; \ - sum=(ptr[24]+ptr[26]+1) >> 1;lum[6]=sum; \ - sum=(ptr[28]+ptr[30]+1) >> 1;lum[7]=sum; - -#define DEINT_LINE_LUM(ptroff) \ - sum=(-lum_m4[(ptroff)]+(lum_m3[(ptroff)]<<2)+(lum_m2[(ptroff)]<<1)+(lum_m1[(ptroff)]<<2)-lum[(ptroff)]); \ - lum_m4[(ptroff)]=lum_m2[(ptroff)];\ - lum_m2[(ptroff)]=cm[(sum+4)>>3];\ - sum=(-lum_m4[(ptroff)+1]+(lum_m3[(ptroff)+1]<<2)+(lum_m2[(ptroff)+1]<<1)+(lum_m1[(ptroff)+1]<<2)-lum[(ptroff)+1]); \ - lum_m4[(ptroff)+1]=lum_m2[(ptroff)+1];\ - lum_m2[(ptroff)+1]=cm[(sum+4)>>3];\ - sum=(-lum_m4[(ptroff)+2]+(lum_m3[(ptroff)+2]<<2)+(lum_m2[(ptroff)+2]<<1)+(lum_m1[(ptroff)+2]<<2)-lum[(ptroff)+2]); \ - lum_m4[(ptroff)+2]=lum_m2[(ptroff)+2];\ - lum_m2[(ptroff)+2]=cm[(sum+4)>>3];\ - sum=(-lum_m4[(ptroff)+3]+(lum_m3[(ptroff)+3]<<2)+(lum_m2[(ptroff)+3]<<1)+(lum_m1[(ptroff)+3]<<2)-lum[(ptroff)+3]); \ - lum_m4[(ptroff)+3]=lum_m2[(ptroff)+3];\ - lum_m2[(ptroff)+3]=cm[(sum+4)>>3]; - -#endif - - -/* Read two fields separately. */ -static int aiw_read_picture(VideoData *s, uint8_t *data) -{ - uint8_t *ptr, *lum, *cb, *cr; - int h; -#ifndef HAVE_MMX - int sum; -#endif - uint8_t* src = s->src_mem; - uint8_t *ptrend = &src[s->width*2]; - lum=data; - cb=&lum[s->width*s->height]; - cr=&cb[(s->width*s->height)/4]; - if (s->deint == 0 && s->halfw == 0) { - while (read(s->fd,src,s->width*2) < 0) { - usleep(100); - } - for (h = 0; h < s->height-2; h+=2) { - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) { - LINE_WITH_UV - } - read(s->fd,src,s->width*2); - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) { - LINE_NO_UV - } - read(s->fd,src,s->width*2); - } - /* - * Do last two lines - */ - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) { - LINE_WITH_UV - } - read(s->fd,src,s->width*2); - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) { - LINE_NO_UV - } - /* drop second field */ - while (read(s->fd,src,s->width*2) < 0) { - usleep(100); - } - for (h = 0; h < s->height - 1; h++) { - read(s->fd,src,s->width*2); - } - } else if (s->halfw == 1) { -#ifdef HAVE_MMX - mmx_t rounder; - mmx_t masker; - rounder.uw[0]=1; - rounder.uw[1]=1; - rounder.uw[2]=1; - rounder.uw[3]=1; - masker.ub[0]=0xff; - masker.ub[1]=0; - masker.ub[2]=0xff; - masker.ub[3]=0; - masker.ub[4]=0xff; - masker.ub[5]=0; - masker.ub[6]=0xff; - masker.ub[7]=0; - pxor_r2r(mm7,mm7); - movq_m2r(rounder,mm6); -#endif - while (read(s->fd,src,s->width*4) < 0) { - usleep(100); - } - ptrend = &src[s->width*4]; - for (h = 0; h < s->height-2; h+=2) { - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8, cb+=4, cr+=4) { - LINE_WITHUV_AVG - } - read(s->fd,src,s->width*4); -#ifdef HAVE_MMX - movq_m2r(masker,mm5); -#endif - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8) { - LINE_NOUV_AVG - } - read(s->fd,src,s->width*4); - } - /* - * Do last two lines - */ - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8, cb+=4, cr+=4) { - LINE_WITHUV_AVG - } - read(s->fd,src,s->width*4); -#ifdef HAVE_MMX - movq_m2r(masker,mm5); -#endif - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=8) { - LINE_NOUV_AVG - } - /* drop second field */ - while (read(s->fd,src,s->width*4) < 0) { - usleep(100); - } - for (h = 0; h < s->height - 1; h++) { - read(s->fd,src,s->width*4); - } - } else { - uint8_t *lum_m1, *lum_m2, *lum_m3, *lum_m4; -#ifdef HAVE_MMX - mmx_t rounder; - rounder.uw[0]=4; - rounder.uw[1]=4; - rounder.uw[2]=4; - rounder.uw[3]=4; - movq_m2r(rounder,mm6); - pxor_r2r(mm7,mm7); -#else - uint8_t *cm = ff_cropTbl + MAX_NEG_CROP; -#endif - - /* read two fields and deinterlace them */ - while (read(s->fd,src,s->width*2) < 0) { - usleep(100); - } - for (h = 0; h < (s->height/2)-2; h+=2) { - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) { - LINE_WITH_UV - } - read(s->fd,src,s->width*2); - /* skip a luminance line - will be filled in later */ - lum += s->width; - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) { - LINE_WITH_UV - } - /* skip a luminance line - will be filled in later */ - lum += s->width; - read(s->fd,src,s->width*2); - } - /* - * Do last two lines - */ - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) { - LINE_WITH_UV - } - /* skip a luminance line - will be filled in later */ - lum += s->width; - read(s->fd,src,s->width*2); - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, cb+=8, cr+=8) { - LINE_WITH_UV - } - /* - * - * SECOND FIELD - * - */ - lum=&data[s->width]; - while (read(s->fd,src,s->width*2) < 0) { - usleep(10); - } - /* First (and last) two lines not interlaced */ - for (h = 0; h < 2; h++) { - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16) { - LINE_NO_UV - } - read(s->fd,src,s->width*2); - /* skip a luminance line */ - lum += s->width; - } - lum_m1=&lum[-s->width]; - lum_m2=&lum_m1[-s->width]; - lum_m3=&lum_m2[-s->width]; - memmove(s->lum_m4_mem,&lum_m3[-s->width],s->width); - for (; h < (s->height/2)-1; h++) { - lum_m4=s->lum_m4_mem; - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16,lum_m1+=16,lum_m2+=16,lum_m3+=16,lum_m4+=16) { - LINE_NO_UV - - DEINT_LINE_LUM(0) - DEINT_LINE_LUM(4) - DEINT_LINE_LUM(8) - DEINT_LINE_LUM(12) - } - read(s->fd,src,s->width*2); - /* skip a luminance line */ - lum += s->width; - lum_m1 += s->width; - lum_m2 += s->width; - lum_m3 += s->width; - // lum_m4 += s->width; - } - /* - * Do last line - */ - lum_m4=s->lum_m4_mem; - for (ptr = &src[0]; ptr < ptrend; ptr+=32, lum+=16, lum_m1+=16, lum_m2+=16, lum_m3+=16, lum_m4+=16) { - LINE_NO_UV - - DEINT_LINE_LUM(0) - DEINT_LINE_LUM(4) - DEINT_LINE_LUM(8) - DEINT_LINE_LUM(12) - } - } -#ifdef HAVE_MMX - emms(); -#endif - return s->frame_size; -} - -static int aiw_close(VideoData *s) -{ - av_freep(&s->lum_m4_mem); - av_freep(&s->src_mem); - return 0; -} diff --git a/contrib/ffmpeg/libavformat/grab_bktr.c b/contrib/ffmpeg/libavformat/grab_bktr.c deleted file mode 100644 index 100653db7..000000000 --- a/contrib/ffmpeg/libavformat/grab_bktr.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * *BSD video grab interface - * Copyright (c) 2002 Steve O'Hara-Smith - * based on - * Linux video grab interface - * Copyright (c) 2000,2001 Gerard Lantau. - * and - * simple_grab.c Copyright (c) 1999 Roger Hardiman - * - * 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" -#if defined (HAVE_DEV_BKTR_IOCTL_METEOR_H) && defined (HAVE_DEV_BKTR_IOCTL_BT848_H) -# include <dev/bktr/ioctl_meteor.h> -# include <dev/bktr/ioctl_bt848.h> -#elif defined (HAVE_MACHINE_IOCTL_METEOR_H) && defined (HAVE_MACHINE_IOCTL_BT848_H) -# include <machine/ioctl_meteor.h> -# include <machine/ioctl_bt848.h> -#elif defined (HAVE_DEV_VIDEO_METEOR_IOCTL_METEOR_H) && defined (HAVE_DEV_VIDEO_METEOR_IOCTL_BT848_H) -# include <dev/video/meteor/ioctl_meteor.h> -# include <dev/video/bktr/ioctl_bt848.h> -#elif HAVE_DEV_IC_BT8XX_H -# include <dev/ic/bt8xx.h> -#endif -#include <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <signal.h> - -typedef struct { - int video_fd; - int tuner_fd; - int width, height; - int frame_rate; - int frame_rate_base; - u_int64_t per_frame; -} VideoData; - - -#define PAL 1 -#define PALBDGHI 1 -#define NTSC 2 -#define NTSCM 2 -#define SECAM 3 -#define PALN 4 -#define PALM 5 -#define NTSCJ 6 - -/* PAL is 768 x 576. NTSC is 640 x 480 */ -#define PAL_HEIGHT 576 -#define SECAM_HEIGHT 576 -#define NTSC_HEIGHT 480 - -#ifndef VIDEO_FORMAT -#define VIDEO_FORMAT NTSC -#endif - -static int bktr_dev[] = { METEOR_DEV0, METEOR_DEV1, METEOR_DEV2, - METEOR_DEV3, METEOR_DEV_SVIDEO }; - -uint8_t *video_buf; -size_t video_buf_size; -u_int64_t last_frame_time; -volatile sig_atomic_t nsignals; - - -static void catchsignal(int signal) -{ - nsignals++; - return; -} - -static int bktr_init(const char *video_device, int width, int height, - int format, int *video_fd, int *tuner_fd, int idev, double frequency) -{ - struct meteor_geomet geo; - int h_max; - long ioctl_frequency; - char *arg; - int c; - struct sigaction act, old; - - if (idev < 0 || idev > 4) - { - arg = getenv ("BKTR_DEV"); - if (arg) - idev = atoi (arg); - if (idev < 0 || idev > 4) - idev = 1; - } - - if (format < 1 || format > 6) - { - arg = getenv ("BKTR_FORMAT"); - if (arg) - format = atoi (arg); - if (format < 1 || format > 6) - format = VIDEO_FORMAT; - } - - if (frequency <= 0) - { - arg = getenv ("BKTR_FREQUENCY"); - if (arg) - frequency = atof (arg); - if (frequency <= 0) - frequency = 0.0; - } - - memset(&act, 0, sizeof(act)); - sigemptyset(&act.sa_mask); - act.sa_handler = catchsignal; - sigaction(SIGUSR1, &act, &old); - - *tuner_fd = open("/dev/tuner0", O_RDONLY); - if (*tuner_fd < 0) - perror("Warning: Tuner not opened, continuing"); - - *video_fd = open(video_device, O_RDONLY); - if (*video_fd < 0) { - perror(video_device); - return -1; - } - - geo.rows = height; - geo.columns = width; - geo.frames = 1; - geo.oformat = METEOR_GEO_YUV_422 | METEOR_GEO_YUV_12; - - switch (format) { - case PAL: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALBDGHI; break; - case PALN: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALN; break; - case PALM: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALM; break; - case SECAM: h_max = SECAM_HEIGHT; c = BT848_IFORM_F_SECAM; break; - case NTSC: h_max = NTSC_HEIGHT; c = BT848_IFORM_F_NTSCM; break; - case NTSCJ: h_max = NTSC_HEIGHT; c = BT848_IFORM_F_NTSCJ; break; - default: h_max = PAL_HEIGHT; c = BT848_IFORM_F_PALBDGHI; break; - } - - if (height <= h_max / 2) - geo.oformat |= METEOR_GEO_EVEN_ONLY; - - if (ioctl(*video_fd, METEORSETGEO, &geo) < 0) { - perror("METEORSETGEO"); - return -1; - } - - if (ioctl(*video_fd, BT848SFMT, &c) < 0) { - perror("BT848SFMT"); - return -1; - } - - c = bktr_dev[idev]; - if (ioctl(*video_fd, METEORSINPUT, &c) < 0) { - perror("METEORSINPUT"); - return -1; - } - - video_buf_size = width * height * 12 / 8; - - video_buf = (uint8_t *)mmap((caddr_t)0, video_buf_size, - PROT_READ, MAP_SHARED, *video_fd, (off_t)0); - if (video_buf == MAP_FAILED) { - perror("mmap"); - return -1; - } - - if (frequency != 0.0) { - ioctl_frequency = (unsigned long)(frequency*16); - if (ioctl(*tuner_fd, TVTUNER_SETFREQ, &ioctl_frequency) < 0) - perror("TVTUNER_SETFREQ"); - } - - c = AUDIO_UNMUTE; - if (ioctl(*tuner_fd, BT848_SAUDIO, &c) < 0) - perror("TVTUNER_SAUDIO"); - - c = METEOR_CAP_CONTINOUS; - ioctl(*video_fd, METEORCAPTUR, &c); - - c = SIGUSR1; - ioctl(*video_fd, METEORSSIGNAL, &c); - - return 0; -} - -static void bktr_getframe(u_int64_t per_frame) -{ - u_int64_t curtime; - - curtime = av_gettime(); - if (!last_frame_time - || ((last_frame_time + per_frame) > curtime)) { - if (!usleep(last_frame_time + per_frame + per_frame / 8 - curtime)) { - if (!nsignals) - av_log(NULL, AV_LOG_INFO, - "SLEPT NO signals - %d microseconds late\n", - (int)(av_gettime() - last_frame_time - per_frame)); - } - } - nsignals = 0; - last_frame_time = curtime; -} - - -/* note: we support only one picture read at a time */ -static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - VideoData *s = s1->priv_data; - - if (av_new_packet(pkt, video_buf_size) < 0) - return AVERROR(EIO); - - bktr_getframe(s->per_frame); - - pkt->pts = av_gettime(); - memcpy(pkt->data, video_buf, video_buf_size); - - return video_buf_size; -} - -static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) -{ - VideoData *s = s1->priv_data; - AVStream *st; - int width, height; - int frame_rate; - int frame_rate_base; - int format = -1; - - if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) - return -1; - - width = ap->width; - height = ap->height; - frame_rate = ap->time_base.den; - frame_rate_base = ap->time_base.num; - - st = av_new_stream(s1, 0); - if (!st) - return AVERROR(ENOMEM); - av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in use */ - - s->width = width; - s->height = height; - s->frame_rate = frame_rate; - s->frame_rate_base = frame_rate_base; - s->per_frame = ((u_int64_t)1000000 * s->frame_rate_base) / s->frame_rate; - - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->pix_fmt = PIX_FMT_YUV420P; - st->codec->codec_id = CODEC_ID_RAWVIDEO; - st->codec->width = width; - st->codec->height = height; - st->codec->time_base.den = frame_rate; - st->codec->time_base.num = frame_rate_base; - - if (ap->standard) { - if (!strcasecmp(ap->standard, "pal")) - format = PAL; - else if (!strcasecmp(ap->standard, "secam")) - format = SECAM; - else if (!strcasecmp(ap->standard, "ntsc")) - format = NTSC; - } - - if (bktr_init(s1->filename, width, height, format, - &(s->video_fd), &(s->tuner_fd), -1, 0.0) < 0) - return AVERROR(EIO); - - nsignals = 0; - last_frame_time = 0; - - return 0; -} - -static int grab_read_close(AVFormatContext *s1) -{ - VideoData *s = s1->priv_data; - int c; - - c = METEOR_CAP_STOP_CONT; - ioctl(s->video_fd, METEORCAPTUR, &c); - close(s->video_fd); - - c = AUDIO_MUTE; - ioctl(s->tuner_fd, BT848_SAUDIO, &c); - close(s->tuner_fd); - - munmap((caddr_t)video_buf, video_buf_size); - - return 0; -} - -AVInputFormat video_grab_device_demuxer = { - "bktr", - "video grab", - sizeof(VideoData), - NULL, - grab_read_header, - grab_read_packet, - grab_read_close, - .flags = AVFMT_NOFILE, -}; diff --git a/contrib/ffmpeg/libavformat/gxf.c b/contrib/ffmpeg/libavformat/gxf.c index ba2463ead..d4bf6f43b 100644 --- a/contrib/ffmpeg/libavformat/gxf.c +++ b/contrib/ffmpeg/libavformat/gxf.c @@ -20,33 +20,7 @@ */ #include "avformat.h" #include "common.h" - -typedef enum { - PKT_MAP = 0xbc, - PKT_MEDIA = 0xbf, - PKT_EOS = 0xfb, - PKT_FLT = 0xfc, - PKT_UMF = 0xfd -} pkt_type_t; - -typedef enum { - MAT_NAME = 0x40, - MAT_FIRST_FIELD = 0x41, - MAT_LAST_FIELD = 0x42, - MAT_MARK_IN = 0x43, - MAT_MARK_OUT = 0x44, - MAT_SIZE = 0x45 -} mat_tag_t; - -typedef enum { - TRACK_NAME = 0x4c, - TRACK_AUX = 0x4d, - TRACK_VER = 0x4e, - TRACK_MPG_AUX = 0x4f, - TRACK_FPS = 0x50, - TRACK_LINES = 0x51, - TRACK_FPF = 0x52 -} track_tag_t; +#include "gxf.h" typedef struct { int64_t first_field; @@ -87,8 +61,6 @@ static int parse_packet_header(ByteIOContext *pb, pkt_type_t *type, int *length) static int gxf_probe(AVProbeData *p) { static const uint8_t startcode[] = {0, 0, 0, 0, 1, 0xbc}; // start with map packet static const uint8_t endcode[] = {0, 0, 0, 0, 0xe1, 0xe2}; - if (p->buf_size < 16) - return 0; if (!memcmp(p->buf, startcode, sizeof(startcode)) && !memcmp(&p->buf[16 - sizeof(endcode)], endcode, sizeof(endcode))) return AVPROBE_SCORE_MAX; @@ -130,13 +102,13 @@ static int get_sindex(AVFormatContext *s, int id, int format) { case 20: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_MPEG2VIDEO; - st->need_parsing = 2; // get keyframe flag etc. + st->need_parsing = AVSTREAM_PARSE_HEADERS; //get keyframe flag etc. break; case 22: case 23: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_MPEG1VIDEO; - st->need_parsing = 2; // get keyframe flag etc. + st->need_parsing = AVSTREAM_PARSE_HEADERS; //get keyframe flag etc. break; case 9: st->codec->codec_type = CODEC_TYPE_AUDIO; @@ -179,7 +151,7 @@ static int get_sindex(AVFormatContext *s, int id, int format) { /** * \brief filters out interesting tags from material information. - * \param len lenght of tag section, will be adjusted to contain remaining bytes + * \param len length of tag section, will be adjusted to contain remaining bytes * \param si struct to store collected information into */ static void gxf_material_tags(ByteIOContext *pb, int *len, st_info_t *si) { @@ -256,7 +228,7 @@ static void gxf_track_tags(ByteIOContext *pb, int *len, st_info_t *si) { * \brief read index from FLT packet into stream 0 av_index */ static void gxf_read_index(AVFormatContext *s, int pkt_len) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st = s->streams[0]; uint32_t fields_per_map = get_le32(pb); uint32_t map_cnt = get_le32(pb); @@ -280,7 +252,7 @@ static void gxf_read_index(AVFormatContext *s, int pkt_len) { } static int gxf_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; pkt_type_t pkt_type; int map_len; int len; @@ -406,7 +378,7 @@ static int64_t gxf_resync_media(AVFormatContext *s, uint64_t max_interval, int t int cur_track; int64_t cur_timestamp = AV_NOPTS_VALUE; int len; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; pkt_type_t type; tmp = get_be32(pb); start: @@ -436,7 +408,7 @@ out: } static int gxf_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; pkt_type_t pkt_type; int pkt_len; while (!url_feof(pb)) { @@ -475,7 +447,7 @@ static int gxf_packet(AVFormatContext *s, AVPacket *pkt) { pkt->dts = field_nr; return ret; } - return AVERROR_IO; + return AVERROR(EIO); } static int gxf_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { @@ -494,7 +466,7 @@ static int gxf_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int if (idx < st->nb_index_entries - 2) maxlen = st->index_entries[idx + 2].pos - pos; maxlen = FFMAX(maxlen, 200 * 1024); - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); found = gxf_resync_media(s, maxlen, -1, timestamp); if (FFABS(found - timestamp) > 4) return -1; @@ -503,7 +475,7 @@ static int gxf_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int static int64_t gxf_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos, int64_t pos_limit) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int64_t res; url_fseek(pb, *pos, SEEK_SET); res = gxf_resync_media(s, pos_limit - *pos, -1, -1); diff --git a/contrib/ffmpeg/libavformat/gxf.h b/contrib/ffmpeg/libavformat/gxf.h index 0e2a31ca4..ab37cb97f 100644 --- a/contrib/ffmpeg/libavformat/gxf.h +++ b/contrib/ffmpeg/libavformat/gxf.h @@ -24,11 +24,30 @@ /* gxf.c */ typedef enum { - PKT_MAP = 0xbc, - PKT_MEDIA = 0xbf, - PKT_EOS = 0xfb, - PKT_FLT = 0xfc, - PKT_UMF = 0xfd + PKT_MAP = 0xbc, + PKT_MEDIA = 0xbf, + PKT_EOS = 0xfb, + PKT_FLT = 0xfc, + PKT_UMF = 0xfd, } pkt_type_t; +typedef enum { + MAT_NAME = 0x40, + MAT_FIRST_FIELD = 0x41, + MAT_LAST_FIELD = 0x42, + MAT_MARK_IN = 0x43, + MAT_MARK_OUT = 0x44, + MAT_SIZE = 0x45, +} mat_tag_t; + +typedef enum { + TRACK_NAME = 0x4c, + TRACK_AUX = 0x4d, + TRACK_VER = 0x4e, + TRACK_MPG_AUX = 0x4f, + TRACK_FPS = 0x50, + TRACK_LINES = 0x51, + TRACK_FPF = 0x52, +} track_tag_t; + #endif /* FFMPEG_GXF_H */ diff --git a/contrib/ffmpeg/libavformat/gxfenc.c b/contrib/ffmpeg/libavformat/gxfenc.c index 39b9ed3e1..469105de5 100644 --- a/contrib/ffmpeg/libavformat/gxfenc.c +++ b/contrib/ffmpeg/libavformat/gxfenc.c @@ -4,18 +4,18 @@ * * This file is part of FFmpeg. * - * FFmpeg is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with FFmpeg; if not, write to the Free Software + * 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 */ @@ -187,7 +187,7 @@ static int gxf_write_mpeg_auxiliary(ByteIOContext *pb, GXFStreamContext *ctx) (float)ctx->codec->bit_rate, ctx->p_per_gop, ctx->b_per_gop, ctx->codec->pix_fmt == PIX_FMT_YUV422P ? 2 : 1, ctx->first_gop_closed == 1, ctx->codec->height / 16); - put_byte(pb, 0x4F); + put_byte(pb, TRACK_MPG_AUX); put_byte(pb, size + 1); put_buffer(pb, (uint8_t *)buffer, size + 1); return size + 3; @@ -217,7 +217,7 @@ static int gxf_write_track_description(ByteIOContext *pb, GXFStreamContext *stre put_be16(pb, 0); /* size */ /* media file name */ - put_byte(pb, 0x4C); + put_byte(pb, TRACK_NAME); put_byte(pb, strlen(ES_NAME_PATTERN) + 3); put_tag(pb, ES_NAME_PATTERN); put_be16(pb, stream->media_info); @@ -225,7 +225,7 @@ static int gxf_write_track_description(ByteIOContext *pb, GXFStreamContext *stre if (stream->codec->codec_id != CODEC_ID_MPEG2VIDEO) { /* auxiliary information */ - put_byte(pb, 0x4D); + put_byte(pb, TRACK_AUX); put_byte(pb, 8); if (stream->codec->codec_id == CODEC_ID_NONE) gxf_write_timecode_auxiliary(pb, stream); @@ -234,7 +234,7 @@ static int gxf_write_track_description(ByteIOContext *pb, GXFStreamContext *stre } /* file system version */ - put_byte(pb, 0x4E); + put_byte(pb, TRACK_VER); put_byte(pb, 4); put_be32(pb, 0); @@ -242,17 +242,17 @@ static int gxf_write_track_description(ByteIOContext *pb, GXFStreamContext *stre gxf_write_mpeg_auxiliary(pb, stream); /* frame rate */ - put_byte(pb, 0x50); + put_byte(pb, TRACK_FPS); put_byte(pb, 4); put_be32(pb, stream->frame_rate_index); /* lines per frame */ - put_byte(pb, 0x51); + put_byte(pb, TRACK_LINES); put_byte(pb, 4); put_be32(pb, stream->lines_index); /* fields per frame */ - put_byte(pb, 0x52); + put_byte(pb, TRACK_FPF); put_byte(pb, 4); put_be32(pb, stream->fields); @@ -272,33 +272,33 @@ static int gxf_write_material_data_section(ByteIOContext *pb, GXFContext *ctx) filename++; else filename = ctx->fc->filename; - put_byte(pb, 0x40); + put_byte(pb, MAT_NAME); put_byte(pb, strlen(SERVER_PATH) + strlen(filename) + 1); put_tag(pb, SERVER_PATH); put_tag(pb, filename); put_byte(pb, 0); /* first field */ - put_byte(pb, 0x41); + put_byte(pb, MAT_FIRST_FIELD); put_byte(pb, 4); put_be32(pb, 0); /* last field */ - put_byte(pb, 0x42); + put_byte(pb, MAT_LAST_FIELD); put_byte(pb, 4); put_be32(pb, ctx->nb_frames); /* reserved */ - put_byte(pb, 0x43); + put_byte(pb, MAT_MARK_IN); put_byte(pb, 4); put_be32(pb, 0); - put_byte(pb, 0x44); + put_byte(pb, MAT_MARK_OUT); put_byte(pb, 4); put_be32(pb, ctx->nb_frames); /* estimated size */ - put_byte(pb, 0x45); + put_byte(pb, MAT_SIZE); put_byte(pb, 4); put_be32(pb, url_fsize(pb) / 1024); @@ -576,7 +576,7 @@ static int gxf_write_umf_packet(ByteIOContext *pb, GXFContext *ctx) static int gxf_write_header(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; GXFContext *gxf = s->priv_data; int i; @@ -671,7 +671,7 @@ static int gxf_write_eos_packet(ByteIOContext *pb, GXFContext *ctx) static int gxf_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; GXFContext *gxf = s->priv_data; offset_t end; int i; @@ -679,9 +679,9 @@ static int gxf_write_trailer(AVFormatContext *s) for (i = 0; i < s->nb_streams; ++i) { if (s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) { av_fifo_free(&gxf->streams[i].audio_buffer); - } - if (s->streams[i]->codec->frame_number > gxf->nb_frames) + } else if (s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) { gxf->nb_frames = 2 * s->streams[i]->codec->frame_number; + } } gxf_write_eos_packet(pb, gxf); @@ -710,7 +710,7 @@ static int gxf_parse_mpeg_frame(GXFStreamContext *sc, const uint8_t *buf, int si static int gxf_write_media_preamble(ByteIOContext *pb, GXFContext *ctx, AVPacket *pkt, int size) { GXFStreamContext *sc = &ctx->streams[pkt->stream_index]; - int64_t dts = av_rescale(pkt->dts, ctx->sample_rate, sc->codec->time_base.den); + int64_t dts = av_rescale_rnd(pkt->dts, ctx->sample_rate, sc->codec->time_base.den, AV_ROUND_UP); put_byte(pb, sc->media_type); put_byte(pb, sc->index); @@ -763,8 +763,8 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt) { GXFContext *gxf = s->priv_data; - gxf_write_media_packet(&s->pb, gxf, pkt); - put_flush_packet(&s->pb); + gxf_write_media_packet(s->pb, gxf, pkt); + put_flush_packet(s->pb); return 0; } diff --git a/contrib/ffmpeg/libavformat/http.c b/contrib/ffmpeg/libavformat/http.c index e057d6efe..1d542061b 100644 --- a/contrib/ffmpeg/libavformat/http.c +++ b/contrib/ffmpeg/libavformat/http.c @@ -21,11 +21,13 @@ #include "avformat.h" #include <unistd.h> #include "network.h" +#include "os_support.h" #include "base64.h" +#include "avstring.h" -/* XXX: POST protocol is not completly implemented because ffmpeg use - only a subset of it */ +/* XXX: POST protocol is not completely implemented because ffmpeg uses + only a subset of it. */ //#define DEBUG @@ -62,7 +64,7 @@ static int http_open_cnx(URLContext *h) proxy_path = getenv("http_proxy"); use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && - strstart(proxy_path, "http://", NULL); + av_strstart(proxy_path, "http://", NULL); /* fill the dest addr */ redo: @@ -72,7 +74,7 @@ static int http_open_cnx(URLContext *h) if (port > 0) { snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port); } else { - pstrcpy(hoststr, sizeof(hoststr), hostname); + av_strlcpy(hoststr, hostname, sizeof(hoststr)); } if (use_proxy) { @@ -100,7 +102,7 @@ static int http_open_cnx(URLContext *h) /* url moved, get next */ url_close(hd); if (redirects++ >= MAX_REDIRECTS) - return AVERROR_IO; + return AVERROR(EIO); location_changed = 0; goto redo; } @@ -108,7 +110,7 @@ static int http_open_cnx(URLContext *h) fail: if (hd) url_close(hd); - return AVERROR_IO; + return AVERROR(EIO); } static int http_open(URLContext *h, const char *uri, int flags) @@ -125,7 +127,7 @@ static int http_open(URLContext *h, const char *uri, int flags) h->priv_data = s; s->filesize = -1; s->off = 0; - pstrcpy (s->location, URL_SIZE, uri); + av_strlcpy(s->location, uri, URL_SIZE); ret = http_open_cnx(h); if (ret != 0) @@ -138,7 +140,7 @@ static int http_getc(HTTPContext *s) if (s->buf_ptr >= s->buf_end) { len = url_read(s->hd, s->buffer, BUFFER_SIZE); if (len < 0) { - return AVERROR_IO; + return AVERROR(EIO); } else if (len == 0) { return -1; } else { @@ -217,7 +219,7 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr, /* send http header */ post = h->flags & URL_WRONLY; auth_b64 = av_malloc(auth_b64_len); - av_base64_encode(auth_b64, auth_b64_len, (uint8_t *)auth, strlen(auth)); + av_base64_encode(auth_b64, auth_b64_len, auth, strlen(auth)); snprintf(s->buffer, sizeof(s->buffer), "%s %s HTTP/1.1\r\n" "User-Agent: %s\r\n" @@ -236,7 +238,7 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr, av_freep(&auth_b64); if (http_write(h, s->buffer, strlen(s->buffer)) < 0) - return AVERROR_IO; + return AVERROR(EIO); /* init input buffer */ s->buf_ptr = s->buffer; @@ -245,7 +247,6 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr, s->off = 0; s->filesize = -1; if (post) { - sleep(1); return 0; } @@ -254,7 +255,7 @@ static int http_connect(URLContext *h, const char *path, const char *hoststr, for(;;) { ch = http_getc(s); if (ch < 0) - return AVERROR_IO; + return AVERROR(EIO); if (ch == '\n') { /* process line */ if (q > line && q[-1] == '\r') diff --git a/contrib/ffmpeg/libavformat/idcin.c b/contrib/ffmpeg/libavformat/idcin.c index e2c92f3b4..914a3532a 100644 --- a/contrib/ffmpeg/libavformat/idcin.c +++ b/contrib/ffmpeg/libavformat/idcin.c @@ -71,7 +71,7 @@ #include "avformat.h" #define HUFFMAN_TABLE_SIZE (64 * 1024) -#define FRAME_PTS_INC (90000 / 14) +#define IDCIN_FPS 14 typedef struct IdcinDemuxContext { int video_stream_index; @@ -104,10 +104,6 @@ static int idcin_probe(AVProbeData *p) * audio channels: 0 for no audio, or 1 or 2 */ - /* cannot proceed without 20 bytes */ - if (p->buf_size < 20) - return 0; - /* check the video width */ number = AV_RL32(&p->buf[0]); if ((number == 0) || (number > 1024)) @@ -140,8 +136,8 @@ static int idcin_probe(AVProbeData *p) static int idcin_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; - IdcinDemuxContext *idcin = (IdcinDemuxContext *)s->priv_data; + ByteIOContext *pb = s->pb; + IdcinDemuxContext *idcin = s->priv_data; AVStream *st; unsigned int width, height; unsigned int sample_rate, bytes_per_sample, channels; @@ -155,8 +151,8 @@ static int idcin_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; - av_set_pts_info(st, 33, 1, 90000); + return AVERROR(ENOMEM); + av_set_pts_info(st, 33, 1, IDCIN_FPS); idcin->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_IDCIN; @@ -169,7 +165,7 @@ static int idcin_read_header(AVFormatContext *s, st->codec->extradata = av_malloc(HUFFMAN_TABLE_SIZE); if (get_buffer(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE) != HUFFMAN_TABLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); /* save a reference in order to transport the palette */ st->codec->palctrl = &idcin->palctrl; @@ -178,8 +174,8 @@ static int idcin_read_header(AVFormatContext *s, idcin->audio_present = 1; st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; - av_set_pts_info(st, 33, 1, 90000); + return AVERROR(ENOMEM); + av_set_pts_info(st, 33, 1, IDCIN_FPS); idcin->audio_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_tag = 1; @@ -218,25 +214,25 @@ static int idcin_read_packet(AVFormatContext *s, int ret; unsigned int command; unsigned int chunk_size; - IdcinDemuxContext *idcin = (IdcinDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + IdcinDemuxContext *idcin = s->priv_data; + ByteIOContext *pb = s->pb; int i; int palette_scale; unsigned char r, g, b; unsigned char palette_buffer[768]; - if (url_feof(&s->pb)) - return AVERROR_IO; + if (url_feof(s->pb)) + return AVERROR(EIO); if (idcin->next_chunk_is_video) { command = get_le32(pb); if (command == 2) { - return AVERROR_IO; + return AVERROR(EIO); } else if (command == 1) { /* trigger a palette change */ idcin->palctrl.palette_changed = 1; if (get_buffer(pb, palette_buffer, 768) != 768) - return AVERROR_IO; + return AVERROR(EIO); /* scale the palette as necessary */ palette_scale = 2; for (i = 0; i < 768; i++) @@ -259,7 +255,7 @@ static int idcin_read_packet(AVFormatContext *s, chunk_size -= 4; ret= av_get_packet(pb, pkt, chunk_size); if (ret != chunk_size) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = idcin->video_stream_index; pkt->pts = idcin->pts; } else { @@ -270,12 +266,12 @@ static int idcin_read_packet(AVFormatContext *s, chunk_size = idcin->audio_chunk_size1; ret= av_get_packet(pb, pkt, chunk_size); if (ret != chunk_size) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = idcin->audio_stream_index; pkt->pts = idcin->pts; idcin->current_audio_chunk ^= 1; - idcin->pts += FRAME_PTS_INC; + idcin->pts++; } if (idcin->audio_present) diff --git a/contrib/ffmpeg/libavformat/idroq.c b/contrib/ffmpeg/libavformat/idroq.c index b8ee176ab..394697fcd 100644 --- a/contrib/ffmpeg/libavformat/idroq.c +++ b/contrib/ffmpeg/libavformat/idroq.c @@ -58,9 +58,6 @@ typedef struct RoqDemuxContext { static int roq_probe(AVProbeData *p) { - if (p->buf_size < 6) - return 0; - if ((AV_RL16(&p->buf[0]) != RoQ_MAGIC_NUMBER) || (AV_RL32(&p->buf[2]) != 0xFFFFFFFF)) return 0; @@ -72,7 +69,7 @@ static int roq_read_header(AVFormatContext *s, AVFormatParameters *ap) { RoqDemuxContext *roq = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; int i; @@ -82,7 +79,7 @@ static int roq_read_header(AVFormatContext *s, /* get the main header */ if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); roq->framerate = AV_RL16(&preamble[6]); roq->frame_pts_inc = 90000 / roq->framerate; @@ -94,7 +91,7 @@ static int roq_read_header(AVFormatContext *s, for (i = 0; i < RoQ_CHUNKS_TO_SCAN; i++) { if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); chunk_type = AV_RL16(&preamble[0]); chunk_size = AV_RL32(&preamble[2]); @@ -105,7 +102,7 @@ static int roq_read_header(AVFormatContext *s, /* fetch the width and height; reuse the preamble bytes */ if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); roq->width = AV_RL16(&preamble[0]); roq->height = AV_RL16(&preamble[2]); break; @@ -143,7 +140,7 @@ static int roq_read_header(AVFormatContext *s, /* initialize the decoders */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); /* set the pts reference (1 pts = 1/90000) */ av_set_pts_info(st, 33, 1, 90000); roq->video_stream_index = st->index; @@ -156,7 +153,7 @@ static int roq_read_header(AVFormatContext *s, if (roq->audio_channels) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, 90000); roq->audio_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_AUDIO; @@ -177,7 +174,7 @@ static int roq_read_packet(AVFormatContext *s, AVPacket *pkt) { RoqDemuxContext *roq = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int ret = 0; unsigned int chunk_size; unsigned int chunk_type; @@ -188,13 +185,13 @@ static int roq_read_packet(AVFormatContext *s, while (!packet_read) { - if (url_feof(&s->pb)) - return AVERROR_IO; + if (url_feof(s->pb)) + return AVERROR(EIO); /* get the next chunk preamble */ if ((ret = get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) != RoQ_CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); chunk_type = AV_RL16(&preamble[0]); chunk_size = AV_RL32(&preamble[2]); @@ -215,7 +212,7 @@ static int roq_read_packet(AVFormatContext *s, url_fseek(pb, codebook_size, SEEK_CUR); if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); chunk_size = AV_RL32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 + codebook_size; @@ -225,7 +222,7 @@ static int roq_read_packet(AVFormatContext *s, /* load up the packet */ ret= av_get_packet(pb, pkt, chunk_size); if (ret != chunk_size) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = roq->video_stream_index; pkt->pts = roq->video_pts; @@ -238,7 +235,7 @@ static int roq_read_packet(AVFormatContext *s, case RoQ_QUAD_VQ: /* load up the packet */ if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE)) - return AVERROR_IO; + return AVERROR(EIO); /* copy over preamble */ memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE); @@ -258,7 +255,7 @@ static int roq_read_packet(AVFormatContext *s, ret = get_buffer(pb, pkt->data + RoQ_CHUNK_PREAMBLE_SIZE, chunk_size); if (ret != chunk_size) - ret = AVERROR_IO; + ret = AVERROR(EIO); packet_read = 1; break; @@ -275,7 +272,7 @@ static int roq_read_packet(AVFormatContext *s, static int roq_read_close(AVFormatContext *s) { -// RoqDemuxContext *roq = (RoqDemuxContext *)s->priv_data; +// RoqDemuxContext *roq = s->priv_data; return 0; } diff --git a/contrib/ffmpeg/libavformat/img2.c b/contrib/ffmpeg/libavformat/img2.c index fa67ee742..6e846df66 100644 --- a/contrib/ffmpeg/libavformat/img2.c +++ b/contrib/ffmpeg/libavformat/img2.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" +#include "avstring.h" typedef struct { int img_first; @@ -40,6 +41,7 @@ static const IdStrMap img_tags[] = { { CODEC_ID_MJPEG , "jpg"}, { CODEC_ID_LJPEG , "ljpg"}, { CODEC_ID_PNG , "png"}, + { CODEC_ID_PNG , "mng"}, { CODEC_ID_PPM , "ppm"}, { CODEC_ID_PGM , "pgm"}, { CODEC_ID_PGMYUV , "pgmyuv"}, @@ -54,6 +56,16 @@ static const IdStrMap img_tags[] = { { CODEC_ID_GIF , "gif"}, { CODEC_ID_TARGA , "tga"}, { CODEC_ID_TIFF , "tiff"}, + { CODEC_ID_SGI , "sgi"}, + { CODEC_ID_PTX , "ptx"}, + { CODEC_ID_PCX , "pcx"}, + { CODEC_ID_SUNRAST , "sun"}, + { CODEC_ID_SUNRAST , "ras"}, + { CODEC_ID_SUNRAST , "rs"}, + { CODEC_ID_SUNRAST , "im1"}, + { CODEC_ID_SUNRAST , "im8"}, + { CODEC_ID_SUNRAST , "im24"}, + { CODEC_ID_SUNRAST , "sunras"}, {0, NULL} }; @@ -180,7 +192,7 @@ static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) return AVERROR(ENOMEM); } - pstrcpy(s->path, sizeof(s->path), s1->filename); + av_strlcpy(s->path, s1->filename, sizeof(s->path)); s->img_number = 0; s->img_count = 0; @@ -189,7 +201,7 @@ static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) s->is_pipe = 0; else{ s->is_pipe = 1; - st->need_parsing= 1; + st->need_parsing = AVSTREAM_PARSE_FULL; } if (!ap->time_base.num) { @@ -205,7 +217,7 @@ static int img_read_header(AVFormatContext *s1, AVFormatParameters *ap) if (!s->is_pipe) { if (find_image_range(&first_index, &last_index, s->path) < 0) - return AVERROR_IO; + return AVERROR(EIO); s->img_first = first_index; s->img_last = last_index; s->img_number = first_index; @@ -236,7 +248,7 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) char filename[1024]; int i; int size[3]={0}, ret[3]={0}; - ByteIOContext f1[3], *f[3]= {&f1[0], &f1[1], &f1[2]}; + ByteIOContext *f[3]; AVCodecContext *codec= s1->streams[0]->codec; if (!s->is_pipe) { @@ -246,10 +258,10 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) } if (av_get_frame_filename(filename, sizeof(filename), s->path, s->img_number)<0 && s->img_number > 1) - return AVERROR_IO; + return AVERROR(EIO); for(i=0; i<3; i++){ - if (url_fopen(f[i], filename, URL_RDONLY) < 0) - return AVERROR_IO; + if (url_fopen(&f[i], filename, URL_RDONLY) < 0) + return AVERROR(EIO); size[i]= url_fsize(f[i]); if(codec->codec_id != CODEC_ID_RAWVIDEO) @@ -260,9 +272,9 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) if(codec->codec_id == CODEC_ID_RAWVIDEO && !codec->width) infer_size(&codec->width, &codec->height, size[0]); } else { - f[0] = &s1->pb; + f[0] = s1->pb; if (url_feof(f[0])) - return AVERROR_IO; + return AVERROR(EIO); size[0]= 4096; } @@ -283,7 +295,7 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt) if (ret[0] <= 0 || ret[1]<0 || ret[2]<0) { av_free_packet(pkt); - return AVERROR_IO; /* signal EOF */ + return AVERROR(EIO); /* signal EOF */ } else { s->img_count++; s->img_number++; @@ -305,7 +317,7 @@ static int img_write_header(AVFormatContext *s) VideoData *img = s->priv_data; img->img_number = 1; - pstrcpy(img->path, sizeof(img->path), s->filename); + av_strlcpy(img->path, s->filename, sizeof(img->path)); /* find format */ if (s->oformat->flags & AVFMT_NOFILE) @@ -319,7 +331,7 @@ static int img_write_header(AVFormatContext *s) static int img_write_packet(AVFormatContext *s, AVPacket *pkt) { VideoData *img = s->priv_data; - ByteIOContext pb1[3], *pb[3]= {&pb1[0], &pb1[1], &pb1[2]}; + ByteIOContext *pb[3]; char filename[1024]; AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec; int i; @@ -327,17 +339,17 @@ static int img_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) - return AVERROR_IO; + return AVERROR(EIO); for(i=0; i<3; i++){ - if (url_fopen(pb[i], filename, URL_WRONLY) < 0) - return AVERROR_IO; + if (url_fopen(&pb[i], filename, URL_WRONLY) < 0) + return AVERROR(EIO); if(codec->codec_id != CODEC_ID_RAWVIDEO) break; filename[ strlen(filename) - 1 ]= 'U' + i; } } else { - pb[0] = &s->pb; + pb[0] = s->pb; } if(codec->codec_id == CODEC_ID_RAWVIDEO){ diff --git a/contrib/ffmpeg/libavformat/ipmovie.c b/contrib/ffmpeg/libavformat/ipmovie.c index 975bfd36b..311f29f49 100644 --- a/contrib/ffmpeg/libavformat/ipmovie.c +++ b/contrib/ffmpeg/libavformat/ipmovie.c @@ -507,8 +507,6 @@ static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb, static int ipmovie_probe(AVProbeData *p) { - if (p->buf_size < IPMOVIE_SIGNATURE_SIZE) - return 0; if (strncmp(p->buf, IPMOVIE_SIGNATURE, IPMOVIE_SIGNATURE_SIZE) != 0) return 0; @@ -518,8 +516,8 @@ static int ipmovie_probe(AVProbeData *p) static int ipmovie_read_header(AVFormatContext *s, AVFormatParameters *ap) { - IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + IPMVEContext *ipmovie = s->priv_data; + ByteIOContext *pb = s->pb; AVPacket pkt; AVStream *st; unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; @@ -541,7 +539,7 @@ static int ipmovie_read_header(AVFormatContext *s, * it; if it is the first video chunk, this is a silent file */ if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); chunk_type = AV_RL16(&chunk_preamble[2]); url_fseek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR); @@ -553,7 +551,7 @@ static int ipmovie_read_header(AVFormatContext *s, /* initialize the stream decoders */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, 90000); ipmovie->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; @@ -568,7 +566,7 @@ static int ipmovie_read_header(AVFormatContext *s, if (ipmovie->audio_type) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, 90000); ipmovie->audio_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_AUDIO; @@ -590,17 +588,17 @@ static int ipmovie_read_header(AVFormatContext *s, static int ipmovie_read_packet(AVFormatContext *s, AVPacket *pkt) { - IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + IPMVEContext *ipmovie = s->priv_data; + ByteIOContext *pb = s->pb; int ret; ret = process_ipmovie_chunk(ipmovie, pb, pkt); if (ret == CHUNK_BAD) ret = AVERROR_INVALIDDATA; else if (ret == CHUNK_EOF) - ret = AVERROR_IO; + ret = AVERROR(EIO); else if (ret == CHUNK_NOMEM) - ret = AVERROR_NOMEM; + ret = AVERROR(ENOMEM); else if (ret == CHUNK_VIDEO) ret = 0; else @@ -611,7 +609,7 @@ static int ipmovie_read_packet(AVFormatContext *s, static int ipmovie_read_close(AVFormatContext *s) { -// IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; +// IPMVEContext *ipmovie = s->priv_data; return 0; } diff --git a/contrib/ffmpeg/libavformat/isom.c b/contrib/ffmpeg/libavformat/isom.c index f913bc0a9..f6e81cdcf 100644 --- a/contrib/ffmpeg/libavformat/isom.c +++ b/contrib/ffmpeg/libavformat/isom.c @@ -26,12 +26,13 @@ #include "isom.h" /* http://www.mp4ra.org */ +/* ordered by muxing preference */ const AVCodecTag ff_mp4_obj_type[] = { { CODEC_ID_MPEG4 , 32 }, { CODEC_ID_H264 , 33 }, { CODEC_ID_AAC , 64 }, - { CODEC_ID_MPEG2VIDEO, 96 }, /* MPEG2 Simple */ { CODEC_ID_MPEG2VIDEO, 97 }, /* MPEG2 Main */ + { CODEC_ID_MPEG2VIDEO, 96 }, /* MPEG2 Simple */ { CODEC_ID_MPEG2VIDEO, 98 }, /* MPEG2 SNR */ { CODEC_ID_MPEG2VIDEO, 99 }, /* MPEG2 Spatial */ { CODEC_ID_MPEG2VIDEO, 100 }, /* MPEG2 High */ @@ -39,22 +40,16 @@ const AVCodecTag ff_mp4_obj_type[] = { { CODEC_ID_AAC , 102 }, /* MPEG2 AAC Main */ { CODEC_ID_AAC , 103 }, /* MPEG2 AAC Low */ { CODEC_ID_AAC , 104 }, /* MPEG2 AAC SSR */ + { CODEC_ID_MP3 , 107 }, /* 11172-3 */ { CODEC_ID_MP3 , 105 }, /* 13818-3 */ { CODEC_ID_MPEG1VIDEO, 106 }, /* 11172-2 */ - { CODEC_ID_MP3 , 107 }, /* 11172-3 */ { CODEC_ID_MJPEG , 108 }, /* 10918-1 */ { CODEC_ID_PNG , 109 }, { CODEC_ID_JPEG2000 , 110 }, /* 15444-1 */ { CODEC_ID_VC1 , 163 }, - { CODEC_ID_VORBIS , 221 }, - { CODEC_ID_PCM_S16LE , 224 }, + { CODEC_ID_VORBIS , 221 }, /* non standard, gpac uses it */ + { CODEC_ID_DVD_SUBTITLE, 224 }, /* non standard, see unsupported-embedded-subs-2.mp4 */ { CODEC_ID_QCELP , 225 }, - { CODEC_ID_AC3 , 226 }, - { CODEC_ID_PCM_ALAW , 227 }, - { CODEC_ID_PCM_MULAW , 228 }, - { CODEC_ID_PCM_S16BE , 230 }, - { CODEC_ID_H263 , 242 }, - { CODEC_ID_H261 , 243 }, { 0, 0 }, }; @@ -70,6 +65,7 @@ const AVCodecTag codec_movvideo_tags[] = { { CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */ { CODEC_ID_MJPEG, MKTAG('A', 'V', 'D', 'J') }, /* MJPEG with alpha-channel (AVID JFIF meridien compressed) */ /* { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, *//* MJPEG with alpha-channel (AVID ABVB/Truevision NuVista) */ + { CODEC_ID_MJPEG, MKTAG('d', 'm', 'b', '1') }, /* Motion JPEG OpenDML */ { CODEC_ID_MJPEGB, MKTAG('m', 'j', 'p', 'b') }, /* Motion-JPEG (format B) */ { CODEC_ID_SVQ1, MKTAG('S', 'V', 'Q', '1') }, /* Sorenson Video v1 */ @@ -111,8 +107,11 @@ const AVCodecTag codec_movvideo_tags[] = { { CODEC_ID_MPEG2VIDEO, MKTAG('h', 'd', 'v', '3') }, /* HDV produced by FCP */ { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '5', 'n') }, /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */ { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '5', 'p') }, /* MPEG2 IMX PAL 625/50 50mb/s produced by FCP */ + { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '4', 'n') }, /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */ + { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '4', 'p') }, /* MPEG2 IMX PAL 625/50 40mb/s produced by FCP */ { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'n') }, /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */ { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'x', '3', 'p') }, /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */ + { CODEC_ID_MPEG2VIDEO, MKTAG('x', 'd', 'v', '2') }, /* XDCAM HD 1080i60 */ { CODEC_ID_MPEG2VIDEO, MKTAG('A', 'V', 'm', 'p') }, /* AVID IMX PAL */ //{ CODEC_ID_JPEG2000, MKTAG('m', 'j', 'p', '2') }, /* JPEG 2000 produced by FCP */ @@ -125,6 +124,7 @@ const AVCodecTag codec_movvideo_tags[] = { { CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') }, /* SMPTE RP 2025 */ { CODEC_ID_DNXHD, MKTAG('A', 'V', 'd', 'n') }, /* AVID DNxHD */ + { CODEC_ID_SGI, MKTAG('s', 'g', 'i', ' ') }, /* SGI */ { CODEC_ID_NONE, 0 }, }; @@ -135,11 +135,11 @@ const AVCodecTag codec_movaudio_tags[] = { { CODEC_ID_PCM_S24BE, MKTAG('i', 'n', '2', '4') }, { CODEC_ID_PCM_S24LE, MKTAG('i', 'n', '2', '4') }, { CODEC_ID_PCM_S16BE, MKTAG('t', 'w', 'o', 's') }, /* 16 bits */ - { CODEC_ID_PCM_S16BE, MKTAG('N', 'O', 'N', 'E') }, /* uncompressed */ { CODEC_ID_PCM_S16LE, MKTAG('s', 'o', 'w', 't') }, /* */ { CODEC_ID_PCM_S16LE, MKTAG('l', 'p', 'c', 'm') }, { CODEC_ID_PCM_S8, MKTAG('s', 'o', 'w', 't') }, { CODEC_ID_PCM_U8, MKTAG('r', 'a', 'w', ' ') }, /* 8 bits unsigned */ + { CODEC_ID_PCM_U8, MKTAG('N', 'O', 'N', 'E') }, /* uncompressed */ { CODEC_ID_PCM_MULAW, MKTAG('u', 'l', 'a', 'w') }, /* */ { CODEC_ID_PCM_ALAW, MKTAG('a', 'l', 'a', 'w') }, /* */ @@ -171,6 +171,12 @@ const AVCodecTag codec_movaudio_tags[] = { { CODEC_ID_NONE, 0 }, }; +const AVCodecTag ff_codec_movsubtitle_tags[] = { + { CODEC_ID_MOV_TEXT, MKTAG('t', 'e', 'x', 't') }, + { CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') }, + { CODEC_ID_NONE, 0 }, +}; + /* map numeric codes from mdhd atom to ISO 639 */ /* cf. QTFileFormat.pdf p253, qtff.pdf p205 */ /* http://developer.apple.com/documentation/mac/Text/Text-368.html */ diff --git a/contrib/ffmpeg/libavformat/isom.h b/contrib/ffmpeg/libavformat/isom.h index efcb1fc42..7a66ce524 100644 --- a/contrib/ffmpeg/libavformat/isom.h +++ b/contrib/ffmpeg/libavformat/isom.h @@ -24,17 +24,20 @@ #ifndef FFMPEG_ISOM_H #define FFMPEG_ISOM_H +#include "riff.h" + /* isom.c */ extern const AVCodecTag ff_mp4_obj_type[]; extern const AVCodecTag codec_movvideo_tags[]; extern const AVCodecTag codec_movaudio_tags[]; +extern const AVCodecTag ff_codec_movsubtitle_tags[]; int ff_mov_iso639_to_lang(const char *lang, int mp4); int ff_mov_lang_to_iso639(int code, char *to); -typedef struct Time2Sample{ +typedef struct { int count; int duration; -}Time2Sample; +} MOV_stts_t; #endif /* FFMPEG_ISOM_H */ diff --git a/contrib/ffmpeg/libavformat/libnut.c b/contrib/ffmpeg/libavformat/libnut.c index 0f7b879a9..f5423069f 100644 --- a/contrib/ffmpeg/libavformat/libnut.c +++ b/contrib/ffmpeg/libavformat/libnut.c @@ -54,7 +54,7 @@ static int av_write(void * h, size_t len, const uint8_t * buf) { static int nut_write_header(AVFormatContext * avf) { NUTContext * priv = avf->priv_data; - ByteIOContext * bc = &avf->pb; + ByteIOContext * bc = avf->pb; nut_muxer_opts_t mopts = { .output = { .priv = bc, @@ -137,7 +137,7 @@ static int nut_write_packet(AVFormatContext * avf, AVPacket * pkt) { } static int nut_write_trailer(AVFormatContext * avf) { - ByteIOContext * bc = &avf->pb; + ByteIOContext * bc = avf->pb; NUTContext * priv = avf->priv_data; int i; @@ -151,7 +151,7 @@ static int nut_write_trailer(AVFormatContext * avf) { } AVOutputFormat libnut_muxer = { - "nut", + "libnut", "nut format", "video/x-nut", "nut", @@ -166,7 +166,7 @@ AVOutputFormat libnut_muxer = { #endif //CONFIG_MUXERS static int nut_probe(AVProbeData *p) { - if (p->buf_size >= ID_LENGTH && !memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX; + if (!memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX; return 0; } @@ -187,7 +187,7 @@ static off_t av_seek(void * h, long long pos, int whence) { static int nut_read_header(AVFormatContext * avf, AVFormatParameters * ap) { NUTContext * priv = avf->priv_data; - ByteIOContext * bc = &avf->pb; + ByteIOContext * bc = avf->pb; nut_demuxer_opts_t dopts = { .input = { .priv = bc, @@ -272,7 +272,7 @@ static int nut_read_packet(AVFormatContext * avf, AVPacket * pkt) { if (pd.flags & NUT_FLAG_KEY) pkt->flags |= PKT_FLAG_KEY; pkt->pts = pd.pts; pkt->stream_index = pd.stream; - pkt->pos = url_ftell(&avf->pb); + pkt->pos = url_ftell(avf->pb); ret = nut_read_frame(priv->nut, &pd.len, pkt->data); @@ -298,7 +298,7 @@ static int nut_read_close(AVFormatContext *s) { } AVInputFormat libnut_demuxer = { - "nut", + "libnut", "nut format", sizeof(NUTContext), nut_probe, diff --git a/contrib/ffmpeg/libavformat/lmlm4.c b/contrib/ffmpeg/libavformat/lmlm4.c new file mode 100644 index 000000000..6646a412b --- /dev/null +++ b/contrib/ffmpeg/libavformat/lmlm4.c @@ -0,0 +1,126 @@ +/* + * Linux Media Labs MPEG-4 demuxer + * Copyright (c) 2008 Ivo van Poorten + * + * 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 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" + +#define LMLM4_I_FRAME 0x00 +#define LMLM4_P_FRAME 0x01 +#define LMLM4_B_FRAME 0x02 +#define LMLM4_INVALID 0x03 +#define LMLM4_MPEG1L2 0x04 + +#define LMLM4_MAX_PACKET_SIZE 1024 * 1024 + +static int lmlm4_probe(AVProbeData * pd) { + unsigned char *buf = pd->buf; + unsigned int frame_type, packet_size; + + frame_type = AV_RB16(buf+2); + packet_size = AV_RB32(buf+4); + + if (!AV_RB16(buf) && frame_type <= LMLM4_MPEG1L2 && packet_size && + frame_type != LMLM4_INVALID && packet_size <= LMLM4_MAX_PACKET_SIZE) { + + if (frame_type == LMLM4_MPEG1L2) { + if ((AV_RB16(buf+8) & 0xfffe) != 0xfffc) + return 0; + /* I could calculate the audio framesize and compare with + * packet_size-8, but that seems overkill */ + return AVPROBE_SCORE_MAX / 3; + } else if (AV_RB24(buf+8) == 0x000001) { /* PES Signal */ + return AVPROBE_SCORE_MAX / 5; + } + } + + return 0; +} + +static int lmlm4_read_header(AVFormatContext *s, AVFormatParameters *ap) { + AVStream *st; + + if (!(st = av_new_stream(s, 0))) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_MPEG4; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + av_set_pts_info(st, 64, 1001, 30000); + + if (!(st = av_new_stream(s, 1))) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_MP2; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + + /* the parameters will be extracted from the compressed bitstream */ + return 0; +} + +static int lmlm4_read_packet(AVFormatContext *s, AVPacket *pkt) { + ByteIOContext *pb = s->pb; + int ret; + unsigned int frame_type, packet_size, padding, frame_size; + + get_be16(pb); /* channel number */ + frame_type = get_be16(pb); + packet_size = get_be32(pb); + padding = -packet_size & 511; + frame_size = packet_size - 8; + + if (frame_type > LMLM4_MPEG1L2 || frame_type == LMLM4_INVALID) { + av_log(s, AV_LOG_ERROR, "invalid or unsupported frame_type\n"); + return AVERROR(EIO); + } + if (packet_size > LMLM4_MAX_PACKET_SIZE) { + av_log(s, AV_LOG_ERROR, "packet size exceeds maximum\n"); + return AVERROR(EIO); + } + + if ((ret = av_get_packet(pb, pkt, frame_size)) <= 0) + return AVERROR(EIO); + + url_fskip(pb, padding); + + switch (frame_type) { + case LMLM4_I_FRAME: + pkt->flags = PKT_FLAG_KEY; + case LMLM4_P_FRAME: + case LMLM4_B_FRAME: + pkt->stream_index = 0; + break; + case LMLM4_MPEG1L2: + pkt->stream_index = 1; + break; + } + + return ret; +} + +AVInputFormat lmlm4_demuxer = { + "lmlm4", + "lmlm4 raw format", + 0, + lmlm4_probe, + lmlm4_read_header, + lmlm4_read_packet, +}; diff --git a/contrib/ffmpeg/libavformat/matroska.c b/contrib/ffmpeg/libavformat/matroska.c index 591530490..b62511f29 100644 --- a/contrib/ffmpeg/libavformat/matroska.c +++ b/contrib/ffmpeg/libavformat/matroska.c @@ -1,5 +1,5 @@ /* - * Matroska file demuxer (no muxer yet) + * Matroska common data * Copyright (c) 2003-2004 The ffmpeg Project * * This file is part of FFmpeg. @@ -19,190 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file matroska.c - * Matroska file demuxer - * by Ronald Bultje <rbultje@ronald.bitfreak.net> - * with a little help from Moritz Bunkus <moritz@bunkus.org> - * Specs available on the matroska project page: - * http://www.matroska.org/. - */ - -#include "avformat.h" -/* For codec_get_id(). */ -#include "riff.h" -#include "intfloat_readwrite.h" - -/* EBML version supported */ -#define EBML_VERSION 1 - -/* top-level master-IDs */ -#define EBML_ID_HEADER 0x1A45DFA3 - -/* IDs in the HEADER master */ -#define EBML_ID_EBMLVERSION 0x4286 -#define EBML_ID_EBMLREADVERSION 0x42F7 -#define EBML_ID_EBMLMAXIDLENGTH 0x42F2 -#define EBML_ID_EBMLMAXSIZELENGTH 0x42F3 -#define EBML_ID_DOCTYPE 0x4282 -#define EBML_ID_DOCTYPEVERSION 0x4287 -#define EBML_ID_DOCTYPEREADVERSION 0x4285 - -/* general EBML types */ -#define EBML_ID_VOID 0xEC - -/* - * Matroska element IDs. max. 32-bit. - */ - -/* toplevel segment */ -#define MATROSKA_ID_SEGMENT 0x18538067 - -/* matroska top-level master IDs */ -#define MATROSKA_ID_INFO 0x1549A966 -#define MATROSKA_ID_TRACKS 0x1654AE6B -#define MATROSKA_ID_CUES 0x1C53BB6B -#define MATROSKA_ID_TAGS 0x1254C367 -#define MATROSKA_ID_SEEKHEAD 0x114D9B74 -#define MATROSKA_ID_CLUSTER 0x1F43B675 - -/* IDs in the info master */ -#define MATROSKA_ID_TIMECODESCALE 0x2AD7B1 -#define MATROSKA_ID_DURATION 0x4489 -#define MATROSKA_ID_TITLE 0x7BA9 -#define MATROSKA_ID_WRITINGAPP 0x5741 -#define MATROSKA_ID_MUXINGAPP 0x4D80 -#define MATROSKA_ID_DATEUTC 0x4461 - -/* ID in the tracks master */ -#define MATROSKA_ID_TRACKENTRY 0xAE - -/* IDs in the trackentry master */ -#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_CODECID 0x86 -#define MATROSKA_ID_CODECPRIVATE 0x63A2 -#define MATROSKA_ID_CODECNAME 0x258688 -#define MATROSKA_ID_CODECINFOURL 0x3B4040 -#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240 -#define MATROSKA_ID_TRACKNAME 0x536E -#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C -#define MATROSKA_ID_TRACKFLAGENABLED 0xB9 -#define MATROSKA_ID_TRACKFLAGDEFAULT 0x88 -#define MATROSKA_ID_TRACKFLAGLACING 0x9C -#define MATROSKA_ID_TRACKMINCACHE 0x6DE7 -#define MATROSKA_ID_TRACKMAXCACHE 0x6DF8 -#define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383 - -/* IDs in the trackvideo master */ -#define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 -#define MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 -#define MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA -#define MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 -#define MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA -#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A -#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9 -#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3 -#define MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524 - -/* IDs in the trackaudio master */ -#define MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 -#define MATROSKA_ID_AUDIOOUTSAMPLINGFREQ 0x78B5 - -#define MATROSKA_ID_AUDIOBITDEPTH 0x6264 -#define MATROSKA_ID_AUDIOCHANNELS 0x9F - -/* ID in the cues master */ -#define MATROSKA_ID_POINTENTRY 0xBB - -/* IDs in the pointentry master */ -#define MATROSKA_ID_CUETIME 0xB3 -#define MATROSKA_ID_CUETRACKPOSITION 0xB7 - -/* IDs in the cuetrackposition master */ -#define MATROSKA_ID_CUETRACK 0xF7 -#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1 - -/* IDs in the tags master */ -/* TODO */ - -/* IDs in the seekhead master */ -#define MATROSKA_ID_SEEKENTRY 0x4DBB - -/* IDs in the seekpoint master */ -#define MATROSKA_ID_SEEKID 0x53AB -#define MATROSKA_ID_SEEKPOSITION 0x53AC - -/* IDs in the cluster master */ -#define MATROSKA_ID_CLUSTERTIMECODE 0xE7 -#define MATROSKA_ID_BLOCKGROUP 0xA0 -#define MATROSKA_ID_SIMPLEBLOCK 0xA3 - -/* IDs in the blockgroup master */ -#define MATROSKA_ID_BLOCK 0xA1 -#define MATROSKA_ID_BLOCKDURATION 0x9B -#define MATROSKA_ID_BLOCKREFERENCE 0xFB - -typedef enum { - MATROSKA_TRACK_TYPE_VIDEO = 0x1, - MATROSKA_TRACK_TYPE_AUDIO = 0x2, - MATROSKA_TRACK_TYPE_COMPLEX = 0x3, - MATROSKA_TRACK_TYPE_LOGO = 0x10, - MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, - MATROSKA_TRACK_TYPE_CONTROL = 0x20, -} MatroskaTrackType; - -typedef enum { - MATROSKA_EYE_MODE_MONO = 0x0, - MATROSKA_EYE_MODE_RIGHT = 0x1, - MATROSKA_EYE_MODE_LEFT = 0x2, - MATROSKA_EYE_MODE_BOTH = 0x3, -} MatroskaEyeMode; - -typedef enum { - MATROSKA_ASPECT_RATIO_MODE_FREE = 0x0, - MATROSKA_ASPECT_RATIO_MODE_KEEP = 0x1, - MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2, -} MatroskaAspectRatioMode; - -/* - * These aren't in any way "matroska-form" things, - * it's just something I use in the muxer/demuxer. - */ - -typedef enum { - MATROSKA_TRACK_ENABLED = (1<<0), - MATROSKA_TRACK_DEFAULT = (1<<1), - MATROSKA_TRACK_LACING = (1<<2), - MATROSKA_TRACK_REAL_V = (1<<4), - MATROSKA_TRACK_REORDER = (1<<8), - MATROSKA_TRACK_SHIFT = (1<<16) -} MatroskaTrackFlags; - -typedef enum { - MATROSKA_VIDEOTRACK_INTERLACED = (MATROSKA_TRACK_SHIFT<<0) -} MatroskaVideoTrackFlags; - -/* - * Matroska Codec IDs. Strings. - */ - -typedef struct CodecTags{ - const char *str; - enum CodecID id; -}CodecTags; +#include "matroska.h" -#define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC" -#define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" - -static CodecTags codec_tags[]={ +const CodecTags ff_mkv_codec_tags[]={ // {"V_MS/VFW/FOURCC" , CODEC_ID_NONE}, {"V_UNCOMPRESSED" , CODEC_ID_RAWVIDEO}, - {"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4}, {"V_MPEG4/ISO/ASP" , CODEC_ID_MPEG4}, + {"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4}, {"V_MPEG4/ISO/AP" , CODEC_ID_MPEG4}, {"V_MPEG4/ISO/AVC" , CODEC_ID_H264}, {"V_MPEG4/MS/V3" , CODEC_ID_MSMPEG4V3}, @@ -214,12 +37,13 @@ static CodecTags codec_tags[]={ {"V_REAL/RV30" , CODEC_ID_RV30}, {"V_REAL/RV40" , CODEC_ID_RV40}, {"V_THEORA" , CODEC_ID_THEORA}, + {"V_SNOW" , CODEC_ID_SNOW}, /* TODO: Real/Quicktime */ // {"A_MS/ACM" , CODEC_ID_NONE}, - {"A_MPEG/L1" , CODEC_ID_MP3}, - {"A_MPEG/L2" , CODEC_ID_MP3}, {"A_MPEG/L3" , CODEC_ID_MP3}, + {"A_MPEG/L2" , CODEC_ID_MP2}, + {"A_MPEG/L1" , CODEC_ID_MP2}, {"A_PCM/INT/BIG" , CODEC_ID_PCM_U16BE}, {"A_PCM/INT/LIT" , CODEC_ID_PCM_U16LE}, // {"A_PCM/FLOAT/IEEE" , CODEC_ID_NONE}, @@ -230,2621 +54,32 @@ static CodecTags codec_tags[]={ {"A_FLAC" , CODEC_ID_FLAC}, {"A_WAVPACK4" , CODEC_ID_WAVPACK}, {"A_TTA1" , CODEC_ID_TTA}, - {NULL , CODEC_ID_NONE} + {"A_REAL/14_4" , CODEC_ID_RA_144}, + {"A_REAL/28_8" , CODEC_ID_RA_288}, + {"A_REAL/ATRC" , CODEC_ID_ATRAC3}, + {"A_REAL/COOK" , CODEC_ID_COOK}, +// {"A_REAL/SIPR" , CODEC_ID_SIPRO}, + + {"S_TEXT/UTF8" , CODEC_ID_TEXT}, + {"S_TEXT/ASCII" , CODEC_ID_TEXT}, + {"S_TEXT/ASS" , CODEC_ID_SSA}, + {"S_TEXT/SSA" , CODEC_ID_SSA}, + {"S_ASS" , CODEC_ID_SSA}, + {"S_SSA" , CODEC_ID_SSA}, + {"S_VOBSUB" , CODEC_ID_DVD_SUBTITLE}, + + {"" , CODEC_ID_NONE} /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */ }; -/* max. depth in the EBML tree structure */ -#define EBML_MAX_DEPTH 16 - -typedef struct Track { - MatroskaTrackType type; - - /* Unique track number and track ID. stream_index is the index that - * the calling app uses for this track. */ - uint32_t num, - uid, - stream_index; - - char *name, - *language; - - char *codec_id, - *codec_name; - - unsigned char *codec_priv; - int codec_priv_size; - - uint64_t default_duration; - MatroskaTrackFlags flags; -} MatroskaTrack; - -typedef struct MatroskaVideoTrack { - MatroskaTrack track; - - int pixel_width, - pixel_height, - display_width, - display_height; - - uint32_t fourcc; - - MatroskaAspectRatioMode ar_mode; - MatroskaEyeMode eye_mode; - - //.. -} MatroskaVideoTrack; - -typedef struct MatroskaAudioTrack { - MatroskaTrack track; - - int channels, - bitdepth, - internal_samplerate, - samplerate; - //.. -} MatroskaAudioTrack; - -typedef struct MatroskaSubtitleTrack { - MatroskaTrack track; - - //.. -} MatroskaSubtitleTrack; - -#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \ - sizeof(MatroskaAudioTrack)), \ - sizeof(MatroskaSubtitleTrack))) - -typedef struct MatroskaLevel { - uint64_t start, length; -} MatroskaLevel; - -typedef struct MatroskaDemuxIndex { - uint64_t pos; /* of the corresponding *cluster*! */ - uint16_t track; /* reference to 'num' */ - uint64_t time; /* in nanoseconds */ -} MatroskaDemuxIndex; - -typedef struct MatroskaDemuxContext { - AVFormatContext *ctx; - - /* ebml stuff */ - int num_levels; - MatroskaLevel levels[EBML_MAX_DEPTH]; - int level_up; - - /* matroska stuff */ - char *writing_app, - *muxing_app; - int64_t created; - - /* timescale in the file */ - int64_t time_scale; - - /* position (time, ns) */ - int64_t pos; - - /* num_streams is the number of streams that av_new_stream() was called - * for ( = that are available to the calling program). */ - int num_tracks, num_streams; - MatroskaTrack *tracks[MAX_STREAMS]; - - /* cache for ID peeking */ - uint32_t peek_id; - - /* byte position of the segment inside the stream */ - offset_t segment_start; - - /* The packet queue. */ - AVPacket **packets; - int num_packets; - /* Second packet queue used to reorder pts of some video track. */ - AVPacket **packets_reorder; - int num_packets_reorder; - uint64_t reorder_max_pts; - - /* have we already parse metadata/cues/clusters? */ - int metadata_parsed, - index_parsed, - done; - - /* The index for seeking. */ - int num_indexes; - MatroskaDemuxIndex *index; -} MatroskaDemuxContext; - -/* - * The first few functions handle EBML file parsing. The rest - * is the document interpretation. Matroska really just is a - * EBML file. - */ - -/* - * Return: the amount of levels in the hierarchy that the - * current element lies higher than the previous one. - * The opposite isn't done - that's auto-done using master - * element reading. - */ - -static int -ebml_read_element_level_up (MatroskaDemuxContext *matroska) -{ - ByteIOContext *pb = &matroska->ctx->pb; - offset_t pos = url_ftell(pb); - int num = 0; - - while (matroska->num_levels > 0) { - MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; - - if (pos >= level->start + level->length) { - matroska->num_levels--; - num++; - } else { - break; - } - } - - return num; -} - -/* - * Read: an "EBML number", which is defined as a variable-length - * array of bytes. The first byte indicates the length by giving a - * number of 0-bits followed by a one. The position of the first - * "one" bit inside the first byte indicates the length of this - * number. - * Returns: num. of bytes read. < 0 on error. - */ - -static int -ebml_read_num (MatroskaDemuxContext *matroska, - int max_size, - uint64_t *number) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int len_mask = 0x80, read = 1, n = 1; - int64_t total = 0; - - /* the first byte tells us the length in bytes - get_byte() can normally - * return 0, but since that's not a valid first ebmlID byte, we can - * use it safely here to catch EOS. */ - if (!(total = get_byte(pb))) { - /* we might encounter EOS here */ - if (!url_feof(pb)) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", - pos, pos); - } - return AVERROR_IO; /* EOS or actual I/O error */ - } - - /* get the length of the EBML number */ - while (read <= max_size && !(total & len_mask)) { - read++; - len_mask >>= 1; - } - if (read > max_size) { - offset_t pos = url_ftell(pb) - 1; - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", - (uint8_t) total, pos, pos); - return AVERROR_INVALIDDATA; - } - - /* read out length */ - total &= ~len_mask; - while (n++ < read) - total = (total << 8) | get_byte(pb); - - *number = total; - - return read; -} - -/* - * Read: the element content data ID. - * Return: the number of bytes read or < 0 on error. - */ - -static int -ebml_read_element_id (MatroskaDemuxContext *matroska, - uint32_t *id, - int *level_up) -{ - int read; - uint64_t total; - - /* if we re-call this, use our cached ID */ - if (matroska->peek_id != 0) { - if (level_up) - *level_up = 0; - *id = matroska->peek_id; - return 0; - } - - /* read out the "EBML number", include tag in ID */ - if ((read = ebml_read_num(matroska, 4, &total)) < 0) - return read; - *id = matroska->peek_id = total | (1 << (read * 7)); - - /* level tracking */ - if (level_up) - *level_up = ebml_read_element_level_up(matroska); - - return read; -} - -/* - * Read: element content length. - * Return: the number of bytes read or < 0 on error. - */ - -static int -ebml_read_element_length (MatroskaDemuxContext *matroska, - uint64_t *length) -{ - /* clear cache since we're now beyond that data point */ - matroska->peek_id = 0; - - /* read out the "EBML number", include tag in ID */ - return ebml_read_num(matroska, 8, length); -} - -/* - * Return: the ID of the next element, or 0 on error. - * Level_up contains the amount of levels that this - * next element lies higher than the previous one. - */ - -static uint32_t -ebml_peek_id (MatroskaDemuxContext *matroska, - int *level_up) -{ - uint32_t id; - - assert(level_up != NULL); - - if (ebml_read_element_id(matroska, &id, level_up) < 0) - return 0; - - return id; -} - -/* - * Seek to a given offset. - * 0 is success, -1 is failure. - */ - -static int -ebml_read_seek (MatroskaDemuxContext *matroska, - offset_t offset) -{ - ByteIOContext *pb = &matroska->ctx->pb; - - /* clear ID cache, if any */ - matroska->peek_id = 0; - - return (url_fseek(pb, offset, SEEK_SET) == offset) ? 0 : -1; -} - -/* - * Skip the next element. - * 0 is success, -1 is failure. - */ - -static int -ebml_read_skip (MatroskaDemuxContext *matroska) -{ - ByteIOContext *pb = &matroska->ctx->pb; - uint32_t id; - uint64_t length; - int res; - - if ((res = ebml_read_element_id(matroska, &id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &length)) < 0) - return res; - - url_fskip(pb, length); - - return 0; -} - -/* - * Read the next element as an unsigned int. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_uint (MatroskaDemuxContext *matroska, - uint32_t *id, - uint64_t *num) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int n = 0, size, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - if (size < 1 || size > 8) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid uint element size %d at position %"PRId64" (0x%"PRIx64")\n", - size, pos, pos); - return AVERROR_INVALIDDATA; - } - - /* big-endian ordening; build up number */ - *num = 0; - while (n++ < size) - *num = (*num << 8) | get_byte(pb); - - return 0; -} - -/* - * Read the next element as a signed int. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_sint (MatroskaDemuxContext *matroska, - uint32_t *id, - int64_t *num) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int size, n = 1, negative = 0, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - if (size < 1 || size > 8) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid sint element size %d at position %"PRId64" (0x%"PRIx64")\n", - size, pos, pos); - return AVERROR_INVALIDDATA; - } - if ((*num = get_byte(pb)) & 0x80) { - negative = 1; - *num &= ~0x80; - } - while (n++ < size) - *num = (*num << 8) | get_byte(pb); - - /* make signed */ - if (negative) - *num = *num - (1LL << ((8 * size) - 1)); - - return 0; -} - -/* - * Read the next element as a float. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_float (MatroskaDemuxContext *matroska, - uint32_t *id, - double *num) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int size, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - - if (size == 4) { - *num= av_int2flt(get_be32(pb)); - } else if(size==8){ - *num= av_int2dbl(get_be64(pb)); - } else{ - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid float element size %d at position %"PRIu64" (0x%"PRIx64")\n", - size, pos, pos); - return AVERROR_INVALIDDATA; - } - - return 0; -} - -/* - * Read the next element as an ASCII string. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_ascii (MatroskaDemuxContext *matroska, - uint32_t *id, - char **str) -{ - ByteIOContext *pb = &matroska->ctx->pb; - int size, res; - uint64_t rlength; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - size = rlength; - - /* ebml strings are usually not 0-terminated, so we allocate one - * byte more, read the string and NULL-terminate it ourselves. */ - if (size < 0 || !(*str = av_malloc(size + 1))) { - av_log(matroska->ctx, AV_LOG_ERROR, "Memory allocation failed\n"); - return AVERROR_NOMEM; - } - if (get_buffer(pb, (uint8_t *) *str, size) != size) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); - return AVERROR_IO; - } - (*str)[size] = '\0'; - - return 0; -} - -/* - * Read the next element as a UTF-8 string. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_utf8 (MatroskaDemuxContext *matroska, - uint32_t *id, - char **str) -{ - return ebml_read_ascii(matroska, id, str); -} - -/* - * Read the next element as a date (nanoseconds since 1/1/2000). - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_date (MatroskaDemuxContext *matroska, - uint32_t *id, - int64_t *date) -{ - return ebml_read_sint(matroska, id, date); -} - -/* - * Read the next element, but only the header. The contents - * are supposed to be sub-elements which can be read separately. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_master (MatroskaDemuxContext *matroska, - uint32_t *id) -{ - ByteIOContext *pb = &matroska->ctx->pb; - uint64_t length; - MatroskaLevel *level; - int res; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &length)) < 0) - return res; - - /* protect... (Heaven forbids that the '>' is true) */ - if (matroska->num_levels >= EBML_MAX_DEPTH) { - av_log(matroska->ctx, AV_LOG_ERROR, - "File moves beyond max. allowed depth (%d)\n", EBML_MAX_DEPTH); - return AVERROR_NOTSUPP; - } - - /* remember level */ - level = &matroska->levels[matroska->num_levels++]; - level->start = url_ftell(pb); - level->length = length; - - return 0; -} - -/* - * Read the next element as binary data. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_binary (MatroskaDemuxContext *matroska, - uint32_t *id, - uint8_t **binary, - int *size) -{ - ByteIOContext *pb = &matroska->ctx->pb; - uint64_t rlength; - int res; - - if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || - (res = ebml_read_element_length(matroska, &rlength)) < 0) - return res; - *size = rlength; - - if (!(*binary = av_malloc(*size))) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Memory allocation error\n"); - return AVERROR_NOMEM; - } - - if (get_buffer(pb, *binary, *size) != *size) { - offset_t pos = url_ftell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); - return AVERROR_IO; - } - - return 0; -} - -/* - * Read signed/unsigned "EBML" numbers. - * Return: number of bytes processed, < 0 on error. - * XXX: use ebml_read_num(). - */ - -static int -matroska_ebmlnum_uint (uint8_t *data, - uint32_t size, - uint64_t *num) -{ - int len_mask = 0x80, read = 1, n = 1, num_ffs = 0; - uint64_t total; - - if (size <= 0) - return AVERROR_INVALIDDATA; - - total = data[0]; - while (read <= 8 && !(total & len_mask)) { - read++; - len_mask >>= 1; - } - if (read > 8) - return AVERROR_INVALIDDATA; - - if ((total &= (len_mask - 1)) == len_mask - 1) - num_ffs++; - if (size < read) - return AVERROR_INVALIDDATA; - while (n < read) { - if (data[n] == 0xff) - num_ffs++; - total = (total << 8) | data[n]; - n++; - } - - if (read == num_ffs) - *num = (uint64_t)-1; - else - *num = total; - - return read; -} - -/* - * Same as above, but signed. - */ - -static int -matroska_ebmlnum_sint (uint8_t *data, - uint32_t size, - int64_t *num) -{ - uint64_t unum; - int res; - - /* read as unsigned number first */ - if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0) - return res; - - /* make signed (weird way) */ - if (unum == (uint64_t)-1) - *num = INT64_MAX; - else - *num = unum - ((1LL << ((7 * res) - 1)) - 1); - - return res; -} - -/* - * Read an EBML header. - * 0 is success, < 0 is failure. - */ - -static int -ebml_read_header (MatroskaDemuxContext *matroska, - char **doctype, - int *version) -{ - uint32_t id; - int level_up, res = 0; - - /* default init */ - if (doctype) - *doctype = NULL; - if (version) - *version = 1; - - if (!(id = ebml_peek_id(matroska, &level_up)) || - level_up != 0 || id != EBML_ID_HEADER) { - av_log(matroska->ctx, AV_LOG_ERROR, - "This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER); - return AVERROR_INVALIDDATA; - } - if ((res = ebml_read_master(matroska, &id)) < 0) - return res; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &level_up))) - return AVERROR_IO; - - /* end-of-header */ - if (level_up) - break; - - switch (id) { - /* is our read version uptodate? */ - case EBML_ID_EBMLREADVERSION: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (num > EBML_VERSION) { - av_log(matroska->ctx, AV_LOG_ERROR, - "EBML version %"PRIu64" (> %d) is not supported\n", - num, EBML_VERSION); - return AVERROR_INVALIDDATA; - } - break; - } - - /* we only handle 8 byte lengths at max */ - case EBML_ID_EBMLMAXSIZELENGTH: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (num > sizeof(uint64_t)) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Integers of size %"PRIu64" (> %zd) not supported\n", - num, sizeof(uint64_t)); - return AVERROR_INVALIDDATA; - } - break; - } - - /* we handle 4 byte IDs at max */ - case EBML_ID_EBMLMAXIDLENGTH: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (num > sizeof(uint32_t)) { - av_log(matroska->ctx, AV_LOG_ERROR, - "IDs of size %"PRIu64" (> %zu) not supported\n", - num, sizeof(uint32_t)); - return AVERROR_INVALIDDATA; - } - break; - } - - case EBML_ID_DOCTYPE: { - char *text; - - if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) - return res; - if (doctype) { - if (*doctype) - av_free(*doctype); - *doctype = text; - } else - av_free(text); - break; - } - - case EBML_ID_DOCTYPEREADVERSION: { - uint64_t num; - - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - return res; - if (version) - *version = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown data type 0x%x in EBML header", id); - /* pass-through */ - - case EBML_ID_VOID: - /* we ignore these two, as they don't tell us anything we - * care about */ - case EBML_ID_EBMLVERSION: - case EBML_ID_DOCTYPEVERSION: - res = ebml_read_skip (matroska); - break; - } - } - - return 0; -} - -/* - * Put one packet in an application-supplied AVPacket struct. - * Returns 0 on success or -1 on failure. - */ - -static int -matroska_deliver_packet (MatroskaDemuxContext *matroska, - AVPacket *pkt) -{ - if (matroska->num_packets > 0) { - memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); - av_free(matroska->packets[0]); - if (matroska->num_packets > 1) { - memmove(&matroska->packets[0], &matroska->packets[1], - (matroska->num_packets - 1) * sizeof(AVPacket *)); - matroska->packets = - av_realloc(matroska->packets, (matroska->num_packets - 1) * - sizeof(AVPacket *)); - } else { - av_freep(&matroska->packets); - } - matroska->num_packets--; - return 0; - } - - return -1; -} - -/* - * Put a packet into our internal queue. Will be delivered to the - * user/application during the next get_packet() call. - */ - -static void -matroska_queue_packet (MatroskaDemuxContext *matroska, - AVPacket *pkt) -{ - matroska->packets = - av_realloc(matroska->packets, (matroska->num_packets + 1) * - sizeof(AVPacket *)); - matroska->packets[matroska->num_packets] = pkt; - matroska->num_packets++; -} - -/* - * Put a packet into our internal reordering queue. Will be moved to the - * main packet queue when enough packets are available to reorder pts. - */ - -static void -matroska_queue_packet_reordered (MatroskaDemuxContext *matroska, - AVPacket *pkt, - int is_bframe) -{ - if (matroska->num_packets_reorder && !is_bframe - && pkt->pts > matroska->reorder_max_pts) { - /* reorder pts */ - int i, j, k = 1; - for (j=matroska->num_packets_reorder-1; j && k; j--) { - k = 0; - for (i=0; i<j; i++) { - if (matroska->packets_reorder[i]->pts > matroska->packets_reorder[i+1]->pts) { - FFSWAP(uint64_t, matroska->packets_reorder[i]->pts, matroska->packets_reorder[i+1]->pts); - k = 1; - } - } - } - /* then really queue the packets */ - for (i=0; i<matroska->num_packets_reorder; i++) - matroska_queue_packet (matroska, matroska->packets_reorder[i]); - matroska->num_packets_reorder = 0; - } - matroska->packets_reorder = - av_realloc(matroska->packets_reorder, - (matroska->num_packets_reorder + 1) * sizeof(AVPacket *)); - matroska->packets_reorder[matroska->num_packets_reorder++] = pkt; - if (pkt->pts > matroska->reorder_max_pts) - matroska->reorder_max_pts = pkt->pts; -} - - -/* - * Autodetecting... - */ - -static int -matroska_probe (AVProbeData *p) -{ - uint64_t total = 0; - int len_mask = 0x80, size = 1, n = 1; - uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' }; - - if (p->buf_size < 5) - return 0; - - /* ebml header? */ - if ((p->buf[0] << 24 | p->buf[1] << 16 | - p->buf[2] << 8 | p->buf[3]) != EBML_ID_HEADER) - return 0; - - /* length of header */ - total = p->buf[4]; - while (size <= 8 && !(total & len_mask)) { - size++; - len_mask >>= 1; - } - if (size > 8) - return 0; - total &= (len_mask - 1); - while (n < size) - total = (total << 8) | p->buf[4 + n++]; - - /* does the probe data contain the whole header? */ - if (p->buf_size < 4 + size + total) - return 0; - - /* the header must contain the document type 'matroska'. For now, - * we don't parse the whole header but simply check for the - * availability of that array of characters inside the header. - * Not fully fool-proof, but good enough. */ - for (n = 4 + size; n <= 4 + size + total - sizeof(probe_data); n++) - if (!memcmp (&p->buf[n], probe_data, sizeof(probe_data))) - return AVPROBE_SCORE_MAX; - - return 0; -} - -/* - * From here on, it's all XML-style DTD stuff... Needs no comments. - */ - -static int -matroska_parse_info (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - av_log(matroska->ctx, AV_LOG_DEBUG, "Parsing info...\n"); - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* cluster timecode */ - case MATROSKA_ID_TIMECODESCALE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - matroska->time_scale = num; - break; - } - - case MATROSKA_ID_DURATION: { - double num; - if ((res = ebml_read_float(matroska, &id, &num)) < 0) - break; - matroska->ctx->duration = num * matroska->time_scale * 1000 / AV_TIME_BASE; - break; - } - - case MATROSKA_ID_TITLE: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - strncpy(matroska->ctx->title, text, - sizeof(matroska->ctx->title)-1); - av_free(text); - break; - } - - case MATROSKA_ID_WRITINGAPP: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - matroska->writing_app = text; - break; - } - - case MATROSKA_ID_MUXINGAPP: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - matroska->muxing_app = text; - break; - } - - case MATROSKA_ID_DATEUTC: { - int64_t time; - if ((res = ebml_read_date(matroska, &id, &time)) < 0) - break; - matroska->created = time; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in info header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_add_stream (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - MatroskaTrack *track; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing track, adding stream..,\n"); - - /* Allocate a generic track. As soon as we know its type we'll realloc. */ - track = av_mallocz(MAX_TRACK_SIZE); - matroska->num_tracks++; - - /* start with the master */ - if ((res = ebml_read_master(matroska, &id)) < 0) - return res; - - /* try reading the trackentry headers */ - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up > 0) { - matroska->level_up--; - break; - } - - switch (id) { - /* track number (unique stream ID) */ - case MATROSKA_ID_TRACKNUMBER: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - track->num = num; - break; - } - - /* track UID (unique identifier) */ - case MATROSKA_ID_TRACKUID: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - track->uid = num; - break; - } - - /* track type (video, audio, combined, subtitle, etc.) */ - case MATROSKA_ID_TRACKTYPE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (track->type && track->type != num) { - av_log(matroska->ctx, AV_LOG_INFO, - "More than one tracktype in an entry - skip\n"); - break; - } - track->type = num; - - switch (track->type) { - case MATROSKA_TRACK_TYPE_VIDEO: - case MATROSKA_TRACK_TYPE_AUDIO: - case MATROSKA_TRACK_TYPE_SUBTITLE: - break; - case MATROSKA_TRACK_TYPE_COMPLEX: - case MATROSKA_TRACK_TYPE_LOGO: - case MATROSKA_TRACK_TYPE_CONTROL: - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown or unsupported track type 0x%x\n", - track->type); - track->type = 0; - break; - } - matroska->tracks[matroska->num_tracks - 1] = track; - break; - } - - /* tracktype specific stuff for video */ - case MATROSKA_ID_TRACKVIDEO: { - MatroskaVideoTrack *videotrack; - if (!track->type) - track->type = MATROSKA_TRACK_TYPE_VIDEO; - if (track->type != MATROSKA_TRACK_TYPE_VIDEO) { - av_log(matroska->ctx, AV_LOG_INFO, - "video data in non-video track - ignoring\n"); - res = AVERROR_INVALIDDATA; - break; - } else if ((res = ebml_read_master(matroska, &id)) < 0) - break; - videotrack = (MatroskaVideoTrack *)track; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up > 0) { - matroska->level_up--; - break; - } - - switch (id) { - /* fixme, this should be one-up, but I get it here */ - case MATROSKA_ID_TRACKDEFAULTDURATION: { - uint64_t num; - if ((res = ebml_read_uint (matroska, &id, - &num)) < 0) - break; - track->default_duration = num/matroska->time_scale; - break; - } - - /* video framerate */ - case MATROSKA_ID_VIDEOFRAMERATE: { - double num; - if ((res = ebml_read_float(matroska, &id, - &num)) < 0) - break; - track->default_duration = 1000000000/(matroska->time_scale*num); - break; - } - - /* width of the size to display the video at */ - case MATROSKA_ID_VIDEODISPLAYWIDTH: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->display_width = num; - break; - } - - /* height of the size to display the video at */ - case MATROSKA_ID_VIDEODISPLAYHEIGHT: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->display_height = num; - break; - } - - /* width of the video in the file */ - case MATROSKA_ID_VIDEOPIXELWIDTH: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->pixel_width = num; - break; - } - - /* height of the video in the file */ - case MATROSKA_ID_VIDEOPIXELHEIGHT: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->pixel_height = num; - break; - } - - /* whether the video is interlaced */ - case MATROSKA_ID_VIDEOFLAGINTERLACED: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - if (num) - track->flags |= - MATROSKA_VIDEOTRACK_INTERLACED; - else - track->flags &= - ~MATROSKA_VIDEOTRACK_INTERLACED; - break; - } - - /* stereo mode (whether the video has two streams, - * where one is for the left eye and the other for - * the right eye, which creates a 3D-like - * effect) */ - case MATROSKA_ID_VIDEOSTEREOMODE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - if (num != MATROSKA_EYE_MODE_MONO && - num != MATROSKA_EYE_MODE_LEFT && - num != MATROSKA_EYE_MODE_RIGHT && - num != MATROSKA_EYE_MODE_BOTH) { - av_log(matroska->ctx, AV_LOG_INFO, - "Ignoring unknown eye mode 0x%x\n", - (uint32_t) num); - break; - } - videotrack->eye_mode = num; - break; - } - - /* aspect ratio behaviour */ - case MATROSKA_ID_VIDEOASPECTRATIO: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - if (num != MATROSKA_ASPECT_RATIO_MODE_FREE && - num != MATROSKA_ASPECT_RATIO_MODE_KEEP && - num != MATROSKA_ASPECT_RATIO_MODE_FIXED) { - av_log(matroska->ctx, AV_LOG_INFO, - "Ignoring unknown aspect ratio 0x%x\n", - (uint32_t) num); - break; - } - videotrack->ar_mode = num; - break; - } - - /* colourspace (only matters for raw video) - * fourcc */ - case MATROSKA_ID_VIDEOCOLOURSPACE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - videotrack->fourcc = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown video track header entry " - "0x%x - ignoring\n", id); - /* pass-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - break; - } - - /* tracktype specific stuff for audio */ - case MATROSKA_ID_TRACKAUDIO: { - MatroskaAudioTrack *audiotrack; - if (!track->type) - track->type = MATROSKA_TRACK_TYPE_AUDIO; - if (track->type != MATROSKA_TRACK_TYPE_AUDIO) { - av_log(matroska->ctx, AV_LOG_INFO, - "audio data in non-audio track - ignoring\n"); - res = AVERROR_INVALIDDATA; - break; - } else if ((res = ebml_read_master(matroska, &id)) < 0) - break; - audiotrack = (MatroskaAudioTrack *)track; - audiotrack->channels = 1; - audiotrack->samplerate = 8000; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up > 0) { - matroska->level_up--; - break; - } - - switch (id) { - /* samplerate */ - case MATROSKA_ID_AUDIOSAMPLINGFREQ: { - double num; - if ((res = ebml_read_float(matroska, &id, - &num)) < 0) - break; - audiotrack->internal_samplerate = - audiotrack->samplerate = num; - break; - } - - case MATROSKA_ID_AUDIOOUTSAMPLINGFREQ: { - double num; - if ((res = ebml_read_float(matroska, &id, - &num)) < 0) - break; - audiotrack->samplerate = num; - break; - } - - /* bitdepth */ - case MATROSKA_ID_AUDIOBITDEPTH: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - audiotrack->bitdepth = num; - break; - } - - /* channels */ - case MATROSKA_ID_AUDIOCHANNELS: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, - &num)) < 0) - break; - audiotrack->channels = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown audio track header entry " - "0x%x - ignoring\n", id); - /* pass-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - break; - } - - /* codec identifier */ - case MATROSKA_ID_CODECID: { - char *text; - if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) - break; - track->codec_id = text; - break; - } - - /* codec private data */ - case MATROSKA_ID_CODECPRIVATE: { - uint8_t *data; - int size; - if ((res = ebml_read_binary(matroska, &id, &data, &size) < 0)) - break; - track->codec_priv = data; - track->codec_priv_size = size; - break; - } - - /* name of the codec */ - case MATROSKA_ID_CODECNAME: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - track->codec_name = text; - break; - } - - /* name of this track */ - case MATROSKA_ID_TRACKNAME: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - track->name = text; - break; - } - - /* language (matters for audio/subtitles, mostly) */ - case MATROSKA_ID_TRACKLANGUAGE: { - char *text; - if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) - break; - track->language = text; - break; - } - - /* whether this is actually used */ - case MATROSKA_ID_TRACKFLAGENABLED: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (num) - track->flags |= MATROSKA_TRACK_ENABLED; - else - track->flags &= ~MATROSKA_TRACK_ENABLED; - break; - } - - /* whether it's the default for this track type */ - case MATROSKA_ID_TRACKFLAGDEFAULT: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (num) - track->flags |= MATROSKA_TRACK_DEFAULT; - else - track->flags &= ~MATROSKA_TRACK_DEFAULT; - break; - } - - /* lacing (like MPEG, where blocks don't end/start on frame - * boundaries) */ - case MATROSKA_ID_TRACKFLAGLACING: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - if (num) - track->flags |= MATROSKA_TRACK_LACING; - else - track->flags &= ~MATROSKA_TRACK_LACING; - break; - } - - /* default length (in time) of one data block in this track */ - case MATROSKA_ID_TRACKDEFAULTDURATION: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - track->default_duration = num / matroska->time_scale; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown track header entry 0x%x - ignoring\n", id); - /* pass-through */ - - case EBML_ID_VOID: - /* we ignore these because they're nothing useful. */ - case MATROSKA_ID_CODECINFOURL: - case MATROSKA_ID_CODECDOWNLOADURL: - case MATROSKA_ID_TRACKMINCACHE: - case MATROSKA_ID_TRACKMAXCACHE: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_tracks (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing tracks...\n"); - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* one track within the "all-tracks" header */ - case MATROSKA_ID_TRACKENTRY: - res = matroska_add_stream(matroska); - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in track header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_index (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - MatroskaDemuxIndex idx; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing index...\n"); - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* one single index entry ('point') */ - case MATROSKA_ID_POINTENTRY: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - - /* in the end, we hope to fill one entry with a - * timestamp, a file position and a tracknum */ - idx.pos = (uint64_t) -1; - idx.time = (uint64_t) -1; - idx.track = (uint16_t) -1; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* one single index entry ('point') */ - case MATROSKA_ID_CUETIME: { - uint64_t time; - if ((res = ebml_read_uint(matroska, &id, - &time)) < 0) - break; - idx.time = time * matroska->time_scale; - break; - } - - /* position in the file + track to which it - * belongs */ - case MATROSKA_ID_CUETRACKPOSITION: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - - while (res == 0) { - if (!(id = ebml_peek_id (matroska, - &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* track number */ - case MATROSKA_ID_CUETRACK: { - uint64_t num; - if ((res = ebml_read_uint(matroska, - &id, &num)) < 0) - break; - idx.track = num; - break; - } - - /* position in file */ - case MATROSKA_ID_CUECLUSTERPOSITION: { - uint64_t num; - if ((res = ebml_read_uint(matroska, - &id, &num)) < 0) - break; - idx.pos = num; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in " - "CuesTrackPositions\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in cuespoint " - "index\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - /* so let's see if we got what we wanted */ - if (idx.pos != (uint64_t) -1 && - idx.time != (uint64_t) -1 && - idx.track != (uint16_t) -1) { - if (matroska->num_indexes % 32 == 0) { - /* re-allocate bigger index */ - matroska->index = - av_realloc(matroska->index, - (matroska->num_indexes + 32) * - sizeof(MatroskaDemuxIndex)); - } - matroska->index[matroska->num_indexes] = idx; - matroska->num_indexes++; - } - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in cues header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_metadata (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* Hm, this is unsupported... */ - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in metadata header\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_parse_seekhead (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing seekhead...\n"); - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - case MATROSKA_ID_SEEKENTRY: { - uint32_t seek_id = 0, peek_id_cache = 0; - uint64_t seek_pos = (uint64_t) -1, t; - - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - case MATROSKA_ID_SEEKID: - res = ebml_read_uint(matroska, &id, &t); - seek_id = t; - break; - - case MATROSKA_ID_SEEKPOSITION: - res = ebml_read_uint(matroska, &id, &seek_pos); - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown seekhead ID 0x%x\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - if (!seek_id || seek_pos == (uint64_t) -1) { - av_log(matroska->ctx, AV_LOG_INFO, - "Incomplete seekhead entry (0x%x/%"PRIu64")\n", - seek_id, seek_pos); - break; - } - - switch (seek_id) { - case MATROSKA_ID_CUES: - case MATROSKA_ID_TAGS: { - uint32_t level_up = matroska->level_up; - offset_t before_pos; - uint64_t length; - MatroskaLevel level; - - /* remember the peeked ID and the current position */ - peek_id_cache = matroska->peek_id; - before_pos = url_ftell(&matroska->ctx->pb); - - /* seek */ - if ((res = ebml_read_seek(matroska, seek_pos + - matroska->segment_start)) < 0) - return res; - - /* we don't want to lose our seekhead level, so we add - * a dummy. This is a crude hack. */ - if (matroska->num_levels == EBML_MAX_DEPTH) { - av_log(matroska->ctx, AV_LOG_INFO, - "Max EBML element depth (%d) reached, " - "cannot parse further.\n", EBML_MAX_DEPTH); - return AVERROR_UNKNOWN; - } - - level.start = 0; - level.length = (uint64_t)-1; - matroska->levels[matroska->num_levels] = level; - matroska->num_levels++; - - /* check ID */ - if (!(id = ebml_peek_id (matroska, - &matroska->level_up))) - goto finish; - if (id != seek_id) { - av_log(matroska->ctx, AV_LOG_INFO, - "We looked for ID=0x%x but got " - "ID=0x%x (pos=%"PRIu64")", - seek_id, id, seek_pos + - matroska->segment_start); - goto finish; - } - - /* read master + parse */ - if ((res = ebml_read_master(matroska, &id)) < 0) - goto finish; - switch (id) { - case MATROSKA_ID_CUES: - if (!(res = matroska_parse_index(matroska)) || - url_feof(&matroska->ctx->pb)) { - matroska->index_parsed = 1; - res = 0; - } - break; - case MATROSKA_ID_TAGS: - if (!(res = matroska_parse_metadata(matroska)) || - url_feof(&matroska->ctx->pb)) { - matroska->metadata_parsed = 1; - res = 0; - } - break; - } - - finish: - /* remove dummy level */ - while (matroska->num_levels) { - matroska->num_levels--; - length = - matroska->levels[matroska->num_levels].length; - if (length == (uint64_t)-1) - break; - } - - /* seek back */ - if ((res = ebml_read_seek(matroska, before_pos)) < 0) - return res; - matroska->peek_id = peek_id_cache; - matroska->level_up = level_up; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Ignoring seekhead entry for ID=0x%x\n", - seek_id); - break; - } - - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown seekhead ID 0x%x\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) - -static int -matroska_aac_profile (char *codec_id) -{ - static const char *aac_profiles[] = { - "MAIN", "LC", "SSR" - }; - int profile; - - for (profile=0; profile<ARRAY_SIZE(aac_profiles); profile++) - if (strstr(codec_id, aac_profiles[profile])) - break; - return profile + 1; -} - -static int -matroska_aac_sri (int samplerate) -{ - static const int aac_sample_rates[] = { - 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000, - }; - int sri; - - for (sri=0; sri<ARRAY_SIZE(aac_sample_rates); sri++) - if (aac_sample_rates[sri] == samplerate) - break; - return sri; -} - -static int -matroska_read_header (AVFormatContext *s, - AVFormatParameters *ap) -{ - MatroskaDemuxContext *matroska = s->priv_data; - char *doctype; - int version, last_level, res = 0; - uint32_t id; - - matroska->ctx = s; - - /* First read the EBML header. */ - doctype = NULL; - if ((res = ebml_read_header(matroska, &doctype, &version)) < 0) - return res; - if ((doctype == NULL) || strcmp(doctype, "matroska")) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Wrong EBML doctype ('%s' != 'matroska').\n", - doctype ? doctype : "(none)"); - if (doctype) - av_free(doctype); - return AVERROR_NOFMT; - } - av_free(doctype); - if (version > 2) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Matroska demuxer version 2 too old for file version %d\n", - version); - return AVERROR_NOFMT; - } - - /* The next thing is a segment. */ - while (1) { - if (!(id = ebml_peek_id(matroska, &last_level))) - return AVERROR_IO; - if (id == MATROSKA_ID_SEGMENT) - break; - - /* oi! */ - av_log(matroska->ctx, AV_LOG_INFO, - "Expected a Segment ID (0x%x), but received 0x%x!\n", - MATROSKA_ID_SEGMENT, id); - if ((res = ebml_read_skip(matroska)) < 0) - return res; - } - - /* We now have a Matroska segment. - * Seeks are from the beginning of the segment, - * after the segment ID/length. */ - if ((res = ebml_read_master(matroska, &id)) < 0) - return res; - matroska->segment_start = url_ftell(&s->pb); - - matroska->time_scale = 1000000; - /* we've found our segment, start reading the different contents in here */ - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* stream info */ - case MATROSKA_ID_INFO: { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_info(matroska); - break; - } - - /* track info headers */ - case MATROSKA_ID_TRACKS: { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_tracks(matroska); - break; - } - - /* stream index */ - case MATROSKA_ID_CUES: { - if (!matroska->index_parsed) { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_index(matroska); - } else - res = ebml_read_skip(matroska); - break; - } - - /* metadata */ - case MATROSKA_ID_TAGS: { - if (!matroska->metadata_parsed) { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_metadata(matroska); - } else - res = ebml_read_skip(matroska); - break; - } - - /* file index (if seekable, seek to Cues/Tags to parse it) */ - case MATROSKA_ID_SEEKHEAD: { - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_seekhead(matroska); - break; - } - - case MATROSKA_ID_CLUSTER: { - /* Do not read the master - this will be done in the next - * call to matroska_read_packet. */ - res = 1; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown matroska file header ID 0x%x\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - /* Have we found a cluster? */ - if (ebml_peek_id(matroska, NULL) == MATROSKA_ID_CLUSTER) { - int i, j; - MatroskaTrack *track; - AVStream *st; - - for (i = 0; i < matroska->num_tracks; i++) { - enum CodecID codec_id = CODEC_ID_NONE; - uint8_t *extradata = NULL; - int extradata_size = 0; - int extradata_offset = 0; - track = matroska->tracks[i]; - - /* libavformat does not really support subtitles. - * Also apply some sanity checks. */ - if ((track->type == MATROSKA_TRACK_TYPE_SUBTITLE) || - (track->codec_id == NULL)) - continue; - - for(j=0; codec_tags[j].str; j++){ - if(!strncmp(codec_tags[j].str, track->codec_id, - strlen(codec_tags[j].str))){ - codec_id= codec_tags[j].id; - break; - } - } - - /* Set the FourCC from the CodecID. */ - /* This is the MS compatibility mode which stores a - * BITMAPINFOHEADER in the CodecPrivate. */ - if (!strcmp(track->codec_id, - MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC) && - (track->codec_priv_size >= 40) && - (track->codec_priv != NULL)) { - unsigned char *p; - - /* Offset of biCompression. Stored in LE. */ - p = (unsigned char *)track->codec_priv + 16; - ((MatroskaVideoTrack *)track)->fourcc = (p[3] << 24) | - (p[2] << 16) | (p[1] << 8) | p[0]; - codec_id = codec_get_id(codec_bmp_tags, ((MatroskaVideoTrack *)track)->fourcc); - - } - - /* This is the MS compatibility mode which stores a - * WAVEFORMATEX in the CodecPrivate. */ - else if (!strcmp(track->codec_id, - MATROSKA_CODEC_ID_AUDIO_ACM) && - (track->codec_priv_size >= 18) && - (track->codec_priv != NULL)) { - unsigned char *p; - uint16_t tag; - - /* Offset of wFormatTag. Stored in LE. */ - p = (unsigned char *)track->codec_priv; - tag = (p[1] << 8) | p[0]; - codec_id = codec_get_id(codec_wav_tags, tag); - - } - - else if (codec_id == CODEC_ID_AAC && !track->codec_priv_size) { - MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track; - int profile = matroska_aac_profile(track->codec_id); - int sri = matroska_aac_sri(audiotrack->internal_samplerate); - extradata = av_malloc(5); - if (extradata == NULL) - return AVERROR_NOMEM; - extradata[0] = (profile << 3) | ((sri&0x0E) >> 1); - extradata[1] = ((sri&0x01) << 7) | (audiotrack->channels<<3); - if (strstr(track->codec_id, "SBR")) { - sri = matroska_aac_sri(audiotrack->samplerate); - extradata[2] = 0x56; - extradata[3] = 0xE5; - extradata[4] = 0x80 | (sri<<3); - extradata_size = 5; - } else { - extradata_size = 2; - } - track->default_duration = 1024*1000 / audiotrack->internal_samplerate; - } - - else if (codec_id == CODEC_ID_TTA) { - MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track; - ByteIOContext b; - extradata_size = 30; - extradata = av_mallocz(extradata_size); - if (extradata == NULL) - return AVERROR_NOMEM; - init_put_byte(&b, extradata, extradata_size, 1, - NULL, NULL, NULL, NULL); - put_buffer(&b, (uint8_t *) "TTA1", 4); - put_le16(&b, 1); - put_le16(&b, audiotrack->channels); - put_le16(&b, audiotrack->bitdepth); - put_le32(&b, audiotrack->samplerate); - put_le32(&b, matroska->ctx->duration * audiotrack->samplerate); - } - - else if (codec_id == CODEC_ID_RV10 || codec_id == CODEC_ID_RV20 || - codec_id == CODEC_ID_RV30 || codec_id == CODEC_ID_RV40) { - extradata_offset = 26; - track->codec_priv_size -= extradata_offset; - track->flags |= MATROSKA_TRACK_REAL_V; - } - - if (codec_id == CODEC_ID_NONE) { - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown/unsupported CodecID %s.\n", - track->codec_id); - } - - track->stream_index = matroska->num_streams; - - matroska->num_streams++; - st = av_new_stream(s, track->stream_index); - if (st == NULL) - return AVERROR_NOMEM; - av_set_pts_info(st, 64, matroska->time_scale, 1000*1000*1000); /* 64 bit pts in ns */ - - st->codec->codec_id = codec_id; - - if (track->default_duration) - av_reduce(&st->codec->time_base.num, &st->codec->time_base.den, - track->default_duration, 1000, 30000); - - if(extradata){ - st->codec->extradata = extradata; - st->codec->extradata_size = extradata_size; - } else if(track->codec_priv && track->codec_priv_size > 0){ - st->codec->extradata = av_malloc(track->codec_priv_size); - if(st->codec->extradata == NULL) - return AVERROR_NOMEM; - st->codec->extradata_size = track->codec_priv_size; - memcpy(st->codec->extradata,track->codec_priv+extradata_offset, - track->codec_priv_size); - } - - if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { - MatroskaVideoTrack *videotrack = (MatroskaVideoTrack *)track; - - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_tag = videotrack->fourcc; - st->codec->width = videotrack->pixel_width; - st->codec->height = videotrack->pixel_height; - if (videotrack->display_width == 0) - videotrack->display_width= videotrack->pixel_width; - if (videotrack->display_height == 0) - videotrack->display_height= videotrack->pixel_height; - av_reduce(&st->codec->sample_aspect_ratio.num, - &st->codec->sample_aspect_ratio.den, - st->codec->height * videotrack->display_width, - st->codec-> width * videotrack->display_height, - 255); - st->need_parsing = 2; - } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { - MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track; - - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->sample_rate = audiotrack->samplerate; - st->codec->channels = audiotrack->channels; - } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { - st->codec->codec_type = CODEC_TYPE_SUBTITLE; - } - - /* What do we do with private data? E.g. for Vorbis. */ - } - res = 0; - } - - return res; -} - -static int -matroska_find_track_by_num (MatroskaDemuxContext *matroska, - int num) -{ - int i; - - for (i = 0; i < matroska->num_tracks; i++) - if (matroska->tracks[i]->num == num) - return i; - - return -1; -} - -static inline int -rv_offset(uint8_t *data, int slice, int slices) -{ - return AV_RL32(data+8*slice+4) + 8*slices; -} - -static int -matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size, - int64_t pos, uint64_t cluster_time, uint64_t duration, - int is_keyframe, int is_bframe) -{ - int res = 0; - int track; - AVPacket *pkt; - uint8_t *origdata = data; - int16_t block_time; - uint32_t *lace_size = NULL; - int n, flags, laces = 0; - uint64_t num; - - /* first byte(s): tracknum */ - if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) { - av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); - av_free(origdata); - return res; - } - data += n; - size -= n; - - /* fetch track from num */ - track = matroska_find_track_by_num(matroska, num); - if (size <= 3 || track < 0 || track >= matroska->num_tracks) { - av_log(matroska->ctx, AV_LOG_INFO, - "Invalid stream %d or size %u\n", track, size); - av_free(origdata); - return res; - } - if(matroska->ctx->streams[ matroska->tracks[track]->stream_index ]->discard >= AVDISCARD_ALL){ - av_free(origdata); - return res; - } - if (duration == AV_NOPTS_VALUE) - duration = matroska->tracks[track]->default_duration; - - /* block_time (relative to cluster time) */ - block_time = (data[0] << 8) | data[1]; - data += 2; - size -= 2; - flags = *data; - data += 1; - size -= 1; - if (is_keyframe == -1) - is_keyframe = flags & 1 ? PKT_FLAG_KEY : 0; - switch ((flags & 0x06) >> 1) { - case 0x0: /* no lacing */ - laces = 1; - lace_size = av_mallocz(sizeof(int)); - lace_size[0] = size; - break; - - case 0x1: /* xiph lacing */ - case 0x2: /* fixed-size lacing */ - case 0x3: /* EBML lacing */ - if (size == 0) { - res = -1; - break; - } - laces = (*data) + 1; - data += 1; - size -= 1; - lace_size = av_mallocz(laces * sizeof(int)); - - switch ((flags & 0x06) >> 1) { - case 0x1: /* xiph lacing */ { - uint8_t temp; - uint32_t total = 0; - for (n = 0; res == 0 && n < laces - 1; n++) { - while (1) { - if (size == 0) { - res = -1; - break; - } - temp = *data; - lace_size[n] += temp; - data += 1; - size -= 1; - if (temp != 0xff) - break; - } - total += lace_size[n]; - } - lace_size[n] = size - total; - break; - } - - case 0x2: /* fixed-size lacing */ - for (n = 0; n < laces; n++) - lace_size[n] = size / laces; - break; - - case 0x3: /* EBML lacing */ { - uint32_t total; - n = matroska_ebmlnum_uint(data, size, &num); - if (n < 0) { - av_log(matroska->ctx, AV_LOG_INFO, - "EBML block data error\n"); - break; - } - data += n; - size -= n; - total = lace_size[0] = num; - for (n = 1; res == 0 && n < laces - 1; n++) { - int64_t snum; - int r; - r = matroska_ebmlnum_sint (data, size, &snum); - if (r < 0) { - av_log(matroska->ctx, AV_LOG_INFO, - "EBML block data error\n"); - break; - } - data += r; - size -= r; - lace_size[n] = lace_size[n - 1] + snum; - total += lace_size[n]; - } - lace_size[n] = size - total; - break; - } - } - break; - } - - if (res == 0) { - int real_v = matroska->tracks[track]->flags & MATROSKA_TRACK_REAL_V; - uint64_t timecode = AV_NOPTS_VALUE; - - if (cluster_time != (uint64_t)-1 && cluster_time + block_time >= 0) - timecode = cluster_time + block_time; - - for (n = 0; n < laces; n++) { - int slice, slices = 1; - - if (real_v) { - slices = *data++ + 1; - lace_size[n]--; - } - - for (slice=0; slice<slices; slice++) { - int slice_size, slice_offset = 0; - if (real_v) - slice_offset = rv_offset(data, slice, slices); - if (slice+1 == slices) - slice_size = lace_size[n] - slice_offset; - else - slice_size = rv_offset(data, slice+1, slices) - slice_offset; - pkt = av_mallocz(sizeof(AVPacket)); - /* XXX: prevent data copy... */ - if (av_new_packet(pkt, slice_size) < 0) { - res = AVERROR_NOMEM; - n = laces-1; - break; - } - memcpy (pkt->data, data+slice_offset, slice_size); - - if (n == 0) - pkt->flags = is_keyframe; - pkt->stream_index = matroska->tracks[track]->stream_index; - - pkt->pts = timecode; - pkt->pos = pos; - pkt->duration = duration; - - if (matroska->tracks[track]->flags & MATROSKA_TRACK_REORDER) - matroska_queue_packet_reordered(matroska, pkt, is_bframe); - else - matroska_queue_packet(matroska, pkt); - - if (timecode != AV_NOPTS_VALUE) - timecode = duration ? timecode + duration : AV_NOPTS_VALUE; - } - data += lace_size[n]; - } - } - - av_free(lace_size); - av_free(origdata); - return res; -} - -static int -matroska_parse_blockgroup (MatroskaDemuxContext *matroska, - uint64_t cluster_time) -{ - int res = 0; - uint32_t id; - int is_bframe = 0; - int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets; - uint64_t duration = AV_NOPTS_VALUE; - uint8_t *data; - int size = 0; - int64_t pos = 0; - - av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n"); - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* one block inside the group. Note, block parsing is one - * of the harder things, so this code is a bit complicated. - * See http://www.matroska.org/ for documentation. */ - case MATROSKA_ID_BLOCK: { - pos = url_ftell(&matroska->ctx->pb); - res = ebml_read_binary(matroska, &id, &data, &size); - break; - } - - case MATROSKA_ID_BLOCKDURATION: { - if ((res = ebml_read_uint(matroska, &id, &duration)) < 0) - break; - duration /= matroska->time_scale; - break; - } - - case MATROSKA_ID_BLOCKREFERENCE: { - int64_t num; - /* We've found a reference, so not even the first frame in - * the lace is a key frame. */ - is_keyframe = 0; - if (last_num_packets != matroska->num_packets) - matroska->packets[last_num_packets]->flags = 0; - if ((res = ebml_read_sint(matroska, &id, &num)) < 0) - break; - if (num > 0) - is_bframe = 1; - break; - } - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in blockgroup data\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - if (res) - return res; - - if (size > 0) - res = matroska_parse_block(matroska, data, size, pos, cluster_time, - duration, is_keyframe, is_bframe); - - return res; -} - -static int -matroska_parse_cluster (MatroskaDemuxContext *matroska) -{ - int res = 0; - uint32_t id; - uint64_t cluster_time = 0; - uint8_t *data; - int64_t pos; - int size; - - av_log(matroska->ctx, AV_LOG_DEBUG, - "parsing cluster at %"PRId64"\n", url_ftell(&matroska->ctx->pb)); - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - res = AVERROR_IO; - break; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - /* cluster timecode */ - case MATROSKA_ID_CLUSTERTIMECODE: { - uint64_t num; - if ((res = ebml_read_uint(matroska, &id, &num)) < 0) - break; - cluster_time = num; - break; - } - - /* a group of blocks inside a cluster */ - case MATROSKA_ID_BLOCKGROUP: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - res = matroska_parse_blockgroup(matroska, cluster_time); - break; - - case MATROSKA_ID_SIMPLEBLOCK: - pos = url_ftell(&matroska->ctx->pb); - res = ebml_read_binary(matroska, &id, &data, &size); - if (res == 0) - res = matroska_parse_block(matroska, data, size, pos, - cluster_time, AV_NOPTS_VALUE, - -1, 0); - break; - - default: - av_log(matroska->ctx, AV_LOG_INFO, - "Unknown entry 0x%x in cluster data\n", id); - /* fall-through */ - - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - return res; -} - -static int -matroska_read_packet (AVFormatContext *s, - AVPacket *pkt) -{ - MatroskaDemuxContext *matroska = s->priv_data; - int res = 0; - uint32_t id; - - /* Read stream until we have a packet queued. */ - while (matroska_deliver_packet(matroska, pkt)) { - - /* Have we already reached the end? */ - if (matroska->done) - return AVERROR_IO; - - while (res == 0) { - if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { - return AVERROR_IO; - } else if (matroska->level_up) { - matroska->level_up--; - break; - } - - switch (id) { - case MATROSKA_ID_CLUSTER: - if ((res = ebml_read_master(matroska, &id)) < 0) - break; - if ((res = matroska_parse_cluster(matroska)) == 0) - res = 1; /* Parsed one cluster, let's get out. */ - break; - - default: - case EBML_ID_VOID: - res = ebml_read_skip(matroska); - break; - } - - if (matroska->level_up) { - matroska->level_up--; - break; - } - } - - if (res == -1) - matroska->done = 1; - } - - return 0; -} - -static int -matroska_read_close (AVFormatContext *s) -{ - MatroskaDemuxContext *matroska = s->priv_data; - int n = 0; - - av_free(matroska->writing_app); - av_free(matroska->muxing_app); - av_free(matroska->index); - - if (matroska->packets != NULL) { - for (n = 0; n < matroska->num_packets; n++) { - av_free_packet(matroska->packets[n]); - av_free(matroska->packets[n]); - } - av_free(matroska->packets); - } - if (matroska->packets_reorder) { - for (n = 0; n < matroska->num_packets_reorder; n++) { - av_free_packet(matroska->packets_reorder[n]); - av_free(matroska->packets_reorder[n]); - } - av_free(matroska->packets_reorder); - } - - for (n = 0; n < matroska->num_tracks; n++) { - MatroskaTrack *track = matroska->tracks[n]; - av_free(track->codec_id); - av_free(track->codec_name); - av_free(track->codec_priv); - av_free(track->name); - av_free(track->language); - - av_free(track); - } - - return 0; -} +const CodecMime ff_mkv_mime_tags[] = { + {"text/plain" , CODEC_ID_TEXT}, + {"image/gif" , CODEC_ID_GIF}, + {"image/jpeg" , CODEC_ID_MJPEG}, + {"image/png" , CODEC_ID_PNG}, + {"image/tiff" , CODEC_ID_TIFF}, + {"application/x-truetype-font", CODEC_ID_TTF}, + {"application/x-font" , CODEC_ID_TTF}, -AVInputFormat matroska_demuxer = { - "matroska", - "Matroska file format", - sizeof(MatroskaDemuxContext), - matroska_probe, - matroska_read_header, - matroska_read_packet, - matroska_read_close, + {"" , CODEC_ID_NONE} }; diff --git a/contrib/ffmpeg/libavformat/matroska.h b/contrib/ffmpeg/libavformat/matroska.h new file mode 100644 index 000000000..370a8bfd8 --- /dev/null +++ b/contrib/ffmpeg/libavformat/matroska.h @@ -0,0 +1,210 @@ +/* + * Matroska constants + * Copyright (c) 2003-2004 The ffmpeg Project + * + * 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 FFMPEG_MATROSKA_H +#define FFMPEG_MATROSKA_H + +#include "avcodec.h" + +/* EBML version supported */ +#define EBML_VERSION 1 + +/* top-level master-IDs */ +#define EBML_ID_HEADER 0x1A45DFA3 + +/* IDs in the HEADER master */ +#define EBML_ID_EBMLVERSION 0x4286 +#define EBML_ID_EBMLREADVERSION 0x42F7 +#define EBML_ID_EBMLMAXIDLENGTH 0x42F2 +#define EBML_ID_EBMLMAXSIZELENGTH 0x42F3 +#define EBML_ID_DOCTYPE 0x4282 +#define EBML_ID_DOCTYPEVERSION 0x4287 +#define EBML_ID_DOCTYPEREADVERSION 0x4285 + +/* general EBML types */ +#define EBML_ID_VOID 0xEC + +/* + * Matroska element IDs. max. 32-bit. + */ + +/* toplevel segment */ +#define MATROSKA_ID_SEGMENT 0x18538067 + +/* matroska top-level master IDs */ +#define MATROSKA_ID_INFO 0x1549A966 +#define MATROSKA_ID_TRACKS 0x1654AE6B +#define MATROSKA_ID_CUES 0x1C53BB6B +#define MATROSKA_ID_TAGS 0x1254C367 +#define MATROSKA_ID_SEEKHEAD 0x114D9B74 +#define MATROSKA_ID_ATTACHMENTS 0x1941A469 +#define MATROSKA_ID_CLUSTER 0x1F43B675 + +/* IDs in the info master */ +#define MATROSKA_ID_TIMECODESCALE 0x2AD7B1 +#define MATROSKA_ID_DURATION 0x4489 +#define MATROSKA_ID_TITLE 0x7BA9 +#define MATROSKA_ID_WRITINGAPP 0x5741 +#define MATROSKA_ID_MUXINGAPP 0x4D80 +#define MATROSKA_ID_DATEUTC 0x4461 +#define MATROSKA_ID_SEGMENTUID 0x73A4 + +/* ID in the tracks master */ +#define MATROSKA_ID_TRACKENTRY 0xAE + +/* IDs in the trackentry master */ +#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_CODECID 0x86 +#define MATROSKA_ID_CODECPRIVATE 0x63A2 +#define MATROSKA_ID_CODECNAME 0x258688 +#define MATROSKA_ID_CODECINFOURL 0x3B4040 +#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240 +#define MATROSKA_ID_TRACKNAME 0x536E +#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C +#define MATROSKA_ID_TRACKFLAGENABLED 0xB9 +#define MATROSKA_ID_TRACKFLAGDEFAULT 0x88 +#define MATROSKA_ID_TRACKFLAGLACING 0x9C +#define MATROSKA_ID_TRACKMINCACHE 0x6DE7 +#define MATROSKA_ID_TRACKMAXCACHE 0x6DF8 +#define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383 + +/* IDs in the trackvideo master */ +#define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3 +#define MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0 +#define MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA +#define MATROSKA_ID_VIDEOPIXELWIDTH 0xB0 +#define MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA +#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A +#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9 +#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3 +#define MATROSKA_ID_VIDEOCOLORSPACE 0x2EB524 + +/* IDs in the trackaudio master */ +#define MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5 +#define MATROSKA_ID_AUDIOOUTSAMPLINGFREQ 0x78B5 + +#define MATROSKA_ID_AUDIOBITDEPTH 0x6264 +#define MATROSKA_ID_AUDIOCHANNELS 0x9F + +/* ID in the cues master */ +#define MATROSKA_ID_POINTENTRY 0xBB + +/* IDs in the pointentry master */ +#define MATROSKA_ID_CUETIME 0xB3 +#define MATROSKA_ID_CUETRACKPOSITION 0xB7 + +/* IDs in the cuetrackposition master */ +#define MATROSKA_ID_CUETRACK 0xF7 +#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1 + +/* IDs in the tags master */ +/* TODO */ + +/* IDs in the seekhead master */ +#define MATROSKA_ID_SEEKENTRY 0x4DBB + +/* IDs in the seekpoint master */ +#define MATROSKA_ID_SEEKID 0x53AB +#define MATROSKA_ID_SEEKPOSITION 0x53AC + +/* IDs in the cluster master */ +#define MATROSKA_ID_CLUSTERTIMECODE 0xE7 +#define MATROSKA_ID_BLOCKGROUP 0xA0 +#define MATROSKA_ID_SIMPLEBLOCK 0xA3 + +/* IDs in the blockgroup master */ +#define MATROSKA_ID_BLOCK 0xA1 +#define MATROSKA_ID_BLOCKDURATION 0x9B +#define MATROSKA_ID_BLOCKREFERENCE 0xFB + +/* IDs in the attachments master */ +#define MATROSKA_ID_ATTACHEDFILE 0x61A7 +#define MATROSKA_ID_FILENAME 0x466E +#define MATROSKA_ID_FILEMIMETYPE 0x4660 +#define MATROSKA_ID_FILEDATA 0x465C +#define MATROSKA_ID_FILEUID 0x46AE + +typedef enum { + MATROSKA_TRACK_TYPE_VIDEO = 0x1, + MATROSKA_TRACK_TYPE_AUDIO = 0x2, + MATROSKA_TRACK_TYPE_COMPLEX = 0x3, + MATROSKA_TRACK_TYPE_LOGO = 0x10, + MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, + MATROSKA_TRACK_TYPE_CONTROL = 0x20, +} MatroskaTrackType; + +typedef enum { + MATROSKA_EYE_MODE_MONO = 0x0, + MATROSKA_EYE_MODE_RIGHT = 0x1, + MATROSKA_EYE_MODE_LEFT = 0x2, + MATROSKA_EYE_MODE_BOTH = 0x3, +} MatroskaEyeMode; + +typedef enum { + MATROSKA_ASPECT_RATIO_MODE_FREE = 0x0, + MATROSKA_ASPECT_RATIO_MODE_KEEP = 0x1, + MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2, +} MatroskaAspectRatioMode; + +/* + * These aren't in any way "matroska-form" things, + * it's just something I use in the muxer/demuxer. + */ + +typedef enum { + MATROSKA_TRACK_ENABLED = (1<<0), + MATROSKA_TRACK_DEFAULT = (1<<1), + MATROSKA_TRACK_LACING = (1<<2), + MATROSKA_TRACK_SHIFT = (1<<16) +} MatroskaTrackFlags; + +typedef enum { + MATROSKA_VIDEOTRACK_INTERLACED = (MATROSKA_TRACK_SHIFT<<0) +} MatroskaVideoTrackFlags; + +/* + * Matroska Codec IDs. Strings. + */ + +typedef struct CodecTags{ + char str[16]; + enum CodecID id; +}CodecTags; + +typedef struct CodecMime{ + char str[32]; + enum CodecID id; +}CodecMime; + +#define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC" +#define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" + +/* max. depth in the EBML tree structure */ +#define EBML_MAX_DEPTH 16 + +extern const CodecTags ff_mkv_codec_tags[]; +extern const CodecMime ff_mkv_mime_tags[]; + +#endif /* FFMPEG_MATROSKA_H */ diff --git a/contrib/ffmpeg/libavformat/matroskadec.c b/contrib/ffmpeg/libavformat/matroskadec.c new file mode 100644 index 000000000..d9fdcec28 --- /dev/null +++ b/contrib/ffmpeg/libavformat/matroskadec.c @@ -0,0 +1,2842 @@ +/* + * Matroska file demuxer (no muxer yet) + * Copyright (c) 2003-2004 The ffmpeg Project + * + * 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 matroskadec.c + * Matroska file demuxer + * by Ronald Bultje <rbultje@ronald.bitfreak.net> + * with a little help from Moritz Bunkus <moritz@bunkus.org> + * Specs available on the matroska project page: + * http://www.matroska.org/. + */ + +#include "avformat.h" +/* For codec_get_id(). */ +#include "riff.h" +#include "intfloat_readwrite.h" +#include "matroska.h" + +typedef struct Track { + MatroskaTrackType type; + + /* Unique track number and track ID. stream_index is the index that + * the calling app uses for this track. */ + uint32_t num; + uint32_t uid; + int stream_index; + + char *name; + char language[4]; + + char *codec_id; + char *codec_name; + + unsigned char *codec_priv; + int codec_priv_size; + + uint64_t default_duration; + MatroskaTrackFlags flags; +} MatroskaTrack; + +typedef struct MatroskaVideoTrack { + MatroskaTrack track; + + int pixel_width; + int pixel_height; + int display_width; + int display_height; + + uint32_t fourcc; + + MatroskaAspectRatioMode ar_mode; + MatroskaEyeMode eye_mode; + + //.. +} MatroskaVideoTrack; + +typedef struct MatroskaAudioTrack { + MatroskaTrack track; + + int channels; + int bitdepth; + int internal_samplerate; + int samplerate; + int block_align; + + /* real audio header */ + int coded_framesize; + int sub_packet_h; + int frame_size; + int sub_packet_size; + int sub_packet_cnt; + int pkt_cnt; + uint8_t *buf; + //.. +} MatroskaAudioTrack; + +typedef struct MatroskaSubtitleTrack { + MatroskaTrack track; + //.. +} MatroskaSubtitleTrack; + +#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \ + sizeof(MatroskaAudioTrack)), \ + sizeof(MatroskaSubtitleTrack))) + +typedef struct MatroskaLevel { + uint64_t start; + uint64_t length; +} MatroskaLevel; + +typedef struct MatroskaDemuxIndex { + uint64_t pos; /* of the corresponding *cluster*! */ + uint16_t track; /* reference to 'num' */ + uint64_t time; /* in nanoseconds */ +} MatroskaDemuxIndex; + +typedef struct MatroskaDemuxContext { + AVFormatContext *ctx; + + /* ebml stuff */ + int num_levels; + MatroskaLevel levels[EBML_MAX_DEPTH]; + int level_up; + + /* matroska stuff */ + char *writing_app; + char *muxing_app; + int64_t created; + + /* timescale in the file */ + int64_t time_scale; + + /* num_streams is the number of streams that av_new_stream() was called + * for ( = that are available to the calling program). */ + int num_tracks; + int num_streams; + MatroskaTrack *tracks[MAX_STREAMS]; + + /* cache for ID peeking */ + uint32_t peek_id; + + /* byte position of the segment inside the stream */ + offset_t segment_start; + + /* The packet queue. */ + AVPacket **packets; + int num_packets; + + /* have we already parse metadata/cues/clusters? */ + int metadata_parsed; + int index_parsed; + int done; + + /* The index for seeking. */ + int num_indexes; + MatroskaDemuxIndex *index; + + /* What to skip before effectively reading a packet. */ + int skip_to_keyframe; + AVStream *skip_to_stream; +} MatroskaDemuxContext; + +/* + * The first few functions handle EBML file parsing. The rest + * is the document interpretation. Matroska really just is a + * EBML file. + */ + +/* + * Return: the amount of levels in the hierarchy that the + * current element lies higher than the previous one. + * The opposite isn't done - that's auto-done using master + * element reading. + */ + +static int +ebml_read_element_level_up (MatroskaDemuxContext *matroska) +{ + ByteIOContext *pb = matroska->ctx->pb; + offset_t pos = url_ftell(pb); + int num = 0; + + while (matroska->num_levels > 0) { + MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; + + if (pos >= level->start + level->length) { + matroska->num_levels--; + num++; + } else { + break; + } + } + + return num; +} + +/* + * Read: an "EBML number", which is defined as a variable-length + * array of bytes. The first byte indicates the length by giving a + * number of 0-bits followed by a one. The position of the first + * "one" bit inside the first byte indicates the length of this + * number. + * Returns: num. of bytes read. < 0 on error. + */ + +static int +ebml_read_num (MatroskaDemuxContext *matroska, + int max_size, + uint64_t *number) +{ + ByteIOContext *pb = matroska->ctx->pb; + int len_mask = 0x80, read = 1, n = 1; + int64_t total = 0; + + /* the first byte tells us the length in bytes - get_byte() can normally + * return 0, but since that's not a valid first ebmlID byte, we can + * use it safely here to catch EOS. */ + if (!(total = get_byte(pb))) { + /* we might encounter EOS here */ + if (!url_feof(pb)) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", + pos, pos); + } + return AVERROR(EIO); /* EOS or actual I/O error */ + } + + /* get the length of the EBML number */ + while (read <= max_size && !(total & len_mask)) { + read++; + len_mask >>= 1; + } + if (read > max_size) { + offset_t pos = url_ftell(pb) - 1; + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", + (uint8_t) total, pos, pos); + return AVERROR_INVALIDDATA; + } + + /* read out length */ + total &= ~len_mask; + while (n++ < read) + total = (total << 8) | get_byte(pb); + + *number = total; + + return read; +} + +/* + * Read: the element content data ID. + * Return: the number of bytes read or < 0 on error. + */ + +static int +ebml_read_element_id (MatroskaDemuxContext *matroska, + uint32_t *id, + int *level_up) +{ + int read; + uint64_t total; + + /* if we re-call this, use our cached ID */ + if (matroska->peek_id != 0) { + if (level_up) + *level_up = 0; + *id = matroska->peek_id; + return 0; + } + + /* read out the "EBML number", include tag in ID */ + if ((read = ebml_read_num(matroska, 4, &total)) < 0) + return read; + *id = matroska->peek_id = total | (1 << (read * 7)); + + /* level tracking */ + if (level_up) + *level_up = ebml_read_element_level_up(matroska); + + return read; +} + +/* + * Read: element content length. + * Return: the number of bytes read or < 0 on error. + */ + +static int +ebml_read_element_length (MatroskaDemuxContext *matroska, + uint64_t *length) +{ + /* clear cache since we're now beyond that data point */ + matroska->peek_id = 0; + + /* read out the "EBML number", include tag in ID */ + return ebml_read_num(matroska, 8, length); +} + +/* + * Return: the ID of the next element, or 0 on error. + * Level_up contains the amount of levels that this + * next element lies higher than the previous one. + */ + +static uint32_t +ebml_peek_id (MatroskaDemuxContext *matroska, + int *level_up) +{ + uint32_t id; + + if (ebml_read_element_id(matroska, &id, level_up) < 0) + return 0; + + return id; +} + +/* + * Seek to a given offset. + * 0 is success, -1 is failure. + */ + +static int +ebml_read_seek (MatroskaDemuxContext *matroska, + offset_t offset) +{ + ByteIOContext *pb = matroska->ctx->pb; + + /* clear ID cache, if any */ + matroska->peek_id = 0; + + return (url_fseek(pb, offset, SEEK_SET) == offset) ? 0 : -1; +} + +/* + * Skip the next element. + * 0 is success, -1 is failure. + */ + +static int +ebml_read_skip (MatroskaDemuxContext *matroska) +{ + ByteIOContext *pb = matroska->ctx->pb; + uint32_t id; + uint64_t length; + int res; + + if ((res = ebml_read_element_id(matroska, &id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &length)) < 0) + return res; + + url_fskip(pb, length); + + return 0; +} + +/* + * Read the next element as an unsigned int. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_uint (MatroskaDemuxContext *matroska, + uint32_t *id, + uint64_t *num) +{ + ByteIOContext *pb = matroska->ctx->pb; + int n = 0, size, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + if (size < 1 || size > 8) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid uint element size %d at position %"PRId64" (0x%"PRIx64")\n", + size, pos, pos); + return AVERROR_INVALIDDATA; + } + + /* big-endian ordening; build up number */ + *num = 0; + while (n++ < size) + *num = (*num << 8) | get_byte(pb); + + return 0; +} + +/* + * Read the next element as a signed int. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_sint (MatroskaDemuxContext *matroska, + uint32_t *id, + int64_t *num) +{ + ByteIOContext *pb = matroska->ctx->pb; + int size, n = 1, negative = 0, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + if (size < 1 || size > 8) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid sint element size %d at position %"PRId64" (0x%"PRIx64")\n", + size, pos, pos); + return AVERROR_INVALIDDATA; + } + if ((*num = get_byte(pb)) & 0x80) { + negative = 1; + *num &= ~0x80; + } + while (n++ < size) + *num = (*num << 8) | get_byte(pb); + + /* make signed */ + if (negative) + *num = *num - (1LL << ((8 * size) - 1)); + + return 0; +} + +/* + * Read the next element as a float. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_float (MatroskaDemuxContext *matroska, + uint32_t *id, + double *num) +{ + ByteIOContext *pb = matroska->ctx->pb; + int size, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + + if (size == 4) { + *num= av_int2flt(get_be32(pb)); + } else if(size==8){ + *num= av_int2dbl(get_be64(pb)); + } else{ + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid float element size %d at position %"PRIu64" (0x%"PRIx64")\n", + size, pos, pos); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +/* + * Read the next element as an ASCII string. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_ascii (MatroskaDemuxContext *matroska, + uint32_t *id, + char **str) +{ + ByteIOContext *pb = matroska->ctx->pb; + int size, res; + uint64_t rlength; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + size = rlength; + + /* ebml strings are usually not 0-terminated, so we allocate one + * byte more, read the string and NULL-terminate it ourselves. */ + if (size < 0 || !(*str = av_malloc(size + 1))) { + av_log(matroska->ctx, AV_LOG_ERROR, "Memory allocation failed\n"); + return AVERROR(ENOMEM); + } + if (get_buffer(pb, (uint8_t *) *str, size) != size) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); + return AVERROR(EIO); + } + (*str)[size] = '\0'; + + return 0; +} + +/* + * Read the next element as a UTF-8 string. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_utf8 (MatroskaDemuxContext *matroska, + uint32_t *id, + char **str) +{ + return ebml_read_ascii(matroska, id, str); +} + +/* + * Read the next element as a date (nanoseconds since 1/1/2000). + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_date (MatroskaDemuxContext *matroska, + uint32_t *id, + int64_t *date) +{ + return ebml_read_sint(matroska, id, date); +} + +/* + * Read the next element, but only the header. The contents + * are supposed to be sub-elements which can be read separately. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_master (MatroskaDemuxContext *matroska, + uint32_t *id) +{ + ByteIOContext *pb = matroska->ctx->pb; + uint64_t length; + MatroskaLevel *level; + int res; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &length)) < 0) + return res; + + /* protect... (Heaven forbids that the '>' is true) */ + if (matroska->num_levels >= EBML_MAX_DEPTH) { + av_log(matroska->ctx, AV_LOG_ERROR, + "File moves beyond max. allowed depth (%d)\n", EBML_MAX_DEPTH); + return AVERROR(ENOSYS); + } + + /* remember level */ + level = &matroska->levels[matroska->num_levels++]; + level->start = url_ftell(pb); + level->length = length; + + return 0; +} + +/* + * Read the next element as binary data. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_binary (MatroskaDemuxContext *matroska, + uint32_t *id, + uint8_t **binary, + int *size) +{ + ByteIOContext *pb = matroska->ctx->pb; + uint64_t rlength; + int res; + + if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 || + (res = ebml_read_element_length(matroska, &rlength)) < 0) + return res; + *size = rlength; + + if (!(*binary = av_malloc(*size))) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Memory allocation error\n"); + return AVERROR(ENOMEM); + } + + if (get_buffer(pb, *binary, *size) != *size) { + offset_t pos = url_ftell(pb); + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); + return AVERROR(EIO); + } + + return 0; +} + +/* + * Read signed/unsigned "EBML" numbers. + * Return: number of bytes processed, < 0 on error. + * XXX: use ebml_read_num(). + */ + +static int +matroska_ebmlnum_uint (uint8_t *data, + uint32_t size, + uint64_t *num) +{ + int len_mask = 0x80, read = 1, n = 1, num_ffs = 0; + uint64_t total; + + if (size <= 0) + return AVERROR_INVALIDDATA; + + total = data[0]; + while (read <= 8 && !(total & len_mask)) { + read++; + len_mask >>= 1; + } + if (read > 8) + return AVERROR_INVALIDDATA; + + if ((total &= (len_mask - 1)) == len_mask - 1) + num_ffs++; + if (size < read) + return AVERROR_INVALIDDATA; + while (n < read) { + if (data[n] == 0xff) + num_ffs++; + total = (total << 8) | data[n]; + n++; + } + + if (read == num_ffs) + *num = (uint64_t)-1; + else + *num = total; + + return read; +} + +/* + * Same as above, but signed. + */ + +static int +matroska_ebmlnum_sint (uint8_t *data, + uint32_t size, + int64_t *num) +{ + uint64_t unum; + int res; + + /* read as unsigned number first */ + if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0) + return res; + + /* make signed (weird way) */ + if (unum == (uint64_t)-1) + *num = INT64_MAX; + else + *num = unum - ((1LL << ((7 * res) - 1)) - 1); + + return res; +} + +/* + * Read an EBML header. + * 0 is success, < 0 is failure. + */ + +static int +ebml_read_header (MatroskaDemuxContext *matroska, + char **doctype, + int *version) +{ + uint32_t id; + int level_up, res = 0; + + /* default init */ + if (doctype) + *doctype = NULL; + if (version) + *version = 1; + + if (!(id = ebml_peek_id(matroska, &level_up)) || + level_up != 0 || id != EBML_ID_HEADER) { + av_log(matroska->ctx, AV_LOG_ERROR, + "This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER); + return AVERROR_INVALIDDATA; + } + if ((res = ebml_read_master(matroska, &id)) < 0) + return res; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &level_up))) + return AVERROR(EIO); + + /* end-of-header */ + if (level_up) + break; + + switch (id) { + /* is our read version uptodate? */ + case EBML_ID_EBMLREADVERSION: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (num > EBML_VERSION) { + av_log(matroska->ctx, AV_LOG_ERROR, + "EBML version %"PRIu64" (> %d) is not supported\n", + num, EBML_VERSION); + return AVERROR_INVALIDDATA; + } + break; + } + + /* we only handle 8 byte lengths at max */ + case EBML_ID_EBMLMAXSIZELENGTH: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (num > sizeof(uint64_t)) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Integers of size %"PRIu64" (> %zd) not supported\n", + num, sizeof(uint64_t)); + return AVERROR_INVALIDDATA; + } + break; + } + + /* we handle 4 byte IDs at max */ + case EBML_ID_EBMLMAXIDLENGTH: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (num > sizeof(uint32_t)) { + av_log(matroska->ctx, AV_LOG_ERROR, + "IDs of size %"PRIu64" (> %zu) not supported\n", + num, sizeof(uint32_t)); + return AVERROR_INVALIDDATA; + } + break; + } + + case EBML_ID_DOCTYPE: { + char *text; + + if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) + return res; + if (doctype) { + if (*doctype) + av_free(*doctype); + *doctype = text; + } else + av_free(text); + break; + } + + case EBML_ID_DOCTYPEREADVERSION: { + uint64_t num; + + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + return res; + if (version) + *version = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown data type 0x%x in EBML header", id); + /* pass-through */ + + case EBML_ID_VOID: + /* we ignore these two, as they don't tell us anything we + * care about */ + case EBML_ID_EBMLVERSION: + case EBML_ID_DOCTYPEVERSION: + res = ebml_read_skip (matroska); + break; + } + } + + return 0; +} + + +static int +matroska_find_track_by_num (MatroskaDemuxContext *matroska, + int num) +{ + int i; + + for (i = 0; i < matroska->num_tracks; i++) + if (matroska->tracks[i]->num == num) + return i; + + return -1; +} + + +/* + * Put one packet in an application-supplied AVPacket struct. + * Returns 0 on success or -1 on failure. + */ + +static int +matroska_deliver_packet (MatroskaDemuxContext *matroska, + AVPacket *pkt) +{ + if (matroska->num_packets > 0) { + memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); + av_free(matroska->packets[0]); + if (matroska->num_packets > 1) { + memmove(&matroska->packets[0], &matroska->packets[1], + (matroska->num_packets - 1) * sizeof(AVPacket *)); + matroska->packets = + av_realloc(matroska->packets, (matroska->num_packets - 1) * + sizeof(AVPacket *)); + } else { + av_freep(&matroska->packets); + } + matroska->num_packets--; + return 0; + } + + return -1; +} + +/* + * Put a packet into our internal queue. Will be delivered to the + * user/application during the next get_packet() call. + */ + +static void +matroska_queue_packet (MatroskaDemuxContext *matroska, + AVPacket *pkt) +{ + matroska->packets = + av_realloc(matroska->packets, (matroska->num_packets + 1) * + sizeof(AVPacket *)); + matroska->packets[matroska->num_packets] = pkt; + matroska->num_packets++; +} + +/* + * Free all packets in our internal queue. + */ +static void +matroska_clear_queue (MatroskaDemuxContext *matroska) +{ + if (matroska->packets) { + int n; + for (n = 0; n < matroska->num_packets; n++) { + av_free_packet(matroska->packets[n]); + av_free(matroska->packets[n]); + } + av_free(matroska->packets); + matroska->packets = NULL; + matroska->num_packets = 0; + } +} + + +/* + * Autodetecting... + */ + +static int +matroska_probe (AVProbeData *p) +{ + uint64_t total = 0; + int len_mask = 0x80, size = 1, n = 1; + uint8_t probe_data[] = { 'm', 'a', 't', 'r', 'o', 's', 'k', 'a' }; + + /* ebml header? */ + if (AV_RB32(p->buf) != EBML_ID_HEADER) + return 0; + + /* length of header */ + total = p->buf[4]; + while (size <= 8 && !(total & len_mask)) { + size++; + len_mask >>= 1; + } + if (size > 8) + return 0; + total &= (len_mask - 1); + while (n < size) + total = (total << 8) | p->buf[4 + n++]; + + /* does the probe data contain the whole header? */ + if (p->buf_size < 4 + size + total) + return 0; + + /* the header must contain the document type 'matroska'. For now, + * we don't parse the whole header but simply check for the + * availability of that array of characters inside the header. + * Not fully fool-proof, but good enough. */ + for (n = 4 + size; n <= 4 + size + total - sizeof(probe_data); n++) + if (!memcmp (&p->buf[n], probe_data, sizeof(probe_data))) + return AVPROBE_SCORE_MAX; + + return 0; +} + +/* + * From here on, it's all XML-style DTD stuff... Needs no comments. + */ + +static int +matroska_parse_info (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "Parsing info...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* cluster timecode */ + case MATROSKA_ID_TIMECODESCALE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + matroska->time_scale = num; + break; + } + + case MATROSKA_ID_DURATION: { + double num; + if ((res = ebml_read_float(matroska, &id, &num)) < 0) + break; + matroska->ctx->duration = num * matroska->time_scale * 1000 / AV_TIME_BASE; + break; + } + + case MATROSKA_ID_TITLE: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + strncpy(matroska->ctx->title, text, + sizeof(matroska->ctx->title)-1); + av_free(text); + break; + } + + case MATROSKA_ID_WRITINGAPP: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + matroska->writing_app = text; + break; + } + + case MATROSKA_ID_MUXINGAPP: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + matroska->muxing_app = text; + break; + } + + case MATROSKA_ID_DATEUTC: { + int64_t time; + if ((res = ebml_read_date(matroska, &id, &time)) < 0) + break; + matroska->created = time; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in info header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_add_stream (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + MatroskaTrack *track; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing track, adding stream..,\n"); + + /* Allocate a generic track. As soon as we know its type we'll realloc. */ + track = av_mallocz(MAX_TRACK_SIZE); + matroska->num_tracks++; + strcpy(track->language, "eng"); + + /* start with the master */ + if ((res = ebml_read_master(matroska, &id)) < 0) + return res; + + /* try reading the trackentry headers */ + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up > 0) { + matroska->level_up--; + break; + } + + switch (id) { + /* track number (unique stream ID) */ + case MATROSKA_ID_TRACKNUMBER: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + track->num = num; + break; + } + + /* track UID (unique identifier) */ + case MATROSKA_ID_TRACKUID: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + track->uid = num; + break; + } + + /* track type (video, audio, combined, subtitle, etc.) */ + case MATROSKA_ID_TRACKTYPE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (track->type && track->type != num) { + av_log(matroska->ctx, AV_LOG_INFO, + "More than one tracktype in an entry - skip\n"); + break; + } + track->type = num; + + switch (track->type) { + case MATROSKA_TRACK_TYPE_VIDEO: + case MATROSKA_TRACK_TYPE_AUDIO: + case MATROSKA_TRACK_TYPE_SUBTITLE: + break; + case MATROSKA_TRACK_TYPE_COMPLEX: + case MATROSKA_TRACK_TYPE_LOGO: + case MATROSKA_TRACK_TYPE_CONTROL: + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown or unsupported track type 0x%x\n", + track->type); + track->type = 0; + break; + } + matroska->tracks[matroska->num_tracks - 1] = track; + break; + } + + /* tracktype specific stuff for video */ + case MATROSKA_ID_TRACKVIDEO: { + MatroskaVideoTrack *videotrack; + if (!track->type) + track->type = MATROSKA_TRACK_TYPE_VIDEO; + if (track->type != MATROSKA_TRACK_TYPE_VIDEO) { + av_log(matroska->ctx, AV_LOG_INFO, + "video data in non-video track - ignoring\n"); + res = AVERROR_INVALIDDATA; + break; + } else if ((res = ebml_read_master(matroska, &id)) < 0) + break; + videotrack = (MatroskaVideoTrack *)track; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up > 0) { + matroska->level_up--; + break; + } + + switch (id) { + /* fixme, this should be one-up, but I get it here */ + case MATROSKA_ID_TRACKDEFAULTDURATION: { + uint64_t num; + if ((res = ebml_read_uint (matroska, &id, + &num)) < 0) + break; + track->default_duration = num; + break; + } + + /* video framerate */ + case MATROSKA_ID_VIDEOFRAMERATE: { + double num; + if ((res = ebml_read_float(matroska, &id, + &num)) < 0) + break; + if (!track->default_duration) + track->default_duration = 1000000000/num; + break; + } + + /* width of the size to display the video at */ + case MATROSKA_ID_VIDEODISPLAYWIDTH: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->display_width = num; + break; + } + + /* height of the size to display the video at */ + case MATROSKA_ID_VIDEODISPLAYHEIGHT: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->display_height = num; + break; + } + + /* width of the video in the file */ + case MATROSKA_ID_VIDEOPIXELWIDTH: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->pixel_width = num; + break; + } + + /* height of the video in the file */ + case MATROSKA_ID_VIDEOPIXELHEIGHT: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->pixel_height = num; + break; + } + + /* whether the video is interlaced */ + case MATROSKA_ID_VIDEOFLAGINTERLACED: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + if (num) + track->flags |= + MATROSKA_VIDEOTRACK_INTERLACED; + else + track->flags &= + ~MATROSKA_VIDEOTRACK_INTERLACED; + break; + } + + /* stereo mode (whether the video has two streams, + * where one is for the left eye and the other for + * the right eye, which creates a 3D-like + * effect) */ + case MATROSKA_ID_VIDEOSTEREOMODE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + if (num != MATROSKA_EYE_MODE_MONO && + num != MATROSKA_EYE_MODE_LEFT && + num != MATROSKA_EYE_MODE_RIGHT && + num != MATROSKA_EYE_MODE_BOTH) { + av_log(matroska->ctx, AV_LOG_INFO, + "Ignoring unknown eye mode 0x%x\n", + (uint32_t) num); + break; + } + videotrack->eye_mode = num; + break; + } + + /* aspect ratio behaviour */ + case MATROSKA_ID_VIDEOASPECTRATIO: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + if (num != MATROSKA_ASPECT_RATIO_MODE_FREE && + num != MATROSKA_ASPECT_RATIO_MODE_KEEP && + num != MATROSKA_ASPECT_RATIO_MODE_FIXED) { + av_log(matroska->ctx, AV_LOG_INFO, + "Ignoring unknown aspect ratio 0x%x\n", + (uint32_t) num); + break; + } + videotrack->ar_mode = num; + break; + } + + /* colorspace (only matters for raw video) + * fourcc */ + case MATROSKA_ID_VIDEOCOLORSPACE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + videotrack->fourcc = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown video track header entry " + "0x%x - ignoring\n", id); + /* pass-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + break; + } + + /* tracktype specific stuff for audio */ + case MATROSKA_ID_TRACKAUDIO: { + MatroskaAudioTrack *audiotrack; + if (!track->type) + track->type = MATROSKA_TRACK_TYPE_AUDIO; + if (track->type != MATROSKA_TRACK_TYPE_AUDIO) { + av_log(matroska->ctx, AV_LOG_INFO, + "audio data in non-audio track - ignoring\n"); + res = AVERROR_INVALIDDATA; + break; + } else if ((res = ebml_read_master(matroska, &id)) < 0) + break; + audiotrack = (MatroskaAudioTrack *)track; + audiotrack->channels = 1; + audiotrack->samplerate = 8000; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up > 0) { + matroska->level_up--; + break; + } + + switch (id) { + /* samplerate */ + case MATROSKA_ID_AUDIOSAMPLINGFREQ: { + double num; + if ((res = ebml_read_float(matroska, &id, + &num)) < 0) + break; + audiotrack->internal_samplerate = + audiotrack->samplerate = num; + break; + } + + case MATROSKA_ID_AUDIOOUTSAMPLINGFREQ: { + double num; + if ((res = ebml_read_float(matroska, &id, + &num)) < 0) + break; + audiotrack->samplerate = num; + break; + } + + /* bitdepth */ + case MATROSKA_ID_AUDIOBITDEPTH: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + audiotrack->bitdepth = num; + break; + } + + /* channels */ + case MATROSKA_ID_AUDIOCHANNELS: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, + &num)) < 0) + break; + audiotrack->channels = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown audio track header entry " + "0x%x - ignoring\n", id); + /* pass-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + break; + } + + /* codec identifier */ + case MATROSKA_ID_CODECID: { + char *text; + if ((res = ebml_read_ascii(matroska, &id, &text)) < 0) + break; + track->codec_id = text; + break; + } + + /* codec private data */ + case MATROSKA_ID_CODECPRIVATE: { + uint8_t *data; + int size; + if ((res = ebml_read_binary(matroska, &id, &data, &size) < 0)) + break; + track->codec_priv = data; + track->codec_priv_size = size; + break; + } + + /* name of the codec */ + case MATROSKA_ID_CODECNAME: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + track->codec_name = text; + break; + } + + /* name of this track */ + case MATROSKA_ID_TRACKNAME: { + char *text; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + track->name = text; + break; + } + + /* language (matters for audio/subtitles, mostly) */ + case MATROSKA_ID_TRACKLANGUAGE: { + char *text, *end; + if ((res = ebml_read_utf8(matroska, &id, &text)) < 0) + break; + if ((end = strchr(text, '-'))) + *end = '\0'; + if (strlen(text) == 3) + strcpy(track->language, text); + av_free(text); + break; + } + + /* whether this is actually used */ + case MATROSKA_ID_TRACKFLAGENABLED: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (num) + track->flags |= MATROSKA_TRACK_ENABLED; + else + track->flags &= ~MATROSKA_TRACK_ENABLED; + break; + } + + /* whether it's the default for this track type */ + case MATROSKA_ID_TRACKFLAGDEFAULT: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (num) + track->flags |= MATROSKA_TRACK_DEFAULT; + else + track->flags &= ~MATROSKA_TRACK_DEFAULT; + break; + } + + /* lacing (like MPEG, where blocks don't end/start on frame + * boundaries) */ + case MATROSKA_ID_TRACKFLAGLACING: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + if (num) + track->flags |= MATROSKA_TRACK_LACING; + else + track->flags &= ~MATROSKA_TRACK_LACING; + break; + } + + /* default length (in time) of one data block in this track */ + case MATROSKA_ID_TRACKDEFAULTDURATION: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + track->default_duration = num; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown track header entry 0x%x - ignoring\n", id); + /* pass-through */ + + case EBML_ID_VOID: + /* we ignore these because they're nothing useful. */ + case MATROSKA_ID_CODECINFOURL: + case MATROSKA_ID_CODECDOWNLOADURL: + case MATROSKA_ID_TRACKMINCACHE: + case MATROSKA_ID_TRACKMAXCACHE: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_tracks (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing tracks...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* one track within the "all-tracks" header */ + case MATROSKA_ID_TRACKENTRY: + res = matroska_add_stream(matroska); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in track header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_index (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + MatroskaDemuxIndex idx; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing index...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* one single index entry ('point') */ + case MATROSKA_ID_POINTENTRY: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + /* in the end, we hope to fill one entry with a + * timestamp, a file position and a tracknum */ + idx.pos = (uint64_t) -1; + idx.time = (uint64_t) -1; + idx.track = (uint16_t) -1; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* one single index entry ('point') */ + case MATROSKA_ID_CUETIME: { + uint64_t time; + if ((res = ebml_read_uint(matroska, &id, + &time)) < 0) + break; + idx.time = time * matroska->time_scale; + break; + } + + /* position in the file + track to which it + * belongs */ + case MATROSKA_ID_CUETRACKPOSITION: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + while (res == 0) { + if (!(id = ebml_peek_id (matroska, + &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* track number */ + case MATROSKA_ID_CUETRACK: { + uint64_t num; + if ((res = ebml_read_uint(matroska, + &id, &num)) < 0) + break; + idx.track = num; + break; + } + + /* position in file */ + case MATROSKA_ID_CUECLUSTERPOSITION: { + uint64_t num; + if ((res = ebml_read_uint(matroska, + &id, &num)) < 0) + break; + idx.pos = num+matroska->segment_start; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in " + "CuesTrackPositions\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in cuespoint " + "index\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + /* so let's see if we got what we wanted */ + if (idx.pos != (uint64_t) -1 && + idx.time != (uint64_t) -1 && + idx.track != (uint16_t) -1) { + if (matroska->num_indexes % 32 == 0) { + /* re-allocate bigger index */ + matroska->index = + av_realloc(matroska->index, + (matroska->num_indexes + 32) * + sizeof(MatroskaDemuxIndex)); + } + matroska->index[matroska->num_indexes] = idx; + matroska->num_indexes++; + } + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in cues header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_metadata (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* Hm, this is unsupported... */ + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in metadata header\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_seekhead (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing seekhead...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_SEEKENTRY: { + uint32_t seek_id = 0, peek_id_cache = 0; + uint64_t seek_pos = (uint64_t) -1, t; + + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_SEEKID: + res = ebml_read_uint(matroska, &id, &t); + seek_id = t; + break; + + case MATROSKA_ID_SEEKPOSITION: + res = ebml_read_uint(matroska, &id, &seek_pos); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown seekhead ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (!seek_id || seek_pos == (uint64_t) -1) { + av_log(matroska->ctx, AV_LOG_INFO, + "Incomplete seekhead entry (0x%x/%"PRIu64")\n", + seek_id, seek_pos); + break; + } + + switch (seek_id) { + case MATROSKA_ID_CUES: + case MATROSKA_ID_TAGS: { + uint32_t level_up = matroska->level_up; + offset_t before_pos; + uint64_t length; + MatroskaLevel level; + + /* remember the peeked ID and the current position */ + peek_id_cache = matroska->peek_id; + before_pos = url_ftell(matroska->ctx->pb); + + /* seek */ + if ((res = ebml_read_seek(matroska, seek_pos + + matroska->segment_start)) < 0) + return res; + + /* we don't want to lose our seekhead level, so we add + * a dummy. This is a crude hack. */ + if (matroska->num_levels == EBML_MAX_DEPTH) { + av_log(matroska->ctx, AV_LOG_INFO, + "Max EBML element depth (%d) reached, " + "cannot parse further.\n", EBML_MAX_DEPTH); + return AVERROR_UNKNOWN; + } + + level.start = 0; + level.length = (uint64_t)-1; + matroska->levels[matroska->num_levels] = level; + matroska->num_levels++; + + /* check ID */ + if (!(id = ebml_peek_id (matroska, + &matroska->level_up))) + goto finish; + if (id != seek_id) { + av_log(matroska->ctx, AV_LOG_INFO, + "We looked for ID=0x%x but got " + "ID=0x%x (pos=%"PRIu64")", + seek_id, id, seek_pos + + matroska->segment_start); + goto finish; + } + + /* read master + parse */ + if ((res = ebml_read_master(matroska, &id)) < 0) + goto finish; + switch (id) { + case MATROSKA_ID_CUES: + if (!(res = matroska_parse_index(matroska)) || + url_feof(matroska->ctx->pb)) { + matroska->index_parsed = 1; + res = 0; + } + break; + case MATROSKA_ID_TAGS: + if (!(res = matroska_parse_metadata(matroska)) || + url_feof(matroska->ctx->pb)) { + matroska->metadata_parsed = 1; + res = 0; + } + break; + } + + finish: + /* remove dummy level */ + while (matroska->num_levels) { + matroska->num_levels--; + length = + matroska->levels[matroska->num_levels].length; + if (length == (uint64_t)-1) + break; + } + + /* seek back */ + if ((res = ebml_read_seek(matroska, before_pos)) < 0) + return res; + matroska->peek_id = peek_id_cache; + matroska->level_up = level_up; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Ignoring seekhead entry for ID=0x%x\n", + seek_id); + break; + } + + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown seekhead ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_parse_attachments(AVFormatContext *s) +{ + MatroskaDemuxContext *matroska = s->priv_data; + int res = 0; + uint32_t id; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing attachments...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_ATTACHEDFILE: { + char* name = NULL; + char* mime = NULL; + uint8_t* data = NULL; + int i, data_size = 0; + AVStream *st; + + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_FILENAME: + res = ebml_read_utf8 (matroska, &id, &name); + break; + + case MATROSKA_ID_FILEMIMETYPE: + res = ebml_read_ascii (matroska, &id, &mime); + break; + + case MATROSKA_ID_FILEDATA: + res = ebml_read_binary(matroska, &id, &data, &data_size); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown attachedfile ID 0x%x\n", id); + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (!(name && mime && data && data_size > 0)) { + av_log(matroska->ctx, AV_LOG_ERROR, "incomplete attachment\n"); + break; + } + + st = av_new_stream(s, matroska->num_streams++); + if (st == NULL) + return AVERROR(ENOMEM); + st->filename = av_strdup(name); + st->codec->codec_id = CODEC_ID_NONE; + st->codec->codec_type = CODEC_TYPE_ATTACHMENT; + st->codec->extradata = av_malloc(data_size); + if(st->codec->extradata == NULL) + return AVERROR(ENOMEM); + st->codec->extradata_size = data_size; + memcpy(st->codec->extradata, data, data_size); + + for (i=0; ff_mkv_mime_tags[i].id != CODEC_ID_NONE; i++) { + if (!strncmp(ff_mkv_mime_tags[i].str, mime, + strlen(ff_mkv_mime_tags[i].str))) { + st->codec->codec_id = ff_mkv_mime_tags[i].id; + break; + } + } + + av_log(matroska->ctx, AV_LOG_DEBUG, "new attachment: %s, %s, size %d \n", name, mime, data_size); + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown attachments ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) + +static int +matroska_aac_profile (char *codec_id) +{ + static const char *aac_profiles[] = { + "MAIN", "LC", "SSR" + }; + int profile; + + for (profile=0; profile<ARRAY_SIZE(aac_profiles); profile++) + if (strstr(codec_id, aac_profiles[profile])) + break; + return profile + 1; +} + +static int +matroska_aac_sri (int samplerate) +{ + static const int aac_sample_rates[] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, + }; + int sri; + + for (sri=0; sri<ARRAY_SIZE(aac_sample_rates); sri++) + if (aac_sample_rates[sri] == samplerate) + break; + return sri; +} + +static int +matroska_read_header (AVFormatContext *s, + AVFormatParameters *ap) +{ + MatroskaDemuxContext *matroska = s->priv_data; + char *doctype; + int version, last_level, res = 0; + uint32_t id; + + matroska->ctx = s; + + /* First read the EBML header. */ + doctype = NULL; + if ((res = ebml_read_header(matroska, &doctype, &version)) < 0) + return res; + if ((doctype == NULL) || strcmp(doctype, "matroska")) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Wrong EBML doctype ('%s' != 'matroska').\n", + doctype ? doctype : "(none)"); + if (doctype) + av_free(doctype); + return AVERROR_NOFMT; + } + av_free(doctype); + if (version > 2) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Matroska demuxer version 2 too old for file version %d\n", + version); + return AVERROR_NOFMT; + } + + /* The next thing is a segment. */ + while (1) { + if (!(id = ebml_peek_id(matroska, &last_level))) + return AVERROR(EIO); + if (id == MATROSKA_ID_SEGMENT) + break; + + /* oi! */ + av_log(matroska->ctx, AV_LOG_INFO, + "Expected a Segment ID (0x%x), but received 0x%x!\n", + MATROSKA_ID_SEGMENT, id); + if ((res = ebml_read_skip(matroska)) < 0) + return res; + } + + /* We now have a Matroska segment. + * Seeks are from the beginning of the segment, + * after the segment ID/length. */ + if ((res = ebml_read_master(matroska, &id)) < 0) + return res; + matroska->segment_start = url_ftell(s->pb); + + matroska->time_scale = 1000000; + /* we've found our segment, start reading the different contents in here */ + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* stream info */ + case MATROSKA_ID_INFO: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_info(matroska); + break; + } + + /* track info headers */ + case MATROSKA_ID_TRACKS: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_tracks(matroska); + break; + } + + /* stream index */ + case MATROSKA_ID_CUES: { + if (!matroska->index_parsed) { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_index(matroska); + } else + res = ebml_read_skip(matroska); + break; + } + + /* metadata */ + case MATROSKA_ID_TAGS: { + if (!matroska->metadata_parsed) { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_metadata(matroska); + } else + res = ebml_read_skip(matroska); + break; + } + + /* file index (if seekable, seek to Cues/Tags to parse it) */ + case MATROSKA_ID_SEEKHEAD: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_seekhead(matroska); + break; + } + + case MATROSKA_ID_ATTACHMENTS: { + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_attachments(s); + break; + } + + case MATROSKA_ID_CLUSTER: { + /* Do not read the master - this will be done in the next + * call to matroska_read_packet. */ + res = 1; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown matroska file header ID 0x%x\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + /* Have we found a cluster? */ + if (ebml_peek_id(matroska, NULL) == MATROSKA_ID_CLUSTER) { + int i, j; + MatroskaTrack *track; + AVStream *st; + + for (i = 0; i < matroska->num_tracks; i++) { + enum CodecID codec_id = CODEC_ID_NONE; + uint8_t *extradata = NULL; + int extradata_size = 0; + int extradata_offset = 0; + track = matroska->tracks[i]; + track->stream_index = -1; + + /* Apply some sanity checks. */ + if (track->codec_id == NULL) + continue; + + for(j=0; ff_mkv_codec_tags[j].id != CODEC_ID_NONE; j++){ + if(!strncmp(ff_mkv_codec_tags[j].str, track->codec_id, + strlen(ff_mkv_codec_tags[j].str))){ + codec_id= ff_mkv_codec_tags[j].id; + break; + } + } + + /* Set the FourCC from the CodecID. */ + /* This is the MS compatibility mode which stores a + * BITMAPINFOHEADER in the CodecPrivate. */ + if (!strcmp(track->codec_id, + MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC) && + (track->codec_priv_size >= 40) && + (track->codec_priv != NULL)) { + MatroskaVideoTrack *vtrack = (MatroskaVideoTrack *) track; + + /* Offset of biCompression. Stored in LE. */ + vtrack->fourcc = AV_RL32(track->codec_priv + 16); + codec_id = codec_get_id(codec_bmp_tags, vtrack->fourcc); + + } + + /* This is the MS compatibility mode which stores a + * WAVEFORMATEX in the CodecPrivate. */ + else if (!strcmp(track->codec_id, + MATROSKA_CODEC_ID_AUDIO_ACM) && + (track->codec_priv_size >= 18) && + (track->codec_priv != NULL)) { + uint16_t tag; + + /* Offset of wFormatTag. Stored in LE. */ + tag = AV_RL16(track->codec_priv); + codec_id = codec_get_id(codec_wav_tags, tag); + + } + + else if (codec_id == CODEC_ID_AAC && !track->codec_priv_size) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track; + int profile = matroska_aac_profile(track->codec_id); + int sri = matroska_aac_sri(audiotrack->internal_samplerate); + extradata = av_malloc(5); + if (extradata == NULL) + return AVERROR(ENOMEM); + extradata[0] = (profile << 3) | ((sri&0x0E) >> 1); + extradata[1] = ((sri&0x01) << 7) | (audiotrack->channels<<3); + if (strstr(track->codec_id, "SBR")) { + sri = matroska_aac_sri(audiotrack->samplerate); + extradata[2] = 0x56; + extradata[3] = 0xE5; + extradata[4] = 0x80 | (sri<<3); + extradata_size = 5; + } else { + extradata_size = 2; + } + } + + else if (codec_id == CODEC_ID_TTA) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *) track; + ByteIOContext b; + extradata_size = 30; + extradata = av_mallocz(extradata_size); + if (extradata == NULL) + return AVERROR(ENOMEM); + init_put_byte(&b, extradata, extradata_size, 1, + NULL, NULL, NULL, NULL); + put_buffer(&b, "TTA1", 4); + put_le16(&b, 1); + put_le16(&b, audiotrack->channels); + put_le16(&b, audiotrack->bitdepth); + put_le32(&b, audiotrack->samplerate); + put_le32(&b, matroska->ctx->duration * audiotrack->samplerate); + } + + else if (codec_id == CODEC_ID_RV10 || codec_id == CODEC_ID_RV20 || + codec_id == CODEC_ID_RV30 || codec_id == CODEC_ID_RV40) { + extradata_offset = 26; + track->codec_priv_size -= extradata_offset; + } + + else if (codec_id == CODEC_ID_RA_144) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track; + audiotrack->samplerate = 8000; + audiotrack->channels = 1; + } + + else if (codec_id == CODEC_ID_RA_288 || + codec_id == CODEC_ID_COOK || + codec_id == CODEC_ID_ATRAC3) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track; + ByteIOContext b; + + init_put_byte(&b, track->codec_priv, track->codec_priv_size, 0, + NULL, NULL, NULL, NULL); + url_fskip(&b, 24); + audiotrack->coded_framesize = get_be32(&b); + url_fskip(&b, 12); + audiotrack->sub_packet_h = get_be16(&b); + audiotrack->frame_size = get_be16(&b); + audiotrack->sub_packet_size = get_be16(&b); + audiotrack->buf = av_malloc(audiotrack->frame_size * audiotrack->sub_packet_h); + if (codec_id == CODEC_ID_RA_288) { + audiotrack->block_align = audiotrack->coded_framesize; + track->codec_priv_size = 0; + } else { + audiotrack->block_align = audiotrack->sub_packet_size; + extradata_offset = 78; + track->codec_priv_size -= extradata_offset; + } + } + + if (codec_id == CODEC_ID_NONE) { + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown/unsupported CodecID %s.\n", + track->codec_id); + } + + track->stream_index = matroska->num_streams; + + matroska->num_streams++; + st = av_new_stream(s, track->stream_index); + if (st == NULL) + return AVERROR(ENOMEM); + av_set_pts_info(st, 64, matroska->time_scale, 1000*1000*1000); /* 64 bit pts in ns */ + + st->codec->codec_id = codec_id; + st->start_time = 0; + if (strcmp(track->language, "und")) + strcpy(st->language, track->language); + + if (track->default_duration) + av_reduce(&st->codec->time_base.num, &st->codec->time_base.den, + track->default_duration, 1000000000, 30000); + + if(extradata){ + st->codec->extradata = extradata; + st->codec->extradata_size = extradata_size; + } else if(track->codec_priv && track->codec_priv_size > 0){ + st->codec->extradata = av_malloc(track->codec_priv_size); + if(st->codec->extradata == NULL) + return AVERROR(ENOMEM); + st->codec->extradata_size = track->codec_priv_size; + memcpy(st->codec->extradata,track->codec_priv+extradata_offset, + track->codec_priv_size); + } + + if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { + MatroskaVideoTrack *videotrack = (MatroskaVideoTrack *)track; + + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_tag = videotrack->fourcc; + st->codec->width = videotrack->pixel_width; + st->codec->height = videotrack->pixel_height; + if (videotrack->display_width == 0) + videotrack->display_width= videotrack->pixel_width; + if (videotrack->display_height == 0) + videotrack->display_height= videotrack->pixel_height; + av_reduce(&st->codec->sample_aspect_ratio.num, + &st->codec->sample_aspect_ratio.den, + st->codec->height * videotrack->display_width, + st->codec-> width * videotrack->display_height, + 255); + st->need_parsing = AVSTREAM_PARSE_HEADERS; + } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track; + + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->sample_rate = audiotrack->samplerate; + st->codec->channels = audiotrack->channels; + st->codec->block_align = audiotrack->block_align; + } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { + st->codec->codec_type = CODEC_TYPE_SUBTITLE; + } + + /* What do we do with private data? E.g. for Vorbis. */ + } + res = 0; + } + + if (matroska->index_parsed) { + int i, track, stream; + for (i=0; i<matroska->num_indexes; i++) { + MatroskaDemuxIndex *idx = &matroska->index[i]; + track = matroska_find_track_by_num(matroska, idx->track); + stream = matroska->tracks[track]->stream_index; + if (stream >= 0) + av_add_index_entry(matroska->ctx->streams[stream], + idx->pos, idx->time/matroska->time_scale, + 0, 0, AVINDEX_KEYFRAME); + } + } + + return res; +} + +static int +matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size, + int64_t pos, uint64_t cluster_time, uint64_t duration, + int is_keyframe, int is_bframe) +{ + int res = 0; + int track; + AVStream *st; + AVPacket *pkt; + uint8_t *origdata = data; + int16_t block_time; + uint32_t *lace_size = NULL; + int n, flags, laces = 0; + uint64_t num; + + /* first byte(s): tracknum */ + if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) { + av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); + av_free(origdata); + return res; + } + data += n; + size -= n; + + /* fetch track from num */ + track = matroska_find_track_by_num(matroska, num); + if (size <= 3 || track < 0 || track >= matroska->num_tracks) { + av_log(matroska->ctx, AV_LOG_INFO, + "Invalid stream %d or size %u\n", track, size); + av_free(origdata); + return res; + } + if (matroska->tracks[track]->stream_index < 0) { + av_free(origdata); + return res; + } + st = matroska->ctx->streams[matroska->tracks[track]->stream_index]; + if (st->discard >= AVDISCARD_ALL) { + av_free(origdata); + return res; + } + if (duration == AV_NOPTS_VALUE) + duration = matroska->tracks[track]->default_duration / matroska->time_scale; + + /* block_time (relative to cluster time) */ + block_time = AV_RB16(data); + data += 2; + flags = *data++; + size -= 3; + if (is_keyframe == -1) + is_keyframe = flags & 0x80 ? PKT_FLAG_KEY : 0; + + if (matroska->skip_to_keyframe) { + if (!is_keyframe || st != matroska->skip_to_stream) { + av_free(origdata); + return res; + } + matroska->skip_to_keyframe = 0; + } + + switch ((flags & 0x06) >> 1) { + case 0x0: /* no lacing */ + laces = 1; + lace_size = av_mallocz(sizeof(int)); + lace_size[0] = size; + break; + + case 0x1: /* xiph lacing */ + case 0x2: /* fixed-size lacing */ + case 0x3: /* EBML lacing */ + if (size == 0) { + res = -1; + break; + } + laces = (*data) + 1; + data += 1; + size -= 1; + lace_size = av_mallocz(laces * sizeof(int)); + + switch ((flags & 0x06) >> 1) { + case 0x1: /* xiph lacing */ { + uint8_t temp; + uint32_t total = 0; + for (n = 0; res == 0 && n < laces - 1; n++) { + while (1) { + if (size == 0) { + res = -1; + break; + } + temp = *data; + lace_size[n] += temp; + data += 1; + size -= 1; + if (temp != 0xff) + break; + } + total += lace_size[n]; + } + lace_size[n] = size - total; + break; + } + + case 0x2: /* fixed-size lacing */ + for (n = 0; n < laces; n++) + lace_size[n] = size / laces; + break; + + case 0x3: /* EBML lacing */ { + uint32_t total; + n = matroska_ebmlnum_uint(data, size, &num); + if (n < 0) { + av_log(matroska->ctx, AV_LOG_INFO, + "EBML block data error\n"); + break; + } + data += n; + size -= n; + total = lace_size[0] = num; + for (n = 1; res == 0 && n < laces - 1; n++) { + int64_t snum; + int r; + r = matroska_ebmlnum_sint (data, size, &snum); + if (r < 0) { + av_log(matroska->ctx, AV_LOG_INFO, + "EBML block data error\n"); + break; + } + data += r; + size -= r; + lace_size[n] = lace_size[n - 1] + snum; + total += lace_size[n]; + } + lace_size[n] = size - total; + break; + } + } + break; + } + + if (res == 0) { + uint64_t timecode = AV_NOPTS_VALUE; + + if (cluster_time != (uint64_t)-1 + && (block_time >= 0 || cluster_time >= -block_time)) + timecode = cluster_time + block_time; + + for (n = 0; n < laces; n++) { + if (st->codec->codec_id == CODEC_ID_RA_288 || + st->codec->codec_id == CODEC_ID_COOK || + st->codec->codec_id == CODEC_ID_ATRAC3) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)matroska->tracks[track]; + int a = st->codec->block_align; + int sps = audiotrack->sub_packet_size; + int cfs = audiotrack->coded_framesize; + int h = audiotrack->sub_packet_h; + int y = audiotrack->sub_packet_cnt; + int w = audiotrack->frame_size; + int x; + + if (!audiotrack->pkt_cnt) { + if (st->codec->codec_id == CODEC_ID_RA_288) + for (x=0; x<h/2; x++) + memcpy(audiotrack->buf+x*2*w+y*cfs, + data+x*cfs, cfs); + else + for (x=0; x<w/sps; x++) + memcpy(audiotrack->buf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), data+x*sps, sps); + + if (++audiotrack->sub_packet_cnt >= h) { + audiotrack->sub_packet_cnt = 0; + audiotrack->pkt_cnt = h*w / a; + } + } + while (audiotrack->pkt_cnt) { + pkt = av_mallocz(sizeof(AVPacket)); + av_new_packet(pkt, a); + memcpy(pkt->data, audiotrack->buf + + a * (h*w / a - audiotrack->pkt_cnt--), a); + pkt->pos = pos; + pkt->stream_index = matroska->tracks[track]->stream_index; + matroska_queue_packet(matroska, pkt); + } + } else { + int offset = 0; + + pkt = av_mallocz(sizeof(AVPacket)); + /* XXX: prevent data copy... */ + if (av_new_packet(pkt, lace_size[n]-offset) < 0) { + res = AVERROR(ENOMEM); + n = laces-1; + break; + } + memcpy (pkt->data, data+offset, lace_size[n]-offset); + + if (n == 0) + pkt->flags = is_keyframe; + pkt->stream_index = matroska->tracks[track]->stream_index; + + pkt->pts = timecode; + pkt->pos = pos; + pkt->duration = duration; + + matroska_queue_packet(matroska, pkt); + } + + if (timecode != AV_NOPTS_VALUE) + timecode = duration ? timecode + duration : AV_NOPTS_VALUE; + data += lace_size[n]; + } + } + + av_free(lace_size); + av_free(origdata); + return res; +} + +static int +matroska_parse_blockgroup (MatroskaDemuxContext *matroska, + uint64_t cluster_time) +{ + int res = 0; + uint32_t id; + int is_bframe = 0; + int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets; + uint64_t duration = AV_NOPTS_VALUE; + uint8_t *data; + int size = 0; + int64_t pos = 0; + + av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n"); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* one block inside the group. Note, block parsing is one + * of the harder things, so this code is a bit complicated. + * See http://www.matroska.org/ for documentation. */ + case MATROSKA_ID_BLOCK: { + pos = url_ftell(matroska->ctx->pb); + res = ebml_read_binary(matroska, &id, &data, &size); + break; + } + + case MATROSKA_ID_BLOCKDURATION: { + if ((res = ebml_read_uint(matroska, &id, &duration)) < 0) + break; + break; + } + + case MATROSKA_ID_BLOCKREFERENCE: { + int64_t num; + /* We've found a reference, so not even the first frame in + * the lace is a key frame. */ + is_keyframe = 0; + if (last_num_packets != matroska->num_packets) + matroska->packets[last_num_packets]->flags = 0; + if ((res = ebml_read_sint(matroska, &id, &num)) < 0) + break; + if (num > 0) + is_bframe = 1; + break; + } + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in blockgroup data\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (res) + return res; + + if (size > 0) + res = matroska_parse_block(matroska, data, size, pos, cluster_time, + duration, is_keyframe, is_bframe); + + return res; +} + +static int +matroska_parse_cluster (MatroskaDemuxContext *matroska) +{ + int res = 0; + uint32_t id; + uint64_t cluster_time = 0; + uint8_t *data; + int64_t pos; + int size; + + av_log(matroska->ctx, AV_LOG_DEBUG, + "parsing cluster at %"PRId64"\n", url_ftell(matroska->ctx->pb)); + + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + res = AVERROR(EIO); + break; + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + /* cluster timecode */ + case MATROSKA_ID_CLUSTERTIMECODE: { + uint64_t num; + if ((res = ebml_read_uint(matroska, &id, &num)) < 0) + break; + cluster_time = num; + break; + } + + /* a group of blocks inside a cluster */ + case MATROSKA_ID_BLOCKGROUP: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + res = matroska_parse_blockgroup(matroska, cluster_time); + break; + + case MATROSKA_ID_SIMPLEBLOCK: + pos = url_ftell(matroska->ctx->pb); + res = ebml_read_binary(matroska, &id, &data, &size); + if (res == 0) + res = matroska_parse_block(matroska, data, size, pos, + cluster_time, AV_NOPTS_VALUE, + -1, 0); + break; + + default: + av_log(matroska->ctx, AV_LOG_INFO, + "Unknown entry 0x%x in cluster data\n", id); + /* fall-through */ + + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + return res; +} + +static int +matroska_read_packet (AVFormatContext *s, + AVPacket *pkt) +{ + MatroskaDemuxContext *matroska = s->priv_data; + int res; + uint32_t id; + + /* Read stream until we have a packet queued. */ + while (matroska_deliver_packet(matroska, pkt)) { + + /* Have we already reached the end? */ + if (matroska->done) + return AVERROR(EIO); + + res = 0; + while (res == 0) { + if (!(id = ebml_peek_id(matroska, &matroska->level_up))) { + return AVERROR(EIO); + } else if (matroska->level_up) { + matroska->level_up--; + break; + } + + switch (id) { + case MATROSKA_ID_CLUSTER: + if ((res = ebml_read_master(matroska, &id)) < 0) + break; + if ((res = matroska_parse_cluster(matroska)) == 0) + res = 1; /* Parsed one cluster, let's get out. */ + break; + + default: + case EBML_ID_VOID: + res = ebml_read_skip(matroska); + break; + } + + if (matroska->level_up) { + matroska->level_up--; + break; + } + } + + if (res == -1) + matroska->done = 1; + } + + return 0; +} + +static int +matroska_read_seek (AVFormatContext *s, int stream_index, int64_t timestamp, + int flags) +{ + MatroskaDemuxContext *matroska = s->priv_data; + AVStream *st = s->streams[stream_index]; + int index; + + /* find index entry */ + index = av_index_search_timestamp(st, timestamp, flags); + if (index < 0) + return 0; + + matroska_clear_queue(matroska); + + /* do the seek */ + url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); + matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY); + matroska->skip_to_stream = st; + matroska->peek_id = 0; + return 0; +} + +static int +matroska_read_close (AVFormatContext *s) +{ + MatroskaDemuxContext *matroska = s->priv_data; + int n = 0; + + av_free(matroska->writing_app); + av_free(matroska->muxing_app); + av_free(matroska->index); + + matroska_clear_queue(matroska); + + for (n = 0; n < matroska->num_tracks; n++) { + MatroskaTrack *track = matroska->tracks[n]; + av_free(track->codec_id); + av_free(track->codec_name); + av_free(track->codec_priv); + av_free(track->name); + + if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { + MatroskaAudioTrack *audiotrack = (MatroskaAudioTrack *)track; + av_free(audiotrack->buf); + } + + av_free(track); + } + + return 0; +} + +AVInputFormat matroska_demuxer = { + "matroska", + "Matroska file format", + sizeof(MatroskaDemuxContext), + matroska_probe, + matroska_read_header, + matroska_read_packet, + matroska_read_close, + matroska_read_seek, +}; diff --git a/contrib/ffmpeg/libavformat/matroskaenc.c b/contrib/ffmpeg/libavformat/matroskaenc.c new file mode 100644 index 000000000..d096f7204 --- /dev/null +++ b/contrib/ffmpeg/libavformat/matroskaenc.c @@ -0,0 +1,845 @@ +/* + * Matroska muxer + * Copyright (c) 2007 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 "md5.h" +#include "riff.h" +#include "xiph.h" +#include "matroska.h" +#include "avc.h" + +typedef struct ebml_master { + offset_t pos; ///< absolute offset in the file where the master's elements start + int sizebytes; ///< how many bytes were reserved for the size +} ebml_master; + +typedef struct mkv_seekhead_entry { + unsigned int elementid; + uint64_t segmentpos; +} mkv_seekhead_entry; + +typedef struct mkv_seekhead { + offset_t filepos; + offset_t segment_offset; ///< the file offset to the beginning of the segment + int reserved_size; ///< -1 if appending to file + int max_entries; + mkv_seekhead_entry *entries; + int num_entries; +} mkv_seekhead; + +typedef struct { + uint64_t pts; + int tracknum; + offset_t cluster_pos; ///< file offset of the cluster containing the block +} mkv_cuepoint; + +typedef struct { + offset_t segment_offset; + mkv_cuepoint *entries; + int num_entries; +} mkv_cues; + +typedef struct MatroskaMuxContext { + ebml_master segment; + offset_t segment_offset; + offset_t segment_uid; + ebml_master cluster; + offset_t cluster_pos; ///< file offset of the current cluster + uint64_t cluster_pts; + offset_t duration_offset; + uint64_t duration; + mkv_seekhead *main_seekhead; + mkv_seekhead *cluster_seekhead; + mkv_cues *cues; + + struct AVMD5 *md5_ctx; +} MatroskaMuxContext; + + +/** 2 bytes * 3 for EBML IDs, 3 1-byte EBML lengths, 8 bytes for 64 bit + * offset, 4 bytes for target EBML ID */ +#define MAX_SEEKENTRY_SIZE 21 + +/** per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2 + * 8-byte uint max */ +#define MAX_CUETRACKPOS_SIZE 22 + +/** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */ +#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks + + +static int ebml_id_size(unsigned int id) +{ + return (av_log2(id+1)-1)/7+1; +} + +static void put_ebml_id(ByteIOContext *pb, unsigned int id) +{ + int i = ebml_id_size(id); + while (i--) + put_byte(pb, id >> (i*8)); +} + +/** + * Write an EBML size meaning "unknown size". + * + * @param bytes The number of bytes the size should occupy (maximum: 8). + */ +static void put_ebml_size_unknown(ByteIOContext *pb, int bytes) +{ + assert(bytes <= 8); + put_byte(pb, 0x1ff >> bytes); + while (--bytes) + put_byte(pb, 0xff); +} + +/** + * Calculate how many bytes are needed to represent a given number in EBML. + */ +static int ebml_num_size(uint64_t num) +{ + int bytes = 1; + while ((num+1) >> bytes*7) bytes++; + return bytes; +} + +/** + * Write a number in EBML variable length format. + * + * @param bytes The number of bytes that need to be used to write the number. + * If zero, any number of bytes can be used. + */ +static void put_ebml_num(ByteIOContext *pb, uint64_t num, int bytes) +{ + int i, needed_bytes = ebml_num_size(num); + + // sizes larger than this are currently undefined in EBML + assert(num < (1ULL<<56)-1); + + if (bytes == 0) + // don't care how many bytes are used, so use the min + bytes = needed_bytes; + // the bytes needed to write the given size would exceed the bytes + // that we need to use, so write unknown size. This shouldn't happen. + assert(bytes >= needed_bytes); + + num |= 1ULL << bytes*7; + for (i = bytes - 1; i >= 0; i--) + put_byte(pb, num >> i*8); +} + +static void put_ebml_uint(ByteIOContext *pb, unsigned int elementid, uint64_t val) +{ + int i, bytes = 1; + uint64_t tmp = val; + while (tmp>>=8) bytes++; + + put_ebml_id(pb, elementid); + put_ebml_num(pb, bytes, 0); + for (i = bytes - 1; i >= 0; i--) + put_byte(pb, val >> i*8); +} + +static void put_ebml_float(ByteIOContext *pb, unsigned int elementid, double val) +{ + put_ebml_id(pb, elementid); + put_ebml_num(pb, 8, 0); + put_be64(pb, av_dbl2int(val)); +} + +static void put_ebml_binary(ByteIOContext *pb, unsigned int elementid, + const uint8_t *buf, int size) +{ + put_ebml_id(pb, elementid); + put_ebml_num(pb, size, 0); + put_buffer(pb, buf, size); +} + +static void put_ebml_string(ByteIOContext *pb, unsigned int elementid, const char *str) +{ + put_ebml_binary(pb, elementid, str, strlen(str)); +} + +/** + * Writes a void element of a given size. Useful for reserving space in + * the file to be written to later. + * + * @param size The number of bytes to reserve, which must be at least 2. + */ +static void put_ebml_void(ByteIOContext *pb, uint64_t size) +{ + offset_t currentpos = url_ftell(pb); + + assert(size >= 2); + + put_ebml_id(pb, EBML_ID_VOID); + // we need to subtract the length needed to store the size from the + // size we need to reserve so 2 cases, we use 8 bytes to store the + // size if possible, 1 byte otherwise + if (size < 10) + put_ebml_num(pb, size-1, 0); + else + put_ebml_num(pb, size-9, 8); + while(url_ftell(pb) < currentpos + size) + put_byte(pb, 0); +} + +static ebml_master start_ebml_master(ByteIOContext *pb, unsigned int elementid, uint64_t expectedsize) +{ + int bytes = expectedsize ? ebml_num_size(expectedsize) : 8; + put_ebml_id(pb, elementid); + put_ebml_size_unknown(pb, bytes); + return (ebml_master){ url_ftell(pb), bytes }; +} + +static void end_ebml_master(ByteIOContext *pb, ebml_master master) +{ + offset_t pos = url_ftell(pb); + + // leave the unknown size for masters when streaming + if (url_is_streamed(pb)) + return; + + url_fseek(pb, master.pos - master.sizebytes, SEEK_SET); + put_ebml_num(pb, pos - master.pos, master.sizebytes); + url_fseek(pb, pos, SEEK_SET); +} + +static void put_xiph_size(ByteIOContext *pb, int size) +{ + int i; + for (i = 0; i < size / 255; i++) + put_byte(pb, 255); + put_byte(pb, size % 255); +} + +/** + * Initialize a mkv_seekhead element to be ready to index level 1 Matroska + * elements. If a maximum number of elements is specified, enough space + * will be reserved at the current file location to write a seek head of + * that size. + * + * @param segment_offset The absolute offset to the position in the file + * where the segment begins. + * @param numelements The maximum number of elements that will be indexed + * by this seek head, 0 if unlimited. + */ +static mkv_seekhead * mkv_start_seekhead(ByteIOContext *pb, offset_t segment_offset, int numelements) +{ + mkv_seekhead *new_seekhead = av_mallocz(sizeof(mkv_seekhead)); + if (new_seekhead == NULL) + return NULL; + + new_seekhead->segment_offset = segment_offset; + + if (numelements > 0) { + new_seekhead->filepos = url_ftell(pb); + // 21 bytes max for a seek entry, 10 bytes max for the SeekHead ID + // and size, and 3 bytes to guarantee that an EBML void element + // will fit afterwards + new_seekhead->reserved_size = numelements * MAX_SEEKENTRY_SIZE + 13; + new_seekhead->max_entries = numelements; + put_ebml_void(pb, new_seekhead->reserved_size); + } + return new_seekhead; +} + +static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos) +{ + mkv_seekhead_entry *entries = seekhead->entries; + + // don't store more elements than we reserved space for + if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries) + return -1; + + entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry)); + if (entries == NULL) + return AVERROR(ENOMEM); + + entries[seekhead->num_entries ].elementid = elementid; + entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset; + + seekhead->entries = entries; + return 0; +} + +/** + * Write the seek head to the file and free it. If a maximum number of + * elements was specified to mkv_start_seekhead(), the seek head will + * be written at the location reserved for it. Otherwise, it is written + * at the current location in the file. + * + * @return The file offset where the seekhead was written. + */ +static offset_t mkv_write_seekhead(ByteIOContext *pb, mkv_seekhead *seekhead) +{ + ebml_master metaseek, seekentry; + offset_t currentpos; + int i; + + currentpos = url_ftell(pb); + + if (seekhead->reserved_size > 0) + url_fseek(pb, seekhead->filepos, SEEK_SET); + + metaseek = start_ebml_master(pb, MATROSKA_ID_SEEKHEAD, seekhead->reserved_size); + for (i = 0; i < seekhead->num_entries; i++) { + mkv_seekhead_entry *entry = &seekhead->entries[i]; + + seekentry = start_ebml_master(pb, MATROSKA_ID_SEEKENTRY, MAX_SEEKENTRY_SIZE); + + put_ebml_id(pb, MATROSKA_ID_SEEKID); + put_ebml_num(pb, ebml_id_size(entry->elementid), 0); + put_ebml_id(pb, entry->elementid); + + put_ebml_uint(pb, MATROSKA_ID_SEEKPOSITION, entry->segmentpos); + end_ebml_master(pb, seekentry); + } + end_ebml_master(pb, metaseek); + + if (seekhead->reserved_size > 0) { + uint64_t remaining = seekhead->filepos + seekhead->reserved_size - url_ftell(pb); + put_ebml_void(pb, remaining); + url_fseek(pb, currentpos, SEEK_SET); + + currentpos = seekhead->filepos; + } + av_free(seekhead->entries); + av_free(seekhead); + + return currentpos; +} + +static mkv_cues * mkv_start_cues(offset_t segment_offset) +{ + mkv_cues *cues = av_mallocz(sizeof(mkv_cues)); + if (cues == NULL) + return NULL; + + cues->segment_offset = segment_offset; + return cues; +} + +static int mkv_add_cuepoint(mkv_cues *cues, AVPacket *pkt, offset_t cluster_pos) +{ + mkv_cuepoint *entries = cues->entries; + + entries = av_realloc(entries, (cues->num_entries + 1) * sizeof(mkv_cuepoint)); + if (entries == NULL) + return AVERROR(ENOMEM); + + entries[cues->num_entries ].pts = pkt->pts; + entries[cues->num_entries ].tracknum = pkt->stream_index + 1; + entries[cues->num_entries++].cluster_pos = cluster_pos - cues->segment_offset; + + cues->entries = entries; + return 0; +} + +static offset_t mkv_write_cues(ByteIOContext *pb, mkv_cues *cues, int num_tracks) +{ + ebml_master cues_element; + offset_t currentpos; + int i, j; + + currentpos = url_ftell(pb); + cues_element = start_ebml_master(pb, MATROSKA_ID_CUES, 0); + + for (i = 0; i < cues->num_entries; i++) { + ebml_master cuepoint, track_positions; + mkv_cuepoint *entry = &cues->entries[i]; + uint64_t pts = entry->pts; + + cuepoint = start_ebml_master(pb, MATROSKA_ID_POINTENTRY, MAX_CUEPOINT_SIZE(num_tracks)); + put_ebml_uint(pb, MATROSKA_ID_CUETIME, pts); + + // put all the entries from different tracks that have the exact same + // timestamp into the same CuePoint + for (j = 0; j < cues->num_entries - i && entry[j].pts == pts; j++) { + track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE); + put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum ); + put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION, entry[j].cluster_pos); + end_ebml_master(pb, track_positions); + } + i += j - 1; + end_ebml_master(pb, cuepoint); + } + end_ebml_master(pb, cues_element); + + av_free(cues->entries); + av_free(cues); + return currentpos; +} + +static int put_xiph_codecpriv(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec) +{ + uint8_t *header_start[3]; + int header_len[3]; + int first_header_size; + int j; + + if (codec->codec_id == CODEC_ID_VORBIS) + first_header_size = 30; + else + first_header_size = 42; + + if (ff_split_xiph_headers(codec->extradata, codec->extradata_size, + first_header_size, header_start, header_len) < 0) { + av_log(s, AV_LOG_ERROR, "Extradata corrupt.\n"); + return -1; + } + + put_byte(pb, 2); // number packets - 1 + for (j = 0; j < 2; j++) { + put_xiph_size(pb, header_len[j]); + } + for (j = 0; j < 3; j++) + put_buffer(pb, header_start[j], header_len[j]); + + return 0; +} + +#define FLAC_STREAMINFO_SIZE 34 + +static int put_flac_codecpriv(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec) +{ + // if the extradata_size is greater than FLAC_STREAMINFO_SIZE, + // assume that it's in Matroska's format already + if (codec->extradata_size < FLAC_STREAMINFO_SIZE) { + av_log(s, AV_LOG_ERROR, "Invalid FLAC extradata\n"); + return -1; + } else if (codec->extradata_size == FLAC_STREAMINFO_SIZE) { + // only the streaminfo packet + put_byte(pb, 0); + put_xiph_size(pb, codec->extradata_size); + av_log(s, AV_LOG_ERROR, "Only one packet\n"); + } + put_buffer(pb, codec->extradata, codec->extradata_size); + return 0; +} + +static void get_aac_sample_rates(AVFormatContext *s, AVCodecContext *codec, int *sample_rate, int *output_sample_rate) +{ + static const int aac_sample_rates[] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, + }; + int sri; + + if (codec->extradata_size < 2) { + av_log(s, AV_LOG_WARNING, "No AAC extradata, unable to determine samplerate.\n"); + return; + } + + sri = ((codec->extradata[0] << 1) & 0xE) | (codec->extradata[1] >> 7); + if (sri > 12) { + av_log(s, AV_LOG_WARNING, "AAC samplerate index out of bounds\n"); + return; + } + *sample_rate = aac_sample_rates[sri]; + + // if sbr, get output sample rate as well + if (codec->extradata_size == 5) { + sri = (codec->extradata[4] >> 3) & 0xF; + if (sri > 12) { + av_log(s, AV_LOG_WARNING, "AAC output samplerate index out of bounds\n"); + return; + } + *output_sample_rate = aac_sample_rates[sri]; + } +} + +static int mkv_write_codecprivate(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec, int native_id) +{ + ByteIOContext *dyn_cp; + uint8_t *codecpriv; + int ret, codecpriv_size; + + ret = url_open_dyn_buf(&dyn_cp); + if(ret < 0) + return ret; + + if (native_id) { + if (codec->codec_id == CODEC_ID_VORBIS || codec->codec_id == CODEC_ID_THEORA) + ret = put_xiph_codecpriv(s, dyn_cp, codec); + else if (codec->codec_id == CODEC_ID_FLAC) + ret = put_flac_codecpriv(s, dyn_cp, codec); + else if (codec->codec_id == CODEC_ID_H264) + ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); + else if (codec->extradata_size) + put_buffer(dyn_cp, codec->extradata, codec->extradata_size); + } else if (codec->codec_type == CODEC_TYPE_VIDEO) { + if (!codec->codec_tag) + codec->codec_tag = codec_get_tag(codec_bmp_tags, codec->codec_id); + if (!codec->codec_tag) { + av_log(s, AV_LOG_ERROR, "No bmp codec ID found."); + ret = -1; + } + + put_bmp_header(dyn_cp, codec, codec_bmp_tags, 0); + + } else if (codec->codec_type == CODEC_TYPE_AUDIO) { + if (!codec->codec_tag) + codec->codec_tag = codec_get_tag(codec_wav_tags, codec->codec_id); + if (!codec->codec_tag) { + av_log(s, AV_LOG_ERROR, "No wav codec ID found."); + ret = -1; + } + + put_wav_header(dyn_cp, codec); + } + + codecpriv_size = url_close_dyn_buf(dyn_cp, &codecpriv); + if (codecpriv_size) + put_ebml_binary(pb, MATROSKA_ID_CODECPRIVATE, codecpriv, codecpriv_size); + av_free(codecpriv); + return ret; +} + +static int mkv_write_tracks(AVFormatContext *s) +{ + MatroskaMuxContext *mkv = s->priv_data; + ByteIOContext *pb = s->pb; + ebml_master tracks; + int i, j, ret; + + ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, url_ftell(pb)); + if (ret < 0) return ret; + + tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS, 0); + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVCodecContext *codec = st->codec; + ebml_master subinfo, track; + int native_id = 0; + int bit_depth = av_get_bits_per_sample(codec->codec_id); + int sample_rate = codec->sample_rate; + int output_sample_rate = 0; + + if (!bit_depth) + bit_depth = av_get_bits_per_sample_format(codec->sample_fmt); + + if (codec->codec_id == CODEC_ID_AAC) + get_aac_sample_rates(s, codec, &sample_rate, &output_sample_rate); + + track = start_ebml_master(pb, MATROSKA_ID_TRACKENTRY, 0); + put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER , i + 1); + put_ebml_uint (pb, MATROSKA_ID_TRACKUID , i + 1); + put_ebml_uint (pb, MATROSKA_ID_TRACKFLAGLACING , 0); // no lacing (yet) + + if (st->language[0]) + put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, st->language); + else + put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, "und"); + + // look for a codec ID string specific to mkv to use, + // if none are found, use AVI codes + for (j = 0; ff_mkv_codec_tags[j].id != CODEC_ID_NONE; j++) { + if (ff_mkv_codec_tags[j].id == codec->codec_id) { + put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str); + native_id = 1; + break; + } + } + + switch (codec->codec_type) { + case CODEC_TYPE_VIDEO: + put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_VIDEO); + + if (!native_id) + // if there is no mkv-specific codec ID, use VFW mode + put_ebml_string(pb, MATROSKA_ID_CODECID, MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC); + + subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKVIDEO, 0); + // XXX: interlace flag? + put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width); + put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELHEIGHT, codec->height); + if (codec->sample_aspect_ratio.num) { + AVRational dar = av_mul_q(codec->sample_aspect_ratio, + (AVRational){codec->width, codec->height}); + put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , dar.num); + put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, dar.den); + } + end_ebml_master(pb, subinfo); + break; + + case CODEC_TYPE_AUDIO: + put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_AUDIO); + + if (!native_id) + // no mkv-specific ID, use ACM mode + put_ebml_string(pb, MATROSKA_ID_CODECID, MATROSKA_CODEC_ID_AUDIO_ACM); + + subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKAUDIO, 0); + put_ebml_uint (pb, MATROSKA_ID_AUDIOCHANNELS , codec->channels); + put_ebml_float (pb, MATROSKA_ID_AUDIOSAMPLINGFREQ, sample_rate); + if (output_sample_rate) + put_ebml_float(pb, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate); + if (bit_depth) + put_ebml_uint(pb, MATROSKA_ID_AUDIOBITDEPTH, bit_depth); + end_ebml_master(pb, subinfo); + break; + + case CODEC_TYPE_SUBTITLE: + put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_SUBTITLE); + break; + default: + av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska."); + break; + } + ret = mkv_write_codecprivate(s, pb, codec, native_id); + if (ret < 0) return ret; + + end_ebml_master(pb, track); + + // ms precision is the de-facto standard timescale for mkv files + av_set_pts_info(st, 64, 1, 1000); + } + end_ebml_master(pb, tracks); + return 0; +} + +static int mkv_write_header(AVFormatContext *s) +{ + MatroskaMuxContext *mkv = s->priv_data; + ByteIOContext *pb = s->pb; + ebml_master ebml_header, segment_info; + int ret; + + mkv->md5_ctx = av_mallocz(av_md5_size); + av_md5_init(mkv->md5_ctx); + + ebml_header = start_ebml_master(pb, EBML_ID_HEADER, 0); + put_ebml_uint (pb, EBML_ID_EBMLVERSION , 1); + put_ebml_uint (pb, EBML_ID_EBMLREADVERSION , 1); + put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4); + put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8); + put_ebml_string (pb, EBML_ID_DOCTYPE , "matroska"); + put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2); + put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2); + end_ebml_master(pb, ebml_header); + + mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT, 0); + mkv->segment_offset = url_ftell(pb); + + // we write 2 seek heads - one at the end of the file to point to each + // cluster, and one at the beginning to point to all other level one + // elements (including the seek head at the end of the file), which + // isn't more than 10 elements if we only write one of each other + // currently defined level 1 element + mkv->main_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10); + mkv->cluster_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 0); + if (mkv->main_seekhead == NULL || mkv->cluster_seekhead == NULL) + return AVERROR(ENOMEM); + + ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_INFO, url_ftell(pb)); + if (ret < 0) return ret; + + segment_info = start_ebml_master(pb, MATROSKA_ID_INFO, 0); + put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000); + if (strlen(s->title)) + put_ebml_string(pb, MATROSKA_ID_TITLE, s->title); + if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { + put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , LIBAVFORMAT_IDENT); + put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT); + + // reserve space to write the segment UID later + mkv->segment_uid = url_ftell(pb); + put_ebml_void(pb, 19); + } + + // reserve space for the duration + mkv->duration = 0; + mkv->duration_offset = url_ftell(pb); + put_ebml_void(pb, 11); // assumes double-precision float to be written + end_ebml_master(pb, segment_info); + + ret = mkv_write_tracks(s); + if (ret < 0) return ret; + + ret = mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb)); + if (ret < 0) return ret; + + mkv->cluster_pos = url_ftell(pb); + mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER, 0); + put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, 0); + mkv->cluster_pts = 0; + + mkv->cues = mkv_start_cues(mkv->segment_offset); + if (mkv->cues == NULL) + return AVERROR(ENOMEM); + + return 0; +} + +static int mkv_block_size(AVPacket *pkt) +{ + int size = 4; // track num + timecode + flags + return size + pkt->size; +} + +static int mkv_blockgroup_size(AVPacket *pkt) +{ + int size = mkv_block_size(pkt); + size += ebml_num_size(size); + size += 2; // EBML ID for block and block duration + size += 8; // max size of block duration + size += ebml_num_size(size); + size += 1; // blockgroup EBML ID + return size; +} + +static void mkv_write_block(AVFormatContext *s, unsigned int blockid, AVPacket *pkt, int flags) +{ + MatroskaMuxContext *mkv = s->priv_data; + ByteIOContext *pb = s->pb; + + av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " + "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n", + url_ftell(pb), pkt->size, pkt->pts, pkt->dts, pkt->duration, flags); + put_ebml_id(pb, blockid); + put_ebml_num(pb, mkv_block_size(pkt), 0); + put_byte(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126 + put_be16(pb, pkt->pts - mkv->cluster_pts); + put_byte(pb, flags); + put_buffer(pb, pkt->data, pkt->size); +} + +static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + MatroskaMuxContext *mkv = s->priv_data; + ByteIOContext *pb = s->pb; + AVCodecContext *codec = s->streams[pkt->stream_index]->codec; + int keyframe = !!(pkt->flags & PKT_FLAG_KEY); + int ret; + + // start a new cluster every 5 MB or 5 sec + if (url_ftell(pb) > mkv->cluster_pos + 5*1024*1024 || pkt->pts > mkv->cluster_pts + 5000) { + av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64 + " bytes, pts %" PRIu64 "\n", url_ftell(pb), pkt->pts); + end_ebml_master(pb, mkv->cluster); + + ret = mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb)); + if (ret < 0) return ret; + + mkv->cluster_pos = url_ftell(pb); + mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER, 0); + put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, pkt->pts); + mkv->cluster_pts = pkt->pts; + av_md5_update(mkv->md5_ctx, pkt->data, FFMIN(200, pkt->size)); + } + + if (codec->codec_id == CODEC_ID_H264 && + codec->extradata_size > 0 && AV_RB32(codec->extradata) == 0x00000001) { + /* from x264 or from bytestream h264 */ + /* nal reformating needed */ + int ret = ff_avc_parse_nal_units(pkt->data, &pkt->data, &pkt->size); + if (ret < 0) + return ret; + assert(pkt->size); + } + + if (codec->codec_type != CODEC_TYPE_SUBTITLE) { + mkv_write_block(s, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7); + } else { + ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(pkt)); + mkv_write_block(s, MATROSKA_ID_BLOCK, pkt, 0); + put_ebml_uint(pb, MATROSKA_ID_DURATION, pkt->duration); + end_ebml_master(pb, blockgroup); + } + + if (codec->codec_type == CODEC_TYPE_VIDEO && keyframe) { + ret = mkv_add_cuepoint(mkv->cues, pkt, mkv->cluster_pos); + if (ret < 0) return ret; + } + + mkv->duration = FFMAX(mkv->duration, pkt->pts + pkt->duration); + return 0; +} + +static int mkv_write_trailer(AVFormatContext *s) +{ + MatroskaMuxContext *mkv = s->priv_data; + ByteIOContext *pb = s->pb; + offset_t currentpos, second_seekhead, cuespos; + int ret; + + end_ebml_master(pb, mkv->cluster); + + if (!url_is_streamed(pb)) { + cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams); + second_seekhead = mkv_write_seekhead(pb, mkv->cluster_seekhead); + + ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES , cuespos); + if (ret < 0) return ret; + ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_SEEKHEAD, second_seekhead); + if (ret < 0) return ret; + mkv_write_seekhead(pb, mkv->main_seekhead); + + // update the duration + av_log(s, AV_LOG_DEBUG, "end duration = %" PRIu64 "\n", mkv->duration); + currentpos = url_ftell(pb); + url_fseek(pb, mkv->duration_offset, SEEK_SET); + put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration); + + // write the md5sum of some frames as the segment UID + if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) { + uint8_t segment_uid[16]; + av_md5_final(mkv->md5_ctx, segment_uid); + url_fseek(pb, mkv->segment_uid, SEEK_SET); + put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16); + } + url_fseek(pb, currentpos, SEEK_SET); + } + + end_ebml_master(pb, mkv->segment); + av_free(mkv->md5_ctx); + return 0; +} + +AVOutputFormat matroska_muxer = { + "matroska", + "Matroska File Format", + "video/x-matroska", + "mkv", + sizeof(MatroskaMuxContext), + CODEC_ID_MP2, + CODEC_ID_MPEG4, + mkv_write_header, + mkv_write_packet, + mkv_write_trailer, + .codec_tag = (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, + .subtitle_codec = CODEC_ID_TEXT, +}; + +AVOutputFormat matroska_audio_muxer = { + "matroska", + "Matroska File Format", + "audio/x-matroska", + "mka", + sizeof(MatroskaMuxContext), + CODEC_ID_MP2, + CODEC_ID_NONE, + mkv_write_header, + mkv_write_packet, + mkv_write_trailer, + .codec_tag = (const AVCodecTag*[]){codec_wav_tags, 0}, +}; diff --git a/contrib/ffmpeg/libavformat/mm.c b/contrib/ffmpeg/libavformat/mm.c index 443b70929..4e6bac027 100644 --- a/contrib/ffmpeg/libavformat/mm.c +++ b/contrib/ffmpeg/libavformat/mm.c @@ -16,7 +16,7 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** @@ -59,8 +59,6 @@ typedef struct { static int mm_probe(AVProbeData *p) { /* the first chunk is always the header */ - if (p->buf_size < MM_PREAMBLE_SIZE) - return 0; if (AV_RL16(&p->buf[0]) != MM_TYPE_HEADER) return 0; if (AV_RL32(&p->buf[2]) != MM_HEADER_LEN_V && AV_RL32(&p->buf[2]) != MM_HEADER_LEN_AV) @@ -73,8 +71,8 @@ static int mm_probe(AVProbeData *p) static int mm_read_header(AVFormatContext *s, AVFormatParameters *ap) { - MmDemuxContext *mm = (MmDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + MmDemuxContext *mm = s->priv_data; + ByteIOContext *pb = s->pb; AVStream *st; unsigned int type, length; @@ -97,7 +95,7 @@ static int mm_read_header(AVFormatContext *s, /* video stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_MMVIDEO; st->codec->codec_tag = 0; /* no fourcc */ @@ -110,7 +108,7 @@ static int mm_read_header(AVFormatContext *s, if (length == MM_HEADER_LEN_AV) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_tag = 0; /* no fourcc */ st->codec->codec_id = CODEC_ID_PCM_U8; @@ -128,8 +126,8 @@ static int mm_read_header(AVFormatContext *s, static int mm_read_packet(AVFormatContext *s, AVPacket *pkt) { - MmDemuxContext *mm = (MmDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + MmDemuxContext *mm = s->priv_data; + ByteIOContext *pb = s->pb; unsigned char preamble[MM_PREAMBLE_SIZE]; unsigned char pal[MM_PALETTE_SIZE]; unsigned int type, length; @@ -138,7 +136,7 @@ static int mm_read_packet(AVFormatContext *s, while(1) { if (get_buffer(pb, preamble, MM_PREAMBLE_SIZE) != MM_PREAMBLE_SIZE) { - return AVERROR_IO; + return AVERROR(EIO); } type = AV_RL16(&preamble[0]); @@ -148,7 +146,7 @@ static int mm_read_packet(AVFormatContext *s, case MM_TYPE_PALETTE : url_fseek(pb, 4, SEEK_CUR); /* unknown data */ if (get_buffer(pb, pal, MM_PALETTE_SIZE) != MM_PALETTE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); url_fseek(pb, length - (4 + MM_PALETTE_SIZE), SEEK_CUR); for (i=0; i<MM_PALETTE_COUNT; i++) { @@ -170,18 +168,18 @@ static int mm_read_packet(AVFormatContext *s, case MM_TYPE_INTER_HHV : /* output preamble + data */ if (av_new_packet(pkt, length + MM_PREAMBLE_SIZE)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); memcpy(pkt->data, preamble, MM_PREAMBLE_SIZE); if (get_buffer(pb, pkt->data + MM_PREAMBLE_SIZE, length) != length) - return AVERROR_IO; + return AVERROR(EIO); pkt->size = length + MM_PREAMBLE_SIZE; pkt->stream_index = 0; pkt->pts = mm->video_pts++; return 0; case MM_TYPE_AUDIO : - if (av_get_packet(&s->pb, pkt, length)<0) - return AVERROR_NOMEM; + if (av_get_packet(s->pb, pkt, length)<0) + return AVERROR(ENOMEM); pkt->size = length; pkt->stream_index = 1; pkt->pts = mm->audio_pts++; diff --git a/contrib/ffmpeg/libavformat/mmf.c b/contrib/ffmpeg/libavformat/mmf.c index 40b1a497c..84c21a01d 100644 --- a/contrib/ffmpeg/libavformat/mmf.c +++ b/contrib/ffmpeg/libavformat/mmf.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "allformats.h" +#include "raw.h" #include "riff.h" typedef struct { @@ -60,7 +60,7 @@ static void end_tag_be(ByteIOContext *pb, offset_t start) static int mmf_write_header(AVFormatContext *s) { MMFContext *mmf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; offset_t pos; int rate; @@ -108,7 +108,7 @@ static int mmf_write_header(AVFormatContext *s) static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; put_buffer(pb, pkt->data, pkt->size); return 0; } @@ -127,12 +127,12 @@ static void put_varlength(ByteIOContext *pb, int val) static int mmf_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; MMFContext *mmf = s->priv_data; offset_t pos, size; int gatetime; - if (!url_is_streamed(&s->pb)) { + if (!url_is_streamed(s->pb)) { /* Fill in length fields */ end_tag_be(pb, mmf->awapos); end_tag_be(pb, mmf->atrpos); @@ -168,8 +168,6 @@ static int mmf_write_trailer(AVFormatContext *s) static int mmf_probe(AVProbeData *p) { /* check file header */ - if (p->buf_size <= 32) - return 0; if (p->buf[0] == 'M' && p->buf[1] == 'M' && p->buf[2] == 'M' && p->buf[3] == 'D' && p->buf[8] == 'C' && p->buf[9] == 'N' && @@ -185,7 +183,7 @@ static int mmf_read_header(AVFormatContext *s, { MMFContext *mmf = s->priv_data; unsigned int tag; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; offset_t file_size, size; int rate, params; @@ -244,7 +242,7 @@ static int mmf_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_ADPCM_YAMAHA; @@ -267,8 +265,8 @@ static int mmf_read_packet(AVFormatContext *s, AVStream *st; int ret, size; - if (url_feof(&s->pb)) - return AVERROR_IO; + if (url_feof(s->pb)) + return AVERROR(EIO); st = s->streams[0]; size = MAX_SIZE; @@ -276,13 +274,13 @@ static int mmf_read_packet(AVFormatContext *s, size = mmf->data_size; if(!size) - return AVERROR_IO; + return AVERROR(EIO); if (av_new_packet(pkt, size)) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = 0; - ret = get_buffer(&s->pb, pkt->data, pkt->size); + ret = get_buffer(s->pb, pkt->data, pkt->size); if (ret < 0) av_free_packet(pkt); diff --git a/contrib/ffmpeg/libavformat/mov.c b/contrib/ffmpeg/libavformat/mov.c index e9b577576..a67604b0e 100644 --- a/contrib/ffmpeg/libavformat/mov.c +++ b/contrib/ffmpeg/libavformat/mov.c @@ -38,16 +38,8 @@ * * Features and limitations: * - reads most of the QT files I have (at least the structure), - * the exceptions are .mov with zlib compressed headers ('cmov' section). It shouldn't be hard to implement. - * FIXED, Francois Revol, 07/17/2002 - * - ffmpeg has nearly none of the usual QuickTime codecs, - * although I succesfully dumped raw and mp3 audio tracks off .mov files. * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html - * - .mp4 parsing is still hazardous, although the format really is QuickTime with some minor changes - * (to make .mov parser crash maybe ?), despite what they say in the MPEG FAQ at - * http://mpeg.telecomitalialab.com/faq.htm * - the code is quite ugly... maybe I won't do it recursive next time :-) - * - seek is not supported with files that contain edit list * * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/ * when coding this :) (it's a writer anyway) @@ -71,11 +63,16 @@ * Here we just use what is needed to read the chunks */ -typedef struct MOV_sample_to_chunk_tbl { - long first; - long count; - long id; -} MOV_sample_to_chunk_tbl; +typedef struct { + int first; + int count; + int id; +} MOV_stsc_t; + +typedef struct { + uint32_t type; + char *path; +} MOV_dref_t; typedef struct { uint32_t type; @@ -83,94 +80,39 @@ typedef struct { int64_t size; /* total size (excluding the size and type fields) */ } MOV_atom_t; -typedef struct { - int seed; - int flags; - int size; - void* clrs; -} MOV_ctab_t; - -typedef struct MOV_mdat_atom_s { - offset_t offset; - int64_t size; -} MOV_mdat_atom_t; - -typedef struct { - uint8_t version; - uint32_t flags; // 24bit - - /* 0x03 ESDescrTag */ - uint16_t es_id; -#define MP4ODescrTag 0x01 -#define MP4IODescrTag 0x02 -#define MP4ESDescrTag 0x03 -#define MP4DecConfigDescrTag 0x04 -#define MP4DecSpecificDescrTag 0x05 -#define MP4SLConfigDescrTag 0x06 -#define MP4ContentIdDescrTag 0x07 -#define MP4SupplContentIdDescrTag 0x08 -#define MP4IPIPtrDescrTag 0x09 -#define MP4IPMPPtrDescrTag 0x0A -#define MP4IPMPDescrTag 0x0B -#define MP4RegistrationDescrTag 0x0D -#define MP4ESIDIncDescrTag 0x0E -#define MP4ESIDRefDescrTag 0x0F -#define MP4FileIODescrTag 0x10 -#define MP4FileODescrTag 0x11 -#define MP4ExtProfileLevelDescrTag 0x13 -#define MP4ExtDescrTagsStart 0x80 -#define MP4ExtDescrTagsEnd 0xFE - uint8_t stream_priority; - - /* 0x04 DecConfigDescrTag */ - uint8_t object_type_id; - uint8_t stream_type; - /* XXX: really streamType is - * only 6bit, followed by: - * 1bit upStream - * 1bit reserved - */ - uint32_t buffer_size_db; // 24 - uint32_t max_bitrate; - uint32_t avg_bitrate; - - /* 0x05 DecSpecificDescrTag */ - uint8_t decoder_cfg_len; - uint8_t *decoder_cfg; - - /* 0x06 SLConfigDescrTag */ - uint8_t sl_config_len; - uint8_t *sl_config; -} MOV_esds_t; - struct MOVParseTableEntry; typedef struct MOVStreamContext { + ByteIOContext *pb; int ffindex; /* the ffmpeg stream id */ - long next_chunk; + int next_chunk; unsigned int chunk_count; int64_t *chunk_offsets; unsigned int stts_count; - Time2Sample *stts_data; + MOV_stts_t *stts_data; unsigned int ctts_count; - Time2Sample *ctts_data; + MOV_stts_t *ctts_data; unsigned int edit_count; /* number of 'edit' (elst atom) */ unsigned int sample_to_chunk_sz; - MOV_sample_to_chunk_tbl *sample_to_chunk; + MOV_stsc_t *sample_to_chunk; int sample_to_ctime_index; int sample_to_ctime_sample; unsigned int sample_size; unsigned int sample_count; - long *sample_sizes; + int *sample_sizes; unsigned int keyframe_count; - long *keyframes; + int *keyframes; int time_scale; int time_rate; - long current_sample; - MOV_esds_t esds; + int current_sample; unsigned int bytes_per_frame; unsigned int samples_per_frame; int dv_audio_container; + int pseudo_stream_id; + int16_t audio_cid; ///< stsd audio compression id + unsigned drefs_count; + MOV_dref_t *drefs; + int dref_id; } MOVStreamContext; typedef struct MOVContext { @@ -179,18 +121,7 @@ typedef struct MOVContext { int64_t duration; /* duration of the longest track */ int found_moov; /* when both 'moov' and 'mdat' sections has been found */ int found_mdat; /* we suppose we have enough data to read the file */ - int64_t mdat_offset; - int total_streams; - MOVStreamContext *streams[MAX_STREAMS]; - - int ctab_size; - MOV_ctab_t **ctab; /* color tables */ - const struct MOVParseTableEntry *parse_table; /* could be eventually used to change the table */ - /* NOTE: for recursion save to/ restore from local variable! */ - AVPaletteControl palette_control; - MOV_mdat_atom_t *mdat_list; - int mdat_count; DVDemuxContext *dv_demux; AVFormatContext *dv_fctx; int isom; /* 1 if file is ISO Media (mp4/3gp) */ @@ -205,14 +136,14 @@ typedef struct MOVContext { 0: continue to parse next atom -1: error occured, exit */ -typedef int (*mov_parse_function)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom); - /* links atom IDs to parse functions */ typedef struct MOVParseTableEntry { uint32_t type; - mov_parse_function func; + int (*parse)(MOVContext *ctx, ByteIOContext *pb, MOV_atom_t atom); } MOVParseTableEntry; +static const MOVParseTableEntry mov_default_parse_table[]; + static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { int64_t total_size = 0; @@ -223,17 +154,18 @@ static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) a.offset = atom.offset; if (atom.size < 0) - atom.size = 0x7fffffffffffffffLL; + atom.size = INT64_MAX; while(((total_size + 8) < atom.size) && !url_feof(pb) && !err) { a.size = atom.size; - a.type=0L; + a.type=0; if(atom.size >= 8) { a.size = get_be32(pb); a.type = get_le32(pb); } total_size += 8; a.offset += 8; - dprintf(c->fc, "type: %08x %.4s sz: %"PRIx64" %"PRIx64" %"PRIx64"\n", a.type, (char*)&a.type, a.size, atom.size, total_size); + dprintf(c->fc, "type: %08x %.4s sz: %"PRIx64" %"PRIx64" %"PRIx64"\n", + a.type, (char*)&a.type, a.size, atom.size, total_size); if (a.size == 1) { /* 64 bit extended size */ a.size = get_be64(pb) - 8; a.offset += 8; @@ -245,19 +177,22 @@ static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) break; } a.size -= 8; - if(a.size < 0 || a.size > atom.size - total_size) + if(a.size < 0) break; + a.size = FFMIN(a.size, atom.size - total_size); - for (i = 0; c->parse_table[i].type != 0L - && c->parse_table[i].type != a.type; i++) + for (i = 0; mov_default_parse_table[i].type != 0 + && mov_default_parse_table[i].type != a.type; i++) /* empty */; - if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ + if (mov_default_parse_table[i].type == 0) { /* skip leaf atoms data */ url_fskip(pb, a.size); } else { offset_t start_pos = url_ftell(pb); int64_t left; - err = (c->parse_table[i].func)(c, pb, a); + err = mov_default_parse_table[i].parse(c, pb, a); + if (c->found_moov && c->found_mdat) + break; left = a.size - url_ftell(pb) + start_pos; if (left > 0) /* skip garbage at atom end */ url_fskip(pb, left); @@ -274,27 +209,71 @@ static int mov_read_default(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) return err; } -static int mov_read_ctab(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) +static int mov_read_dref(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { -#if 1 - url_fskip(pb, atom.size); // for now -#else - VERY VERY BROKEN, NEVER execute this, needs rewrite - unsigned int len; - MOV_ctab_t *t; - c->ctab = av_realloc(c->ctab, ++c->ctab_size); - t = c->ctab[c->ctab_size]; - t->seed = get_be32(pb); - t->flags = get_be16(pb); - t->size = get_be16(pb) + 1; - len = 2 * t->size * 4; - if (len > 0) { - t->clrs = av_malloc(len); // 16bit A R G B - if (t->clrs) - get_buffer(pb, t->clrs, len); - } -#endif + AVStream *st = c->fc->streams[c->fc->nb_streams-1]; + MOVStreamContext *sc = st->priv_data; + int entries, i, j; + get_be32(pb); // version + flags + entries = get_be32(pb); + if (entries >= UINT_MAX / sizeof(*sc->drefs)) + return -1; + sc->drefs_count = entries; + sc->drefs = av_mallocz(entries * sizeof(*sc->drefs)); + + for (i = 0; i < sc->drefs_count; i++) { + MOV_dref_t *dref = &sc->drefs[i]; + uint32_t size = get_be32(pb); + offset_t next = url_ftell(pb) + size - 4; + + dref->type = get_le32(pb); + get_be32(pb); // version + flags + dprintf(c->fc, "type %.4s size %d\n", (char*)&dref->type, size); + + if (dref->type == MKTAG('a','l','i','s') && size > 150) { + /* macintosh alias record */ + uint16_t volume_len, len; + char volume[28]; + int16_t type; + + url_fskip(pb, 10); + + volume_len = get_byte(pb); + volume_len = FFMIN(volume_len, 27); + get_buffer(pb, volume, 27); + volume[volume_len] = 0; + av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", volume, volume_len); + + url_fskip(pb, 112); + + for (type = 0; type != -1 && url_ftell(pb) < next; ) { + type = get_be16(pb); + len = get_be16(pb); + av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len); + if (len&1) + len += 1; + if (type == 2) { // absolute path + av_free(dref->path); + dref->path = av_mallocz(len+1); + if (!dref->path) + return AVERROR(ENOMEM); + get_buffer(pb, dref->path, len); + if (len > volume_len && !strncmp(dref->path, volume, volume_len)) { + len -= volume_len; + memmove(dref->path, dref->path+volume_len, len); + dref->path[len] = 0; + } + for (j = 0; j < len; j++) + if (dref->path[j] == ':') + dref->path[j] = '/'; + av_log(c->fc, AV_LOG_DEBUG, "path %s\n", dref->path); + } else + url_fskip(pb, len); + } + } + url_fseek(pb, next, SEEK_SET); + } return 0; } @@ -311,8 +290,10 @@ static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) ctype = get_le32(pb); type = get_le32(pb); /* component subtype */ - dprintf(c->fc, "ctype= %c%c%c%c (0x%08lx)\n", *((char *)&ctype), ((char *)&ctype)[1], ((char *)&ctype)[2], ((char *)&ctype)[3], (long) ctype); - dprintf(c->fc, "stype= %c%c%c%c\n", *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); + dprintf(c->fc, "ctype= %c%c%c%c (0x%08x)\n", *((char *)&ctype), ((char *)&ctype)[1], + ((char *)&ctype)[2], ((char *)&ctype)[3], (int) ctype); + dprintf(c->fc, "stype= %c%c%c%c\n", + *((char *)&type), ((char *)&type)[1], ((char *)&type)[2], ((char *)&type)[3]); if(!ctype) c->isom = 1; if(type == MKTAG('v', 'i', 'd', 'e')) @@ -323,7 +304,6 @@ static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec->codec_id = CODEC_ID_MP2; else if(type == MKTAG('s', 'u', 'b', 'p')) { st->codec->codec_type = CODEC_TYPE_SUBTITLE; - st->codec->codec_id = CODEC_ID_DVD_SUBTITLE; } get_be32(pb); /* component manufacture */ get_be32(pb); /* component flags */ @@ -336,7 +316,7 @@ static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) return 0; } -static int mov_mp4_read_descr_len(ByteIOContext *pb) +static int mp4_read_descr_len(ByteIOContext *pb) { int len = 0; int count = 4; @@ -349,51 +329,55 @@ static int mov_mp4_read_descr_len(ByteIOContext *pb) return len; } -static int mov_mp4_read_descr(MOVContext *c, ByteIOContext *pb, int *tag) +static int mp4_read_descr(MOVContext *c, ByteIOContext *pb, int *tag) { int len; *tag = get_byte(pb); - len = mov_mp4_read_descr_len(pb); + len = mp4_read_descr_len(pb); dprintf(c->fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); return len; } +#define MP4ESDescrTag 0x03 +#define MP4DecConfigDescrTag 0x04 +#define MP4DecSpecificDescrTag 0x05 + static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; int tag, len; - /* Well, broken but suffisant for some MP4 streams */ get_be32(pb); /* version + flags */ - len = mov_mp4_read_descr(c, pb, &tag); + len = mp4_read_descr(c, pb, &tag); if (tag == MP4ESDescrTag) { get_be16(pb); /* ID */ get_byte(pb); /* priority */ } else get_be16(pb); /* ID */ - len = mov_mp4_read_descr(c, pb, &tag); + len = mp4_read_descr(c, pb, &tag); if (tag == MP4DecConfigDescrTag) { - sc->esds.object_type_id = get_byte(pb); - sc->esds.stream_type = get_byte(pb); - sc->esds.buffer_size_db = get_be24(pb); - sc->esds.max_bitrate = get_be32(pb); - sc->esds.avg_bitrate = get_be32(pb); - - st->codec->codec_id= codec_get_id(ff_mp4_obj_type, sc->esds.object_type_id); - dprintf(c->fc, "esds object type id %d\n", sc->esds.object_type_id); - len = mov_mp4_read_descr(c, pb, &tag); + int object_type_id = get_byte(pb); + get_byte(pb); /* stream type */ + get_be24(pb); /* buffer size db */ + get_be32(pb); /* max bitrate */ + get_be32(pb); /* avg bitrate */ + + st->codec->codec_id= codec_get_id(ff_mp4_obj_type, object_type_id); + dprintf(c->fc, "esds object type id %d\n", object_type_id); + len = mp4_read_descr(c, pb, &tag); if (tag == MP4DecSpecificDescrTag) { dprintf(c->fc, "Specific MPEG4 header len=%d\n", len); + if((uint64_t)len > (1<<30)) + return -1; st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); - if (st->codec->extradata) { - get_buffer(pb, st->codec->extradata, len); - st->codec->extradata_size = len; - /* from mplayer */ - if ((*st->codec->extradata >> 3) == 29) { - st->codec->codec_id = CODEC_ID_MP3ON4; - } + if (!st->codec->extradata) + return AVERROR(ENOMEM); + get_buffer(pb, st->codec->extradata, len); + st->codec->extradata_size = len; + /* from mplayer */ + if ((*st->codec->extradata >> 3) == 29) { + st->codec->codec_id = CODEC_ID_MP3ON4; } } } @@ -405,12 +389,7 @@ static int mov_read_mdat(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { if(atom.size == 0) /* wrong one (MP4) */ return 0; - c->mdat_list = av_realloc(c->mdat_list, (c->mdat_count + 1) * sizeof(*c->mdat_list)); - c->mdat_list[c->mdat_count].offset = atom.offset; - c->mdat_list[c->mdat_count].size = atom.size; - c->mdat_count++; c->found_mdat=1; - c->mdat_offset = atom.offset; if(c->found_moov) return 1; /* found both, just go */ url_fskip(pb, atom.size); @@ -432,9 +411,8 @@ static int mov_read_ftyp(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) /* this atom should contain all header atoms */ static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { - int err; - - err = mov_read_default(c, pb, atom); + if (mov_read_default(c, pb, atom) < 0) + return -1; /* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */ /* so we don't parse the whole file if over a network */ c->found_moov=1; @@ -447,7 +425,7 @@ static int mov_read_moov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) static int mov_read_mdhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; int version = get_byte(pb); int lang; @@ -488,9 +466,9 @@ static int mov_read_mvhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_be32(pb); /* modification time */ } c->time_scale = get_be32(pb); /* time scale */ -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "time scale = %i\n", c->time_scale); -#endif + + dprintf(c->fc, "time scale = %i\n", c->time_scale); + c->duration = (version == 1) ? get_be64(pb) : get_be32(pb); /* duration */ get_be32(pb); /* preferred scale */ @@ -521,16 +499,13 @@ static int mov_read_smi(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) // currently SVQ3 decoder expect full STSD header - so let's fake it // this should be fixed and just SMI header should be passed av_free(st->codec->extradata); + st->codec->extradata = av_mallocz(atom.size + 0x5a + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); st->codec->extradata_size = 0x5a + atom.size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - memcpy(st->codec->extradata, "SVQ3", 4); // fake - get_buffer(pb, st->codec->extradata + 0x5a, atom.size); - dprintf(c->fc, "Reading SMI %"PRId64" %s\n", atom.size, st->codec->extradata + 0x5a); - } else - url_fskip(pb, atom.size); - + memcpy(st->codec->extradata, "SVQ3", 4); // fake + get_buffer(pb, st->codec->extradata + 0x5a, atom.size); + dprintf(c->fc, "Reading SMI %"PRId64" %s\n", atom.size, st->codec->extradata + 0x5a); return 0; } @@ -558,16 +533,19 @@ static int mov_read_enda(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) static int mov_read_extradata(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - if((uint64_t)atom.size > (1<<30)) + uint64_t size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE; + uint8_t *buf; + if(size > INT_MAX || (uint64_t)atom.size > INT_MAX) return -1; - av_free(st->codec->extradata); - st->codec->extradata_size = atom.size + 8; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - if (st->codec->extradata) { - AV_WL32(st->codec->extradata + 4, atom.type); - get_buffer(pb, st->codec->extradata + 8, atom.size); - } else - url_fskip(pb, atom.size); + buf= av_realloc(st->codec->extradata, size); + if(!buf) + return -1; + st->codec->extradata= buf; + buf+= st->codec->extradata_size; + st->codec->extradata_size= size - FF_INPUT_BUFFER_PADDING_SIZE; + AV_WB32( buf , atom.size + 8); + AV_WL32( buf + 4, atom.type); + get_buffer(pb, buf + 8, atom.size); return 0; } @@ -581,21 +559,24 @@ static int mov_read_wave(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) if (st->codec->codec_id == CODEC_ID_QDM2) { // pass all frma atom to codec, needed at least for QDM2 av_free(st->codec->extradata); + st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); st->codec->extradata_size = atom.size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - get_buffer(pb, st->codec->extradata, atom.size); - } else - url_fskip(pb, atom.size); + get_buffer(pb, st->codec->extradata, atom.size); } else if (atom.size > 8) { /* to read frma, esds atoms */ - mov_read_default(c, pb, atom); + if (mov_read_default(c, pb, atom) < 0) + return -1; } else url_fskip(pb, atom.size); return 0; } -static int mov_read_avcC(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) +/** + * This function reads atom content and puts data in extradata without tag + * nor size unlike mov_read_extradata. + */ +static int mov_read_glbl(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; @@ -603,22 +584,18 @@ static int mov_read_avcC(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) return -1; av_free(st->codec->extradata); - + st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); st->codec->extradata_size = atom.size; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - - if (st->codec->extradata) { - get_buffer(pb, st->codec->extradata, atom.size); - } else - url_fskip(pb, atom.size); - + get_buffer(pb, st->codec->extradata, atom.size); return 0; } static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; unsigned int i, entries; get_byte(pb); /* version */ @@ -650,21 +627,21 @@ static int mov_read_stco(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; int entries, frames_per_sample; uint32_t format; uint8_t codec_name[32]; /* for palette traversal */ - int color_depth; - int color_start; - int color_count; - int color_end; + unsigned int color_depth; + unsigned int color_start; + unsigned int color_count; + unsigned int color_end; int color_index; int color_dec; int color_greyscale; - unsigned char *color_table; - int j; + const uint8_t *color_table; + int j, pseudo_stream_id; unsigned char r, g, b; get_byte(pb); /* version */ @@ -672,8 +649,9 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) entries = get_be32(pb); - while(entries--) { //Parsing Sample description table + for(pseudo_stream_id=0; pseudo_stream_id<entries; pseudo_stream_id++) { //Parsing Sample description table enum CodecID id; + int dref_id; MOV_atom_t a = { 0, 0, 0 }; offset_t start_pos = url_ftell(pb); int size = get_be32(pb); /* size */ @@ -681,16 +659,26 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_be32(pb); /* reserved */ get_be16(pb); /* reserved */ - get_be16(pb); /* index */ - - if (st->codec->codec_tag) { - /* multiple fourcc, just skip for now */ + dref_id = get_be16(pb); + + if (st->codec->codec_tag && + (c->fc->video_codec_id ? codec_get_id(codec_movvideo_tags, format) != c->fc->video_codec_id + : st->codec->codec_tag != MKTAG('j', 'p', 'e', 'g')) + ){ + /* multiple fourcc, we skip jpeg, this isnt correct, we should export it as + seperate AVStream but this needs a few changes in the mov demuxer, patch + welcome */ url_fskip(pb, size - (url_ftell(pb) - start_pos)); continue; } + sc->pseudo_stream_id= pseudo_stream_id; + sc->dref_id= dref_id; st->codec->codec_tag = format; id = codec_get_id(codec_movaudio_tags, format); + if (id<=0 && (format&0xFFFF) == 'm' + ('s'<<8)) + id = codec_get_id(codec_wav_tags, bswap_32(format)&0xFFFF); + if (st->codec->codec_type != CODEC_TYPE_VIDEO && id > 0) { st->codec->codec_type = CODEC_TYPE_AUDIO; } else if (st->codec->codec_type != CODEC_TYPE_AUDIO && /* do not overwrite codec type */ @@ -700,12 +688,16 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) id = codec_get_id(codec_bmp_tags, format); if (id > 0) st->codec->codec_type = CODEC_TYPE_VIDEO; + else if(st->codec->codec_type == CODEC_TYPE_DATA){ + id = codec_get_id(ff_codec_movsubtitle_tags, format); + if(id > 0) + st->codec->codec_type = CODEC_TYPE_SUBTITLE; + } } - dprintf(c->fc, "size=%d 4CC= %c%c%c%c codec_type=%d\n", - size, - (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, (format >> 24) & 0xff, - st->codec->codec_type); + dprintf(c->fc, "size=%d 4CC= %c%c%c%c codec_type=%d\n", size, + (format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff, + (format >> 24) & 0xff, st->codec->codec_type); if(st->codec->codec_type==CODEC_TYPE_VIDEO) { st->codec->codec_id = id; @@ -713,7 +705,7 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_be16(pb); /* revision level */ get_be32(pb); /* vendor */ get_be32(pb); /* temporal quality */ - get_be32(pb); /* spacial quality */ + get_be32(pb); /* spatial quality */ st->codec->width = get_be16(pb); /* width */ st->codec->height = get_be16(pb); /* height */ @@ -722,9 +714,9 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_be32(pb); /* vert resolution */ get_be32(pb); /* data size, always 0 */ frames_per_sample = get_be16(pb); /* frames per samples */ -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "frames/samples = %d\n", frames_per_sample); -#endif + + dprintf(c->fc, "frames/samples = %d\n", frames_per_sample); + get_buffer(pb, codec_name, 32); /* codec name, pascal string (FIXME: true for mp4?) */ if (codec_name[0] <= 31) { memcpy(st->codec->codec_name, &codec_name[1],codec_name[0]); @@ -733,7 +725,8 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec->bits_per_sample = get_be16(pb); /* depth */ st->codec->color_table_id = get_be16(pb); /* colortable id */ - + dprintf(c->fc, "depth %d, ctab id %d\n", + st->codec->bits_per_sample, st->codec->color_table_id); /* figure out the palette situation */ color_depth = st->codec->bits_per_sample & 0x1F; color_greyscale = st->codec->bits_per_sample & 0x20; @@ -741,10 +734,9 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) /* if the depth is 2, 4, or 8 bpp, file is palettized */ if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) { - if (color_greyscale) { - /* compute the greyscale palette */ + st->codec->bits_per_sample = color_depth; color_count = 1 << color_depth; color_index = 255; color_dec = 256 / (color_count - 1); @@ -756,9 +748,7 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) if (color_index < 0) color_index = 0; } - } else if (st->codec->color_table_id & 0x08) { - /* if flag bit 3 is set, use the default palette */ color_count = 1 << color_depth; if (color_depth == 2) @@ -775,30 +765,30 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) c->palette_control.palette[j] = (r << 16) | (g << 8) | (b); } - } else { - /* load the palette from the file */ color_start = get_be32(pb); color_count = get_be16(pb); color_end = get_be16(pb); - 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 */ - get_byte(pb); - get_byte(pb); - r = get_byte(pb); - get_byte(pb); - g = get_byte(pb); - get_byte(pb); - b = get_byte(pb); - get_byte(pb); - c->palette_control.palette[j] = - (r << 16) | (g << 8) | (b); + 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 */ + get_byte(pb); + get_byte(pb); + r = get_byte(pb); + get_byte(pb); + g = get_byte(pb); + get_byte(pb); + b = get_byte(pb); + get_byte(pb); + c->palette_control.palette[j] = + (r << 16) | (g << 8) | (b); + } } } - st->codec->palctrl = &c->palette_control; st->codec->palctrl->palette_changed = 1; } else @@ -814,10 +804,8 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec->channels = get_be16(pb); /* channel count */ dprintf(c->fc, "audio channels %d\n", st->codec->channels); st->codec->bits_per_sample = get_be16(pb); /* sample size */ - /* do we need to force to 16 for AMR ? */ - /* handle specific s8 codec */ - get_be16(pb); /* compression id = 0*/ + sc->audio_cid = get_be16(pb); get_be16(pb); /* packet size = 0 */ st->codec->sample_rate = ((get_be32(pb) >> 16)); @@ -835,11 +823,24 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) else if (st->codec->bits_per_sample == 24) st->codec->codec_id = CODEC_ID_PCM_S24BE; break; + /* set values for old format before stsd version 1 appeared */ + case CODEC_ID_MACE3: + sc->samples_per_frame = 6; + sc->bytes_per_frame = 2*st->codec->channels; + break; + case CODEC_ID_MACE6: + sc->samples_per_frame = 6; + sc->bytes_per_frame = 1*st->codec->channels; + break; + case CODEC_ID_ADPCM_IMA_QT: + sc->samples_per_frame = 64; + sc->bytes_per_frame = 34*st->codec->channels; + break; default: break; } - //Read QT version 1 fields. In version 0 theese dont exist + //Read QT version 1 fields. In version 0 these do not exist. dprintf(c->fc, "version =%d, isom =%d\n",version,c->isom); if(!c->isom) { if(version==1) { @@ -864,45 +865,26 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->codec->bits_per_sample = bits_per_sample; sc->sample_size = (bits_per_sample >> 3) * st->codec->channels; } + } else if(st->codec->codec_type==CODEC_TYPE_SUBTITLE){ + st->codec->codec_id= id; } else { /* other codec type, just skip (rtp, mp4s, tmcd ...) */ url_fskip(pb, size - (url_ftell(pb) - start_pos)); } /* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */ a.size = size - (url_ftell(pb) - start_pos); - if (a.size > 8) - mov_read_default(c, pb, a); - else if (a.size > 0) + if (a.size > 8) { + if (mov_read_default(c, pb, a) < 0) + return -1; + } else if (a.size > 0) url_fskip(pb, a.size); } - if(st->codec->codec_type==CODEC_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) { + if(st->codec->codec_type==CODEC_TYPE_AUDIO && st->codec->sample_rate==0 && sc->time_scale>1) st->codec->sample_rate= sc->time_scale; - } /* special codec parameters handling */ switch (st->codec->codec_id) { -#ifdef CONFIG_H261_DECODER - case CODEC_ID_H261: -#endif -#ifdef CONFIG_H263_DECODER - case CODEC_ID_H263: -#endif -#ifdef CONFIG_MPEG4_DECODER - case CODEC_ID_MPEG4: -#endif - st->codec->width= 0; /* let decoder init width/height */ - st->codec->height= 0; - break; -#ifdef CONFIG_LIBFAAD - case CODEC_ID_AAC: -#endif -#ifdef CONFIG_VORBIS_DECODER - case CODEC_ID_VORBIS: -#endif - case CODEC_ID_MP3ON4: - st->codec->sample_rate= 0; /* let decoder init parameters properly */ - break; #ifdef CONFIG_DV_DEMUXER case CODEC_ID_DVAUDIO: c->dv_fctx = av_alloc_format_context(); @@ -927,7 +909,11 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) case CODEC_ID_MP2: case CODEC_ID_MP3: st->codec->codec_type = CODEC_TYPE_AUDIO; /* force type after stsd for m1a hdlr */ - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; + break; + case CODEC_ID_ADPCM_MS: + case CODEC_ID_ADPCM_IMA_WAV: + st->codec->block_align = sc->bytes_per_frame; break; default: break; @@ -939,7 +925,7 @@ static int mov_read_stsd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; unsigned int i, entries; get_byte(pb); /* version */ @@ -947,14 +933,13 @@ static int mov_read_stsc(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(MOV_sample_to_chunk_tbl)) + if(entries >= UINT_MAX / sizeof(MOV_stsc_t)) return -1; -#ifdef DEBUG -av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); -#endif + dprintf(c->fc, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); + sc->sample_to_chunk_sz = entries; - sc->sample_to_chunk = av_malloc(entries * sizeof(MOV_sample_to_chunk_tbl)); + sc->sample_to_chunk = av_malloc(entries * sizeof(MOV_stsc_t)); if (!sc->sample_to_chunk) return -1; for(i=0; i<entries; i++) { @@ -968,7 +953,7 @@ av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; unsigned int i, entries; get_byte(pb); /* version */ @@ -976,21 +961,19 @@ static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(long)) + if(entries >= UINT_MAX / sizeof(int)) return -1; sc->keyframe_count = entries; -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "keyframe_count = %d\n", sc->keyframe_count); -#endif - sc->keyframes = av_malloc(entries * sizeof(long)); + + dprintf(c->fc, "keyframe_count = %d\n", sc->keyframe_count); + + sc->keyframes = av_malloc(entries * sizeof(int)); if (!sc->keyframes) return -1; for(i=0; i<entries; i++) { sc->keyframes[i] = get_be32(pb); -#ifdef DEBUG -/* av_log(NULL, AV_LOG_DEBUG, "keyframes[]=%ld\n", sc->keyframes[i]); */ -#endif + //dprintf(c->fc, "keyframes[]=%d\n", sc->keyframes[i]); } return 0; } @@ -998,7 +981,7 @@ static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; unsigned int i, entries, sample_size; get_byte(pb); /* version */ @@ -1008,24 +991,21 @@ static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) if (!sc->sample_size) /* do not overwrite value computed in stsd */ sc->sample_size = sample_size; entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(long)) + if(entries >= UINT_MAX / sizeof(int)) return -1; sc->sample_count = entries; if (sample_size) return 0; -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "sample_size = %d sample_count = %d\n", sc->sample_size, sc->sample_count); -#endif - sc->sample_sizes = av_malloc(entries * sizeof(long)); + dprintf(c->fc, "sample_size = %d sample_count = %d\n", sc->sample_size, sc->sample_count); + + sc->sample_sizes = av_malloc(entries * sizeof(int)); if (!sc->sample_sizes) return -1; for(i=0; i<entries; i++) { sc->sample_sizes[i] = get_be32(pb); -#ifdef DEBUG - av_log(NULL, AV_LOG_DEBUG, "sample_sizes[]=%ld\n", sc->sample_sizes[i]); -#endif + dprintf(c->fc, "sample_sizes[]=%d\n", sc->sample_sizes[i]); } return 0; } @@ -1033,7 +1013,7 @@ static int mov_read_stsz(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; unsigned int i, entries; int64_t duration=0; int64_t total_sample_count=0; @@ -1041,15 +1021,14 @@ static int mov_read_stts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) get_byte(pb); /* version */ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(Time2Sample)) + if(entries >= UINT_MAX / sizeof(MOV_stts_t)) return -1; sc->stts_count = entries; - sc->stts_data = av_malloc(entries * sizeof(Time2Sample)); - -#ifdef DEBUG -av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); -#endif + sc->stts_data = av_malloc(entries * sizeof(MOV_stts_t)); + if (!sc->stts_data) + return -1; + dprintf(c->fc, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries); sc->time_rate=0; @@ -1079,18 +1058,19 @@ av_log(NULL, AV_LOG_DEBUG, "track[%i].stts.entries = %i\n", c->fc->nb_streams-1, static int mov_read_ctts(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; - MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; + MOVStreamContext *sc = st->priv_data; unsigned int i, entries; get_byte(pb); /* version */ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb); - if(entries >= UINT_MAX / sizeof(Time2Sample)) + if(entries >= UINT_MAX / sizeof(MOV_stts_t)) return -1; sc->ctts_count = entries; - sc->ctts_data = av_malloc(entries * sizeof(Time2Sample)); - + sc->ctts_data = av_malloc(entries * sizeof(MOV_stts_t)); + if (!sc->ctts_data) + return -1; dprintf(c->fc, "track[%i].ctts.entries = %i\n", c->fc->nb_streams-1, entries); for(i=0; i<entries; i++) { @@ -1127,11 +1107,53 @@ static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) st->priv_data = sc; st->codec->codec_type = CODEC_TYPE_DATA; st->start_time = 0; /* XXX: check */ - c->streams[c->fc->nb_streams-1] = sc; return mov_read_default(c, pb, atom); } +static void mov_parse_udta_string(ByteIOContext *pb, char *str, int size) +{ + uint16_t str_size = get_be16(pb); /* string length */; + + get_be16(pb); /* skip language */ + get_buffer(pb, str, FFMIN(size, str_size)); +} + +static int mov_read_udta(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) +{ + uint64_t end = url_ftell(pb) + atom.size; + + while (url_ftell(pb) + 8 < end) { + uint32_t tag_size = get_be32(pb); + uint32_t tag = get_le32(pb); + uint64_t next = url_ftell(pb) + tag_size - 8; + + if (next > end) // stop if tag_size is wrong + break; + + switch (tag) { + case MKTAG(0xa9,'n','a','m'): + mov_parse_udta_string(pb, c->fc->title, sizeof(c->fc->title)); + break; + case MKTAG(0xa9,'w','r','t'): + mov_parse_udta_string(pb, c->fc->author, sizeof(c->fc->author)); + break; + case MKTAG(0xa9,'c','p','y'): + mov_parse_udta_string(pb, c->fc->copyright, sizeof(c->fc->copyright)); + break; + case MKTAG(0xa9,'i','n','f'): + mov_parse_udta_string(pb, c->fc->comment, sizeof(c->fc->comment)); + break; + default: + break; + } + + url_fseek(pb, next, SEEK_SET); + } + + return 0; +} + static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; @@ -1252,18 +1274,23 @@ static int mov_read_cmov(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) /* edit list atom */ static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom) { + MOVStreamContext *sc = c->fc->streams[c->fc->nb_streams-1]->priv_data; int i, edit_count; get_byte(pb); /* version */ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ - edit_count= c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */ + edit_count= sc->edit_count = get_be32(pb); /* entries */ for(i=0; i<edit_count; i++){ + int time; get_be32(pb); /* Track duration */ - get_be32(pb); /* Media time */ + time = get_be32(pb); /* Media time */ get_be32(pb); /* Media rate */ + if (time != 0) + av_log(c->fc, AV_LOG_WARNING, "edit list not starting at 0, " + "a/v desync might occur, patch welcome\n"); } - dprintf(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count); + dprintf(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, sc->edit_count); return 0; } @@ -1271,11 +1298,14 @@ static const MOVParseTableEntry mov_default_parse_table[] = { /* mp4 atoms */ { MKTAG( 'c', 'o', '6', '4' ), mov_read_stco }, { MKTAG( 'c', 't', 't', 's' ), mov_read_ctts }, /* composition time to sample */ +{ MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, +{ MKTAG( 'd', 'r', 'e', 'f' ), mov_read_dref }, { MKTAG( 'e', 'd', 't', 's' ), mov_read_default }, { MKTAG( 'e', 'l', 's', 't' ), mov_read_elst }, { MKTAG( 'e', 'n', 'd', 'a' ), mov_read_enda }, { MKTAG( 'f', 'i', 'e', 'l' ), mov_read_extradata }, { MKTAG( 'f', 't', 'y', 'p' ), mov_read_ftyp }, +{ MKTAG( 'g', 'l', 'b', 'l' ), mov_read_glbl }, { MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr }, { MKTAG( 'j', 'p', '2', 'h' ), mov_read_extradata }, { MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat }, @@ -1286,7 +1316,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { 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', 'v', 'c', 'C' ), mov_read_avcC }, +{ MKTAG( 'a', 'v', 'c', 'C' ), mov_read_glbl }, { MKTAG( 's', 't', 'b', 'l' ), mov_read_default }, { MKTAG( 's', 't', 'c', 'o' ), mov_read_stco }, { MKTAG( 's', 't', 's', 'c' ), mov_read_stsc }, @@ -1296,22 +1326,14 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG( 's', 't', 't', 's' ), mov_read_stts }, { MKTAG( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */ { MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak }, +{ MKTAG( 'u', 'd', 't', 'a' ), mov_read_udta }, { MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave }, -{ MKTAG( 'c', 't', 'a', 'b' ), mov_read_ctab }, { MKTAG( 'e', 's', 'd', 's' ), mov_read_esds }, { MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder */ { MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov }, -{ 0L, NULL } +{ 0, NULL } }; -static void mov_free_stream_context(MOVStreamContext *sc) -{ - if(sc) { - av_freep(&sc->ctts_data); - av_freep(&sc); - } -} - /* XXX: is it sufficient ? */ static int mov_probe(AVProbeData *p) { @@ -1320,8 +1342,6 @@ static int mov_probe(AVProbeData *p) int score = 0; /* check file header */ - if (p->buf_size <= 12) - return 0; offset = 0; for(;;) { /* ignore invalid offset */ @@ -1337,11 +1357,13 @@ static int mov_probe(AVProbeData *p) case MKTAG( 'u', 'd', 't', 'a' ): /* Packet Video PVAuthor adds this and a lot of more junk */ return AVPROBE_SCORE_MAX; /* those are more common words, so rate then a bit less */ + case MKTAG( 'e', 'd', 'i', 'w' ): /* xdcam files have reverted first tags */ case MKTAG( 'w', 'i', 'd', 'e' ): case MKTAG( 'f', 'r', 'e', 'e' ): case MKTAG( 'j', 'u', 'n', 'k' ): case MKTAG( 'p', 'i', 'c', 't' ): return AVPROBE_SCORE_MAX - 5; + case MKTAG(0x82,0x82,0x7f,0x7d ): case MKTAG( 'f', 't', 'y', 'p' ): case MKTAG( 's', 'k', 'i', 'p' ): case MKTAG( 'u', 'u', 'i', 'd' ): @@ -1365,34 +1387,40 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int stts_index = 0; unsigned int stsc_index = 0; unsigned int stss_index = 0; - unsigned int i, j, k; + unsigned int i, j; - if (sc->sample_sizes || st->codec->codec_type == CODEC_TYPE_VIDEO || sc->dv_audio_container) { + if (sc->sample_sizes || st->codec->codec_type == CODEC_TYPE_VIDEO || + sc->audio_cid == -2) { unsigned int current_sample = 0; unsigned int stts_sample = 0; unsigned int keyframe, sample_size; unsigned int distance = 0; + int key_off = sc->keyframes && sc->keyframes[0] == 1; st->nb_frames = sc->sample_count; for (i = 0; i < sc->chunk_count; i++) { current_offset = sc->chunk_offsets[i]; - if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) + if (stsc_index + 1 < sc->sample_to_chunk_sz && + i + 1 == sc->sample_to_chunk[stsc_index + 1].first) stsc_index++; for (j = 0; j < sc->sample_to_chunk[stsc_index].count; j++) { if (current_sample >= sc->sample_count) { av_log(mov->fc, AV_LOG_ERROR, "wrong sample count\n"); goto out; } - keyframe = !sc->keyframe_count || current_sample + 1 == sc->keyframes[stss_index]; + keyframe = !sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index]; if (keyframe) { distance = 0; if (stss_index + 1 < sc->keyframe_count) stss_index++; } sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample]; - dprintf(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", size %d, distance %d, keyframe %d\n", - st->index, current_sample, current_offset, current_dts, sample_size, distance, keyframe); - av_add_index_entry(st, current_offset, current_dts, sample_size, distance, keyframe ? AVINDEX_KEYFRAME : 0); + dprintf(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " + "size %d, distance %d, keyframe %d\n", st->index, current_sample, + current_offset, current_dts, sample_size, distance, keyframe); + if(sc->sample_to_chunk[stsc_index].id - 1 == sc->pseudo_stream_id) + av_add_index_entry(st, current_offset, current_dts, sample_size, distance, + keyframe ? AVINDEX_KEYFRAME : 0); current_offset += sample_size; assert(sc->stts_data[stts_index].duration % sc->time_rate == 0); current_dts += sc->stts_data[stts_index].duration / sc->time_rate; @@ -1407,63 +1435,51 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } else { /* read whole chunk */ unsigned int chunk_samples, chunk_size, chunk_duration; - + unsigned int frames = 1; for (i = 0; i < sc->chunk_count; i++) { current_offset = sc->chunk_offsets[i]; - if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) + if (stsc_index + 1 < sc->sample_to_chunk_sz && + i + 1 == sc->sample_to_chunk[stsc_index + 1].first) stsc_index++; chunk_samples = sc->sample_to_chunk[stsc_index].count; - /* get chunk size */ - if (sc->sample_size > 1 || st->codec->codec_id == CODEC_ID_PCM_U8 || st->codec->codec_id == CODEC_ID_PCM_S8) - chunk_size = chunk_samples * sc->sample_size; - else if (sc->samples_per_frame > 0 && (chunk_samples * sc->bytes_per_frame % sc->samples_per_frame == 0)) - chunk_size = chunk_samples * sc->bytes_per_frame / sc->samples_per_frame; - else { /* workaround to find nearest next chunk offset */ - chunk_size = INT_MAX; - for (j = 0; j < mov->total_streams; j++) { - MOVStreamContext *msc = mov->streams[j]; - - for (k = msc->next_chunk; k < msc->chunk_count; k++) { - if (msc->chunk_offsets[k] > current_offset && msc->chunk_offsets[k] - current_offset < chunk_size) { - chunk_size = msc->chunk_offsets[k] - current_offset; - msc->next_chunk = k; - break; - } - } - } - /* check for last chunk */ - if (chunk_size == INT_MAX) - for (j = 0; j < mov->mdat_count; j++) { - dprintf(mov->fc, "mdat %d, offset %"PRIx64", size %"PRId64", current offset %"PRIx64"\n", - j, mov->mdat_list[j].offset, mov->mdat_list[j].size, current_offset); - if (mov->mdat_list[j].offset <= current_offset && mov->mdat_list[j].offset + mov->mdat_list[j].size > current_offset) - chunk_size = mov->mdat_list[j].offset + mov->mdat_list[j].size - current_offset; - } - assert(chunk_size != INT_MAX); - for (j = 0; j < mov->total_streams; j++) { - mov->streams[j]->next_chunk = 0; + /* get chunk size, beware of alaw/ulaw/mace */ + if (sc->samples_per_frame > 0 && + (chunk_samples * sc->bytes_per_frame % sc->samples_per_frame == 0)) { + if (sc->samples_per_frame < 1024) + chunk_size = chunk_samples * sc->bytes_per_frame / sc->samples_per_frame; + else { + chunk_size = sc->bytes_per_frame; + frames = chunk_samples / sc->samples_per_frame; + chunk_samples = sc->samples_per_frame; } + } else if (sc->sample_size > 1 || st->codec->bits_per_sample == 8) { + chunk_size = chunk_samples * sc->sample_size; + } else { + av_log(mov->fc, AV_LOG_ERROR, "could not determine chunk size, report problem\n"); + goto out; } - av_add_index_entry(st, current_offset, current_dts, chunk_size, 0, AVINDEX_KEYFRAME); - /* get chunk duration */ - chunk_duration = 0; - while (chunk_samples > 0) { - if (chunk_samples < sc->stts_data[stts_index].count) { - chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; - sc->stts_data[stts_index].count -= chunk_samples; - break; - } else { - chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; - chunk_samples -= sc->stts_data[stts_index].count; - if (stts_index + 1 < sc->stts_count) { - stts_index++; + for (j = 0; j < frames; j++) { + av_add_index_entry(st, current_offset, current_dts, chunk_size, 0, AVINDEX_KEYFRAME); + /* get chunk duration */ + chunk_duration = 0; + while (chunk_samples > 0) { + if (chunk_samples < sc->stts_data[stts_index].count) { + chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; + sc->stts_data[stts_index].count -= chunk_samples; + break; + } else { + chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; + chunk_samples -= sc->stts_data[stts_index].count; + if (stts_index + 1 < sc->stts_count) + stts_index++; } } + current_offset += sc->bytes_per_frame; + dprintf(mov->fc, "AVIndex stream %d, chunk %d, offset %"PRIx64", dts %"PRId64", size %d, " + "duration %d\n", st->index, i, current_offset, current_dts, chunk_size, chunk_duration); + assert(chunk_duration % sc->time_rate == 0); + current_dts += chunk_duration / sc->time_rate; } - dprintf(mov->fc, "AVIndex stream %d, chunk %d, offset %"PRIx64", dts %"PRId64", size %d, duration %d\n", - st->index, i, current_offset, current_dts, chunk_size, chunk_duration); - assert(chunk_duration % sc->time_rate == 0); - current_dts += chunk_duration / sc->time_rate; } } out: @@ -1473,18 +1489,17 @@ static void mov_build_index(MOVContext *mov, AVStream *st) static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) { - MOVContext *mov = (MOVContext *) s->priv_data; - ByteIOContext *pb = &s->pb; + MOVContext *mov = s->priv_data; + ByteIOContext *pb = s->pb; int i, err; MOV_atom_t atom = { 0, 0, 0 }; mov->fc = s; - mov->parse_table = mov_default_parse_table; if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ atom.size = url_fsize(pb); else - atom.size = 0x7FFFFFFFFFFFFFFFLL; + atom.size = INT64_MAX; /* check MOV header */ err = mov_read_default(mov, pb, atom); @@ -1495,15 +1510,9 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) } dprintf(mov->fc, "on_parse_exit_offset=%d\n", (int) url_ftell(pb)); - /* some cleanup : make sure we are on the mdat atom */ - if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) - url_fseek(pb, mov->mdat_offset, SEEK_SET); - - mov->total_streams = s->nb_streams; - - for(i=0; i<mov->total_streams; i++) { - MOVStreamContext *sc = mov->streams[i]; + for(i=0; i<s->nb_streams; i++) { AVStream *st = s->streams[i]; + MOVStreamContext *sc = st->priv_data; /* sanity checks */ if(!sc->stts_count || !sc->chunk_count || !sc->sample_to_chunk_sz || (!sc->sample_size && !sc->sample_count)){ @@ -1518,7 +1527,7 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) av_set_pts_info(st, 64, sc->time_rate, sc->time_scale); if (st->codec->codec_type == CODEC_TYPE_AUDIO && sc->stts_count == 1) - st->codec->frame_size = sc->stts_data[0].duration; + st->codec->frame_size = av_rescale(sc->time_rate, st->codec->sample_rate, sc->time_scale); if(st->duration != AV_NOPTS_VALUE){ assert(st->duration % sc->time_rate == 0); @@ -1526,17 +1535,48 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) } sc->ffindex = i; mov_build_index(mov, st); + + if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { + if (url_fopen(&sc->pb, sc->drefs[sc->dref_id-1].path, URL_RDONLY) < 0) + av_log(s, AV_LOG_ERROR, "stream %d, error opening external essence: %s\n", + st->index, strerror(errno)); + } else + sc->pb = s->pb; + + switch (st->codec->codec_id) { +#ifdef CONFIG_H261_DECODER + case CODEC_ID_H261: +#endif +#ifdef CONFIG_H263_DECODER + case CODEC_ID_H263: +#endif +#ifdef CONFIG_MPEG4_DECODER + case CODEC_ID_MPEG4: +#endif + st->codec->width= 0; /* let decoder init width/height */ + st->codec->height= 0; + break; +#ifdef CONFIG_LIBFAAD + case CODEC_ID_AAC: +#endif +#ifdef CONFIG_VORBIS_DECODER + case CODEC_ID_VORBIS: +#endif + case CODEC_ID_MP3ON4: + st->codec->sample_rate= 0; /* let decoder init parameters properly */ + break; + } } - for(i=0; i<mov->total_streams; i++) { - /* dont need those anymore */ - av_freep(&mov->streams[i]->chunk_offsets); - av_freep(&mov->streams[i]->sample_to_chunk); - av_freep(&mov->streams[i]->sample_sizes); - av_freep(&mov->streams[i]->keyframes); - av_freep(&mov->streams[i]->stts_data); + for(i=0; i<s->nb_streams; i++) { + MOVStreamContext *sc = s->streams[i]->priv_data; + /* Do not need those anymore. */ + av_freep(&sc->chunk_offsets); + av_freep(&sc->sample_to_chunk); + av_freep(&sc->sample_sizes); + av_freep(&sc->keyframes); + av_freep(&sc->stts_data); } - av_freep(&mov->mdat_list); return 0; } @@ -1548,15 +1588,19 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) int64_t best_dts = INT64_MAX; int i; - for (i = 0; i < mov->total_streams; i++) { - MOVStreamContext *msc = mov->streams[i]; - - if (s->streams[i]->discard != AVDISCARD_ALL && msc->current_sample < msc->sample_count) { - AVIndexEntry *current_sample = &s->streams[i]->index_entries[msc->current_sample]; - int64_t dts = av_rescale(current_sample->timestamp * (int64_t)msc->time_rate, AV_TIME_BASE, msc->time_scale); - - dprintf(s, "stream %d, sample %ld, dts %"PRId64"\n", i, msc->current_sample, dts); - if (dts < best_dts) { + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + MOVStreamContext *msc = st->priv_data; + if (st->discard != AVDISCARD_ALL && msc->pb && msc->current_sample < msc->sample_count) { + AVIndexEntry *current_sample = &st->index_entries[msc->current_sample]; + int64_t dts = av_rescale(current_sample->timestamp * (int64_t)msc->time_rate, + AV_TIME_BASE, msc->time_scale); + dprintf(s, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts); + if (!sample || (url_is_streamed(s->pb) && current_sample->pos < sample->pos) || + (!url_is_streamed(s->pb) && + ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb && + ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) || + (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) { sample = current_sample; best_dts = dts; sc = msc; @@ -1567,24 +1611,19 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) return -1; /* must be done just before reading, to avoid infinite loop on sample */ sc->current_sample++; - if (sample->pos >= url_fsize(&s->pb)) { - av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n", sc->ffindex, sample->pos); + if (url_fseek(sc->pb, sample->pos, SEEK_SET) != sample->pos) { + av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n", + sc->ffindex, sample->pos); return -1; } + av_get_packet(sc->pb, pkt, sample->size); #ifdef CONFIG_DV_DEMUXER - if (sc->dv_audio_container) { - dv_get_packet(mov->dv_demux, pkt); - dprintf(s, "dv audio pkt size %d\n", pkt->size); - } else { -#endif - url_fseek(&s->pb, sample->pos, SEEK_SET); - av_get_packet(&s->pb, pkt, sample->size); -#ifdef CONFIG_DV_DEMUXER - if (mov->dv_demux) { - void *pkt_destruct_func = pkt->destruct; - dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); - pkt->destruct = pkt_destruct_func; - } + if (mov->dv_demux && sc->dv_audio_container) { + dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size); + av_free(pkt->data); + pkt->size = 0; + if (dv_get_packet(mov->dv_demux, pkt) < 0) + return -1; } #endif pkt->stream_index = sc->ffindex; @@ -1594,7 +1633,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->pts = pkt->dts + sc->ctts_data[sc->sample_to_ctime_index].duration / sc->time_rate; /* update ctts context */ sc->sample_to_ctime_sample++; - if (sc->sample_to_ctime_index < sc->ctts_count && sc->ctts_data[sc->sample_to_ctime_index].count == sc->sample_to_ctime_sample) { + if (sc->sample_to_ctime_index < sc->ctts_count && + sc->ctts_data[sc->sample_to_ctime_index].count == sc->sample_to_ctime_sample) { sc->sample_to_ctime_index++; sc->sample_to_ctime_sample = 0; } @@ -1603,7 +1643,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) } pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? PKT_FLAG_KEY : 0; pkt->pos = sample->pos; - dprintf(s, "stream %d, pts %"PRId64", dts %"PRId64", pos 0x%"PRIx64", duration %d\n", pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration); + dprintf(s, "stream %d, pts %"PRId64", dts %"PRId64", pos 0x%"PRIx64", duration %d\n", + pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration); return 0; } @@ -1618,17 +1659,18 @@ static int mov_seek_stream(AVStream *st, int64_t timestamp, int flags) if (sample < 0) /* not sure what to do */ return -1; sc->current_sample = sample; - dprintf(st->codec, "stream %d, found sample %ld\n", st->index, sc->current_sample); + dprintf(st->codec, "stream %d, found sample %d\n", st->index, sc->current_sample); /* adjust ctts index */ if (sc->ctts_data) { time_sample = 0; for (i = 0; i < sc->ctts_count; i++) { - time_sample += sc->ctts_data[i].count; - if (time_sample >= sc->current_sample) { + int next = time_sample + sc->ctts_data[i].count; + if (next > sc->current_sample) { sc->sample_to_ctime_index = i; - sc->sample_to_ctime_sample = time_sample - sc->current_sample; + sc->sample_to_ctime_sample = sc->current_sample - time_sample; break; } + time_sample = next; } } return sample; @@ -1665,13 +1707,17 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti static int mov_read_close(AVFormatContext *s) { - int i; - MOVContext *mov = (MOVContext *) s->priv_data; - for(i=0; i<mov->total_streams; i++) - mov_free_stream_context(mov->streams[i]); - /* free color tabs */ - for(i=0; i<mov->ctab_size; i++) - av_freep(&mov->ctab[i]); + int i, j; + MOVContext *mov = s->priv_data; + for(i=0; i<s->nb_streams; i++) { + MOVStreamContext *sc = s->streams[i]->priv_data; + av_freep(&sc->ctts_data); + for (j=0; j<sc->drefs_count; j++) + av_freep(&sc->drefs[j].path); + av_freep(&sc->drefs); + if (sc->pb && sc->pb != s->pb) + url_fclose(sc->pb); + } if(mov->dv_demux){ for(i=0; i<mov->dv_fctx->nb_streams; i++){ av_freep(&mov->dv_fctx->streams[i]->codec); @@ -1680,7 +1726,6 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->dv_fctx); av_freep(&mov->dv_demux); } - av_freep(&mov->ctab); return 0; } diff --git a/contrib/ffmpeg/libavformat/movenc.c b/contrib/ffmpeg/libavformat/movenc.c index e93416914..501c44ebd 100644 --- a/contrib/ffmpeg/libavformat/movenc.c +++ b/contrib/ffmpeg/libavformat/movenc.c @@ -23,6 +23,7 @@ #include "riff.h" #include "avio.h" #include "isom.h" +#include "avc.h" #undef NDEBUG #include <assert.h> @@ -59,7 +60,7 @@ typedef struct MOVIndex { int hasBframes; int language; int trackID; - int tag; + int tag; ///< stsd fourcc AVCodecContext *enc; int vosLen; @@ -78,7 +79,7 @@ typedef struct MOVContext { MOVTrack tracks[MAX_STREAMS]; } MOVContext; -//FIXME supprt 64bit varaint with wide placeholders +//FIXME support 64 bit variant with wide placeholders static offset_t updateSize (ByteIOContext *pb, offset_t pos) { offset_t curpos = url_ftell(pb); @@ -140,7 +141,7 @@ static int mov_write_stsz_tag(ByteIOContext *pb, MOVTrack* track) put_be32(pb, 0); // sample size put_be32(pb, entries); // sample count for (i=0; i<track->entry; i++) { - for ( j=0; j<track->cluster[i].entries; j++) { + for (j=0; j<track->cluster[i].entries; j++) { put_be32(pb, track->cluster[i].size / track->cluster[i].entries); } @@ -322,6 +323,14 @@ static int mov_write_wave_tag(ByteIOContext *pb, MOVTrack* track) return updateSize (pb, pos); } +static int mov_write_glbl_tag(ByteIOContext *pb, MOVTrack* track) +{ + put_be32(pb, track->vosLen+8); + put_tag(pb, "glbl"); + put_buffer(pb, track->vosData, track->vosLen); + return 8+track->vosLen; +} + static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track) { offset_t pos = url_ftell(pb); @@ -372,10 +381,12 @@ static int mov_write_audio_tag(ByteIOContext *pb, MOVTrack* track) track->enc->codec_id == CODEC_ID_PCM_S24LE || track->enc->codec_id == CODEC_ID_PCM_S32LE)) mov_write_wave_tag(pb, track); - else if(track->enc->codec_id == CODEC_ID_AAC) + else if(track->tag == MKTAG('m','p','4','a')) mov_write_esds_tag(pb, track); else if(track->enc->codec_id == CODEC_ID_AMR_NB) mov_write_amr_tag(pb, track); + else if(track->vosLen > 0) + mov_write_glbl_tag(pb, track); return updateSize (pb, pos); } @@ -405,170 +416,128 @@ static int mov_write_svq3_tag(ByteIOContext *pb) return 0x15; } -static uint8_t *avc_find_startcode( uint8_t *p, uint8_t *end ) -{ - uint8_t *a = p + 4 - ((int)p & 3); - - for( end -= 3; p < a && p < end; p++ ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - return p; - } - - for( end -= 3; p < end; p += 4 ) { - uint32_t x = *(uint32_t*)p; -// if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian -// if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian - if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic - if( p[1] == 0 ) { - if( p[0] == 0 && p[2] == 1 ) - return p-1; - if( p[2] == 0 && p[3] == 1 ) - return p; - } - if( p[3] == 0 ) { - if( p[2] == 0 && p[4] == 1 ) - return p+1; - if( p[4] == 0 && p[5] == 1 ) - return p+2; - } - } - } - - for( end += 3; p < end; p++ ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - return p; - } - - return end + 3; -} - -static void avc_parse_nal_units(uint8_t **buf, int *size) -{ - ByteIOContext pb; - uint8_t *p = *buf; - uint8_t *end = p + *size; - uint8_t *nal_start, *nal_end; - - url_open_dyn_buf(&pb); - nal_start = avc_find_startcode(p, end); - while (nal_start < end) { - while(!*(nal_start++)); - nal_end = avc_find_startcode(nal_start, end); - put_be32(&pb, nal_end - nal_start); - put_buffer(&pb, nal_start, nal_end - nal_start); - nal_start = nal_end; - } - av_freep(buf); - *size = url_close_dyn_buf(&pb, buf); -} - static int mov_write_avcc_tag(ByteIOContext *pb, MOVTrack *track) { offset_t pos = url_ftell(pb); put_be32(pb, 0); put_tag(pb, "avcC"); - if (track->vosLen > 6) { - /* check for h264 start code */ - if (AV_RB32(track->vosData) == 0x00000001) { - uint8_t *buf, *end; - uint32_t sps_size=0, pps_size=0; - uint8_t *sps=0, *pps=0; - - avc_parse_nal_units(&track->vosData, &track->vosLen); - buf = track->vosData; - end = track->vosData + track->vosLen; - - /* look for sps and pps */ - while (buf < end) { - unsigned int size; - uint8_t nal_type; - size = AV_RB32(buf); - nal_type = buf[4] & 0x1f; - if (nal_type == 7) { /* SPS */ - sps = buf + 4; - sps_size = size; - } else if (nal_type == 8) { /* PPS */ - pps = buf + 4; - pps_size = size; - } - buf += size + 4; - } - assert(sps); - assert(pps); - - put_byte(pb, 1); /* version */ - put_byte(pb, sps[1]); /* profile */ - put_byte(pb, sps[2]); /* profile compat */ - put_byte(pb, sps[3]); /* level */ - put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ - put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ - - put_be16(pb, sps_size); - put_buffer(pb, sps, sps_size); - put_byte(pb, 1); /* number of pps */ - put_be16(pb, pps_size); - put_buffer(pb, pps, pps_size); - } else { - put_buffer(pb, track->vosData, track->vosLen); - } - } + ff_isom_write_avcc(pb, track->vosData, track->vosLen); return updateSize(pb, pos); } -static int mov_find_video_codec_tag(AVFormatContext *s, MOVTrack *track) +/* also used by all avid codecs (dv, imx, meridien) and their variants */ +static int mov_write_avid_tag(ByteIOContext *pb, MOVTrack *track) { - int tag = track->enc->codec_tag; - if (!tag) { - if (track->enc->codec_id == CODEC_ID_DVVIDEO) { - if (track->enc->height == 480) { /* NTSC */ - if (track->enc->pix_fmt == PIX_FMT_YUV422P) - tag = MKTAG('d', 'v', '5', 'n'); - else - tag = MKTAG('d', 'v', 'c', ' '); - } else { /* assume PAL */ - if (track->enc->pix_fmt == PIX_FMT_YUV422P) - tag = MKTAG('d', 'v', '5', 'p'); - else if (track->enc->pix_fmt == PIX_FMT_YUV420P) - tag = MKTAG('d', 'v', 'c', 'p'); - else - tag = MKTAG('d', 'v', 'p', 'p'); - } - } else if (track->enc->codec_id == CODEC_ID_H263) { - if (track->mode == MODE_MOV) - tag = MKTAG('h', '2', '6', '3'); - else - tag = MKTAG('s', '2', '6', '3'); - } else { - tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id); - } - } - // if no mac fcc found, try with Microsoft tags - if (!tag) { - tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id); - if (tag) { - av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, the file may be unplayable!\n"); - } + int i; + put_be32(pb, 24); /* size */ + put_tag(pb, "ACLR"); + put_tag(pb, "ACLR"); + put_tag(pb, "0001"); + put_be32(pb, 1); /* yuv 1 / rgb 2 ? */ + put_be32(pb, 0); /* unknown */ + + put_be32(pb, 24); /* size */ + put_tag(pb, "APRG"); + put_tag(pb, "APRG"); + put_tag(pb, "0001"); + put_be32(pb, 1); /* unknown */ + put_be32(pb, 0); /* unknown */ + + put_be32(pb, 120); /* size */ + put_tag(pb, "ARES"); + put_tag(pb, "ARES"); + put_tag(pb, "0001"); + put_be32(pb, AV_RB32(track->vosData + 0x28)); /* dnxhd cid, some id ? */ + put_be32(pb, track->enc->width); + /* values below are based on samples created with quicktime and avid codecs */ + if (track->vosData[5] & 2) { // interlaced + put_be32(pb, track->enc->height/2); + put_be32(pb, 2); /* unknown */ + put_be32(pb, 0); /* unknown */ + put_be32(pb, 4); /* unknown */ + } else { + put_be32(pb, track->enc->height); + put_be32(pb, 1); /* unknown */ + put_be32(pb, 0); /* unknown */ + if (track->enc->height == 1080) + put_be32(pb, 5); /* unknown */ + else + put_be32(pb, 6); /* unknown */ } - assert(tag); - return tag; + /* padding */ + for (i = 0; i < 10; i++) + put_be64(pb, 0); + + /* extra padding for stsd needed */ + put_be32(pb, 0); + return 0; } -static int mov_find_audio_codec_tag(AVFormatContext *s, MOVTrack *track) +static const AVCodecTag codec_3gp_tags[] = { + { CODEC_ID_H263, MKTAG('s','2','6','3') }, + { CODEC_ID_H264, MKTAG('a','v','c','1') }, + { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, + { CODEC_ID_AAC, MKTAG('m','p','4','a') }, + { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, + { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') }, +}; + +static const AVCodecTag mov_pix_fmt_tags[] = { + { PIX_FMT_YUYV422, MKTAG('y','u','v','s') }, + { PIX_FMT_UYVY422, MKTAG('2','v','u','y') }, + { PIX_FMT_BGR555, MKTAG('r','a','w',' ') }, + { PIX_FMT_RGB24, MKTAG('r','a','w',' ') }, + { PIX_FMT_BGR32_1, MKTAG('r','a','w',' ') }, +}; + +static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) { int tag = track->enc->codec_tag; - if (!tag) { - tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id); - } - // if no mac fcc found, try with Microsoft tags - if (!tag) { - int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id); - if (ms_tag) { - tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff)); - av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, the file may be unplayable!\n"); + if (track->mode == MODE_MP4 || track->mode == MODE_PSP) { + if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id)) + return 0; + if (track->enc->codec_id == CODEC_ID_H264) tag = MKTAG('a','v','c','1'); + else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); + else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); + } else if (track->mode == MODE_3GP || track->mode == MODE_3G2) { + tag = codec_get_tag(codec_3gp_tags, track->enc->codec_id); + } else if (!tag || (track->enc->strict_std_compliance >= FF_COMPLIANCE_NORMAL && + (tag == MKTAG('d','v','c','p') || + track->enc->codec_id == CODEC_ID_RAWVIDEO))) { + if (track->enc->codec_id == CODEC_ID_DVVIDEO) { + if (track->enc->height == 480) /* NTSC */ + if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n'); + else tag = MKTAG('d','v','c',' '); + else if (track->enc->pix_fmt == PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p'); + else if (track->enc->pix_fmt == PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p'); + else tag = MKTAG('d','v','p','p'); + } else if (track->enc->codec_id == CODEC_ID_RAWVIDEO) { + tag = codec_get_tag(mov_pix_fmt_tags, track->enc->pix_fmt); + if (!tag) // restore tag + tag = track->enc->codec_tag; + } else { + if (track->enc->codec_type == CODEC_TYPE_VIDEO) { + tag = codec_get_tag(codec_movvideo_tags, track->enc->codec_id); + if (!tag) { // if no mac fcc found, try with Microsoft tags + tag = codec_get_tag(codec_bmp_tags, track->enc->codec_id); + if (tag) + av_log(s, AV_LOG_INFO, "Warning, using MS style video codec tag, " + "the file may be unplayable!\n"); + } + } else if (track->enc->codec_type == CODEC_TYPE_AUDIO) { + tag = codec_get_tag(codec_movaudio_tags, track->enc->codec_id); + if (!tag) { // if no mac fcc found, try with Microsoft tags + int ms_tag = codec_get_tag(codec_wav_tags, track->enc->codec_id); + if (ms_tag) { + tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff)); + av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, " + "the file may be unplayable!\n"); + } + } + } } } - assert(tag); return tag; } @@ -613,9 +582,12 @@ static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track) put_byte(pb, strlen(compressor_name)); put_buffer(pb, compressor_name, 31); - put_be16(pb, 0x18); /* Reserved */ + if (track->mode == MODE_MOV && track->enc->bits_per_sample) + put_be16(pb, track->enc->bits_per_sample); + else + put_be16(pb, 0x18); /* Reserved */ put_be16(pb, 0xffff); /* Reserved */ - if(track->enc->codec_id == CODEC_ID_MPEG4) + if(track->tag == MKTAG('m','p','4','v')) mov_write_esds_tag(pb, track); else if(track->enc->codec_id == CODEC_ID_H263) mov_write_d263_tag(pb); @@ -623,6 +595,10 @@ static int mov_write_video_tag(ByteIOContext *pb, MOVTrack* track) mov_write_svq3_tag(pb); else if(track->enc->codec_id == CODEC_ID_H264) mov_write_avcc_tag(pb, track); + else if(track->enc->codec_id == CODEC_ID_DNXHD) + mov_write_avid_tag(pb, track); + else if(track->vosLen > 0) + mov_write_glbl_tag(pb, track); return updateSize (pb, pos); } @@ -643,7 +619,7 @@ static int mov_write_stsd_tag(ByteIOContext *pb, MOVTrack* track) static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track) { - Time2Sample *ctts_entries; + MOV_stts_t *ctts_entries; uint32_t entries = 0; uint32_t atom_size; int i; @@ -677,7 +653,7 @@ static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack* track) /* Time to sample atom */ static int mov_write_stts_tag(ByteIOContext *pb, MOVTrack* track) { - Time2Sample *stts_entries; + MOV_stts_t *stts_entries; uint32_t entries = -1; uint32_t atom_size; int i; @@ -845,6 +821,14 @@ static int mov_write_mdhd_tag(ByteIOContext *pb, MOVTrack* track) (version == 1) ? put_be64(pb, track->trackDuration) : put_be32(pb, track->trackDuration); /* duration */ put_be16(pb, track->language); /* language */ put_be16(pb, 0); /* reserved (quality) */ + + if(version!=0 && track->mode == MODE_MOV){ + av_log(NULL, AV_LOG_ERROR, + "FATAL error, file duration too long for timebase, this file will not be\n" + "playable with quicktime. Choose a different timebase or a different\n" + "container format\n"); + } + return 32; } @@ -903,7 +887,7 @@ static int mov_write_tkhd_tag(ByteIOContext *pb, MOVTrack* track) /* Track width and height, for visual only */ if(track->enc->codec_type == CODEC_TYPE_VIDEO) { double sample_aspect_ratio = av_q2d(track->enc->sample_aspect_ratio); - if( !sample_aspect_ratio ) sample_aspect_ratio = 1; + if(!sample_aspect_ratio) sample_aspect_ratio = 1; put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000); put_be32(pb, track->enc->height*0x10000); } @@ -1075,7 +1059,7 @@ static int mov_write_string_data_tag(ByteIOContext *pb, const char *data, int lo static int mov_write_string_tag(ByteIOContext *pb, const char *name, const char *value, int long_style){ int size = 0; - if ( value && value[0] ) { + if (value && value[0]) { offset_t pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, name); @@ -1101,7 +1085,7 @@ static int mov_write_trkn_tag(ByteIOContext *pb, MOVContext* mov, AVFormatContext *s) { int size = 0; - if ( s->track ) { + if (s->track) { offset_t pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, "trkn"); @@ -1149,8 +1133,8 @@ static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov, int size = 0; // only save meta tag if required - if ( s->title[0] || s->author[0] || s->album[0] || s->year || - s->comment[0] || s->genre[0] || s->track ) { + if (s->title[0] || s->author[0] || s->album[0] || s->year || + s->comment[0] || s->genre[0] || s->track) { offset_t pos = url_ftell(pb); put_be32(pb, 0); /* size */ put_tag(pb, "meta"); @@ -1165,40 +1149,52 @@ static int mov_write_meta_tag(ByteIOContext *pb, MOVContext* mov, static int mov_write_udta_tag(ByteIOContext *pb, MOVContext* mov, AVFormatContext *s) { - offset_t pos = url_ftell(pb); - int i; - - put_be32(pb, 0); /* size */ - put_tag(pb, "udta"); - - /* iTunes meta data */ - mov_write_meta_tag(pb, mov, s); + int i, req = 0; - if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff isnt valid in mp4 /* Requirements */ for (i=0; i<mov->nb_streams; i++) { if(mov->tracks[i].entry <= 0) continue; if (mov->tracks[i].enc->codec_id == CODEC_ID_AAC || mov->tracks[i].enc->codec_id == CODEC_ID_MPEG4) { - mov_write_string_tag(pb, "\251req", "QuickTime 6.0 or greater", 0); + req = 1; break; } } - mov_write_string_tag(pb, "\251nam", s->title , 0); - mov_write_string_tag(pb, "\251aut", s->author , 0); - mov_write_string_tag(pb, "\251alb", s->album , 0); - mov_write_day_tag(pb, s->year, 0); - if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT)) - mov_write_string_tag(pb, "\251enc", LIBAVFORMAT_IDENT, 0); - mov_write_string_tag(pb, "\251des", s->comment , 0); - mov_write_string_tag(pb, "\251gen", s->genre , 0); - } + if (s->title[0] || s->author[0] || s->album[0] || s->year || + s->comment[0] || s->genre[0] || s->track || + (mov->mode == MODE_MOV && + ((mov->tracks[0].enc && !mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT) || req))) { + offset_t pos = url_ftell(pb); - return updateSize(pb, pos); + put_be32(pb, 0); /* size */ + put_tag(pb, "udta"); + + /* iTunes meta data */ + mov_write_meta_tag(pb, mov, s); + + if(mov->mode == MODE_MOV){ // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4 + /* Requirements */ + if (req) + mov_write_string_tag(pb, "\251req", "QuickTime 6.0 or greater", 0); + + mov_write_string_tag(pb, "\251nam", s->title , 0); + mov_write_string_tag(pb, "\251aut", s->author , 0); + mov_write_string_tag(pb, "\251alb", s->album , 0); + mov_write_day_tag(pb, s->year, 0); + if(mov->tracks[0].enc && !(mov->tracks[0].enc->flags & CODEC_FLAG_BITEXACT)) + mov_write_string_tag(pb, "\251enc", LIBAVFORMAT_IDENT, 0); + mov_write_string_tag(pb, "\251des", s->comment , 0); + mov_write_string_tag(pb, "\251gen", s->genre , 0); + } + + return updateSize(pb, pos); + } + + return 0; } -static int utf8len(uint8_t *b){ +static int utf8len(const uint8_t *b){ int len=0; int val; while(*b){ @@ -1208,7 +1204,7 @@ static int utf8len(uint8_t *b){ return len; } -static int ascii_to_wc (ByteIOContext *pb, uint8_t *b) +static int ascii_to_wc (ByteIOContext *pb, const uint8_t *b) { int val; while(*b){ @@ -1235,9 +1231,9 @@ static int mov_write_uuidusmt_tag (ByteIOContext *pb, AVFormatContext *s) put_be32(pb, 0); /* size placeholder*/ put_tag(pb, "uuid"); put_tag(pb, "USMT"); - put_be32(pb, 0x21d24fce ); /* 96 bit UUID */ - put_be32(pb, 0xbb88695c ); - put_be32(pb, 0xfac9c740 ); + put_be32(pb, 0x21d24fce); /* 96 bit UUID */ + put_be32(pb, 0xbb88695c); + put_be32(pb, 0xfac9c740); size += 24; put_be32(pb, 0); /* size placeholder*/ @@ -1328,7 +1324,7 @@ static int mov_write_moov_tag(ByteIOContext *pb, MOVContext *mov, if (mov->mode == MODE_PSP) mov_write_uuidusmt_tag(pb, s); - else + else if (mov->mode != MODE_3GP && mov->mode != MODE_3G2) mov_write_udta_tag(pb, mov, s); return updateSize(pb, pos); @@ -1350,29 +1346,29 @@ static void mov_write_ftyp_tag (ByteIOContext *pb, AVFormatContext *s) { MOVContext *mov = s->priv_data; - put_be32(pb, 0x14 ); /* size */ + put_be32(pb, 0x14); /* size */ put_tag(pb, "ftyp"); - if ( mov->mode == MODE_3GP ) + if (mov->mode == MODE_3GP) put_tag(pb, "3gp4"); - else if ( mov->mode == MODE_3G2 ) + else if (mov->mode == MODE_3G2) put_tag(pb, "3g2a"); - else if ( mov->mode == MODE_PSP ) + else if (mov->mode == MODE_PSP) put_tag(pb, "MSNV"); - else if ( mov->mode == MODE_MP4 ) + else if (mov->mode == MODE_MP4) put_tag(pb, "isom"); else put_tag(pb, "qt "); - put_be32(pb, 0x200 ); + put_be32(pb, 0x200); - if ( mov->mode == MODE_3GP ) + if (mov->mode == MODE_3GP) put_tag(pb, "3gp4"); - else if ( mov->mode == MODE_3G2 ) + else if (mov->mode == MODE_3G2) put_tag(pb, "3g2a"); - else if ( mov->mode == MODE_PSP ) + else if (mov->mode == MODE_PSP) put_tag(pb, "MSNV"); - else if ( mov->mode == MODE_MP4 ) + else if (mov->mode == MODE_MP4) put_tag(pb, "mp41"); else put_tag(pb, "qt "); @@ -1387,49 +1383,49 @@ static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s) int audio_kbitrate= AudioCodec->bit_rate / 1000; int video_kbitrate= FFMIN(VideoCodec->bit_rate / 1000, 800 - audio_kbitrate); - put_be32(pb, 0x94 ); /* size */ + put_be32(pb, 0x94); /* size */ put_tag(pb, "uuid"); put_tag(pb, "PROF"); - put_be32(pb, 0x21d24fce ); /* 96 bit UUID */ - put_be32(pb, 0xbb88695c ); - put_be32(pb, 0xfac9c740 ); + put_be32(pb, 0x21d24fce); /* 96 bit UUID */ + put_be32(pb, 0xbb88695c); + put_be32(pb, 0xfac9c740); - put_be32(pb, 0x0 ); /* ? */ - put_be32(pb, 0x3 ); /* 3 sections ? */ + put_be32(pb, 0x0); /* ? */ + put_be32(pb, 0x3); /* 3 sections ? */ - put_be32(pb, 0x14 ); /* size */ + put_be32(pb, 0x14); /* size */ put_tag(pb, "FPRF"); - put_be32(pb, 0x0 ); /* ? */ - put_be32(pb, 0x0 ); /* ? */ - put_be32(pb, 0x0 ); /* ? */ + put_be32(pb, 0x0); /* ? */ + put_be32(pb, 0x0); /* ? */ + put_be32(pb, 0x0); /* ? */ - put_be32(pb, 0x2c ); /* size */ + put_be32(pb, 0x2c); /* size */ put_tag(pb, "APRF"); /* audio */ - put_be32(pb, 0x0 ); - put_be32(pb, 0x2 ); /* TrackID */ + put_be32(pb, 0x0); + put_be32(pb, 0x2); /* TrackID */ put_tag(pb, "mp4a"); - put_be32(pb, 0x20f ); - put_be32(pb, 0x0 ); + put_be32(pb, 0x20f); + put_be32(pb, 0x0); put_be32(pb, audio_kbitrate); put_be32(pb, audio_kbitrate); - put_be32(pb, AudioRate ); - put_be32(pb, AudioCodec->channels ); + put_be32(pb, AudioRate); + put_be32(pb, AudioCodec->channels); - put_be32(pb, 0x34 ); /* size */ + put_be32(pb, 0x34); /* size */ put_tag(pb, "VPRF"); /* video */ - put_be32(pb, 0x0 ); - put_be32(pb, 0x1 ); /* TrackID */ + put_be32(pb, 0x0); + put_be32(pb, 0x1); /* TrackID */ if (VideoCodec->codec_id == CODEC_ID_H264) { put_tag(pb, "avc1"); - put_be16(pb, 0x014D ); - put_be16(pb, 0x0015 ); + put_be16(pb, 0x014D); + put_be16(pb, 0x0015); } else { put_tag(pb, "mp4v"); - put_be16(pb, 0x0000 ); - put_be16(pb, 0x0103 ); + put_be16(pb, 0x0000); + put_be16(pb, 0x0103); } - put_be32(pb, 0x0 ); + put_be32(pb, 0x0); put_be32(pb, video_kbitrate); put_be32(pb, video_kbitrate); put_be32(pb, FrameRate); @@ -1441,10 +1437,15 @@ static void mov_write_uuidprof_tag(ByteIOContext *pb, AVFormatContext *s) static int mov_write_header(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; MOVContext *mov = s->priv_data; int i; + if (url_is_streamed(s->pb)) { + av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n"); + return -1; + } + /* Default mode == MP4 */ mov->mode = MODE_MP4; @@ -1455,8 +1456,8 @@ static int mov_write_header(AVFormatContext *s) else if (!strcmp("psp", s->oformat->name)) mov->mode = MODE_PSP; mov_write_ftyp_tag(pb,s); - if ( mov->mode == MODE_PSP ) { - if ( s->nb_streams != 2 ) { + if (mov->mode == MODE_PSP) { + if (s->nb_streams != 2) { av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n"); return -1; } @@ -1471,12 +1472,20 @@ static int mov_write_header(AVFormatContext *s) track->enc = st->codec; track->language = ff_mov_iso639_to_lang(st->language, mov->mode != MODE_MOV); track->mode = mov->mode; + track->tag = mov_find_codec_tag(s, track); + if (!track->tag) { + av_log(s, AV_LOG_ERROR, "track %d: could not find tag for codec\n", i); + return -1; + } if(st->codec->codec_type == CODEC_TYPE_VIDEO){ - track->tag = mov_find_video_codec_tag(s, track); track->timescale = st->codec->time_base.den; av_set_pts_info(st, 64, 1, st->codec->time_base.den); + if (track->mode == MODE_MOV && track->timescale > 100000) + av_log(s, AV_LOG_WARNING, + "WARNING codec timebase is very high. If duration is too long,\n" + "file may not be playable by quicktime. Specify a shorter timebase\n" + "or choose different container.\n"); }else if(st->codec->codec_type == CODEC_TYPE_AUDIO){ - track->tag = mov_find_audio_codec_tag(s, track); track->timescale = st->codec->sample_rate; av_set_pts_info(st, 64, 1, st->codec->sample_rate); if(!st->codec->frame_size){ @@ -1502,13 +1511,13 @@ static int mov_write_header(AVFormatContext *s) static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) { MOVContext *mov = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; MOVTrack *trk = &mov->tracks[pkt->stream_index]; AVCodecContext *enc = trk->enc; unsigned int samplesInChunk = 0; int size= pkt->size; - if (url_is_streamed(&s->pb)) return 0; /* Can't handle that */ + if (url_is_streamed(s->pb)) return 0; /* Can't handle that */ if (!size) return 0; /* Discard 0 sized packets */ if (enc->codec_id == CODEC_ID_AMR_NB) { @@ -1522,7 +1531,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) samplesInChunk++; } if(samplesInChunk > 1){ - av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, inplement a AVParser for it\n"); + av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n"); return -1; } } else if (trk->sampleSize) @@ -1540,9 +1549,18 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (enc->codec_id == CODEC_ID_H264 && trk->vosLen > 0 && *(uint8_t *)trk->vosData != 1) { /* from x264 or from bytestream h264 */ /* nal reformating needed */ - avc_parse_nal_units(&pkt->data, &pkt->size); + int ret = ff_avc_parse_nal_units(pkt->data, &pkt->data, &pkt->size); + if (ret < 0) + return ret; assert(pkt->size); size = pkt->size; + } else if (enc->codec_id == CODEC_ID_DNXHD && !trk->vosLen) { + /* copy frame header to create needed atoms */ + if (size < 640) + return -1; + trk->vosLen = 640; + trk->vosData = av_malloc(trk->vosLen); + memcpy(trk->vosData, pkt->data, 640); } if (!(trk->entry % MOV_INDEX_CLUSTER_SIZE)) { @@ -1579,7 +1597,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) static int mov_write_trailer(AVFormatContext *s) { MOVContext *mov = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int res = 0; int i; @@ -1603,7 +1621,7 @@ static int mov_write_trailer(AVFormatContext *s) for (i=0; i<mov->nb_streams; i++) { av_freep(&mov->tracks[i].cluster); - if( mov->tracks[i].vosLen ) av_free( mov->tracks[i].vosData ); + if(mov->tracks[i].vosLen) av_free(mov->tracks[i].vosData); } @@ -1625,6 +1643,7 @@ AVOutputFormat mov_muxer = { mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER, + .codec_tag = (const AVCodecTag*[]){codec_movvideo_tags, codec_movaudio_tags, 0}, }; #endif #ifdef CONFIG_TGP_MUXER @@ -1640,6 +1659,7 @@ AVOutputFormat tgp_muxer = { mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER, + .codec_tag = (const AVCodecTag*[]){codec_3gp_tags, 0}, }; #endif #ifdef CONFIG_MP4_MUXER @@ -1655,6 +1675,7 @@ AVOutputFormat mp4_muxer = { mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER, + .codec_tag = (const AVCodecTag*[]){ff_mp4_obj_type, 0}, }; #endif #ifdef CONFIG_PSP_MUXER @@ -1670,6 +1691,7 @@ AVOutputFormat psp_muxer = { mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER, + .codec_tag = (const AVCodecTag*[]){ff_mp4_obj_type, 0}, }; #endif #ifdef CONFIG_TG2_MUXER @@ -1685,5 +1707,6 @@ AVOutputFormat tg2_muxer = { mov_write_packet, mov_write_trailer, .flags = AVFMT_GLOBALHEADER, + .codec_tag = (const AVCodecTag*[]){codec_3gp_tags, 0}, }; #endif diff --git a/contrib/ffmpeg/libavformat/mp3.c b/contrib/ffmpeg/libavformat/mp3.c index e86ea14c8..64e0ce285 100644 --- a/contrib/ffmpeg/libavformat/mp3.c +++ b/contrib/ffmpeg/libavformat/mp3.c @@ -20,13 +20,15 @@ */ #include "avformat.h" #include "mpegaudio.h" +#include "avstring.h" +#include "mpegaudiodecheader.h" -#define ID3_HEADER_SIZE 10 -#define ID3_TAG_SIZE 128 +#define ID3v2_HEADER_SIZE 10 +#define ID3v1_TAG_SIZE 128 -#define ID3_GENRE_MAX 125 +#define ID3v1_GENRE_MAX 125 -static const char *id3_genre_str[ID3_GENRE_MAX + 1] = { +static const char *id3v1_genre_str[ID3v1_GENRE_MAX + 1] = { [0] = "Blues", [1] = "Classic Rock", [2] = "Country", @@ -155,8 +157,8 @@ static const char *id3_genre_str[ID3_GENRE_MAX + 1] = { [125] = "Dance Hall", }; -/* buf must be ID3_HEADER_SIZE byte long */ -static int id3_match(const uint8_t *buf) +/* buf must be ID3v2_HEADER_SIZE byte long */ +static int id3v2_match(const uint8_t *buf) { return (buf[0] == 'I' && buf[1] == 'D' && @@ -169,8 +171,152 @@ static int id3_match(const uint8_t *buf) (buf[9] & 0x80) == 0); } -static void id3_get_string(char *str, int str_size, - const uint8_t *buf, int buf_size) +static unsigned int id3v2_get_size(ByteIOContext *s, int len) +{ + int v=0; + while(len--) + v= (v<<7) + (get_byte(s)&0x7F); + return v; +} + +static void id3v2_read_ttag(AVFormatContext *s, int taglen, char *dst, int dstlen) +{ + char *q; + int len; + + if(taglen < 1) + return; + + taglen--; /* account for encoding type byte */ + dstlen--; /* Leave space for zero terminator */ + + switch(get_byte(s->pb)) { /* encoding type */ + + case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */ + q = dst; + while(taglen--) { + uint8_t tmp; + PUT_UTF8(get_byte(s->pb), tmp, if (q - dst < dstlen - 1) *q++ = tmp;) + } + *q = '\0'; + break; + + case 3: /* UTF-8 */ + len = FFMIN(taglen, dstlen); + get_buffer(s->pb, dst, len); + dst[len] = 0; + break; + } +} + +/** + * ID3v2 parser + * + * Handles ID3v2.2, 2.3 and 2.4. + * + */ + +static void id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags) +{ + int isv34, tlen; + uint32_t tag; + offset_t next; + char tmp[16]; + int taghdrlen; + const char *reason; + + switch(version) { + case 2: + if(flags & 0x40) { + reason = "compression"; + goto error; + } + isv34 = 0; + taghdrlen = 6; + break; + + case 3: + case 4: + isv34 = 1; + taghdrlen = 10; + break; + + default: + reason = "version"; + goto error; + } + + if(flags & 0x80) { + reason = "unsynchronization"; + goto error; + } + + if(isv34 && flags & 0x40) /* Extended header present, just skip over it */ + url_fskip(s->pb, id3v2_get_size(s->pb, 4)); + + while(len >= taghdrlen) { + if(isv34) { + tag = get_be32(s->pb); + tlen = id3v2_get_size(s->pb, 4); + get_be16(s->pb); /* flags */ + } else { + tag = get_be24(s->pb); + tlen = id3v2_get_size(s->pb, 3); + } + len -= taghdrlen + tlen; + + if(len < 0) + break; + + next = url_ftell(s->pb) + tlen; + + switch(tag) { + case MKBETAG('T', 'I', 'T', '2'): + case MKBETAG(0, 'T', 'T', '2'): + id3v2_read_ttag(s, tlen, s->title, sizeof(s->title)); + break; + case MKBETAG('T', 'P', 'E', '1'): + case MKBETAG(0, 'T', 'P', '1'): + id3v2_read_ttag(s, tlen, s->author, sizeof(s->author)); + break; + case MKBETAG('T', 'A', 'L', 'B'): + case MKBETAG(0, 'T', 'A', 'L'): + id3v2_read_ttag(s, tlen, s->album, sizeof(s->album)); + break; + case MKBETAG('T', 'C', 'O', 'N'): + case MKBETAG(0, 'T', 'C', 'O'): + id3v2_read_ttag(s, tlen, s->genre, sizeof(s->genre)); + break; + case MKBETAG('T', 'C', 'O', 'P'): + case MKBETAG(0, 'T', 'C', 'R'): + id3v2_read_ttag(s, tlen, s->copyright, sizeof(s->copyright)); + break; + case MKBETAG('T', 'R', 'C', 'K'): + case MKBETAG(0, 'T', 'R', 'K'): + id3v2_read_ttag(s, tlen, tmp, sizeof(tmp)); + s->track = atoi(tmp); + break; + case 0: + /* padding, skip to end */ + url_fskip(s->pb, len); + len = 0; + continue; + } + /* Skip to end of tag */ + url_fseek(s->pb, next, SEEK_SET); + } + + if(version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */ + url_fskip(s->pb, 10); + return; + + error: + av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason); + url_fskip(s->pb, len); +} + +static void id3v1_get_string(char *str, int str_size, + const uint8_t *buf, int buf_size) { int i, c; char *q; @@ -187,8 +333,8 @@ static void id3_get_string(char *str, int str_size, *q = '\0'; } -/* 'buf' must be ID3_TAG_SIZE byte long */ -static int id3_parse_tag(AVFormatContext *s, const uint8_t *buf) +/* 'buf' must be ID3v1_TAG_SIZE byte long */ +static int id3v1_parse_tag(AVFormatContext *s, const uint8_t *buf) { char str[5]; int genre; @@ -197,25 +343,25 @@ static int id3_parse_tag(AVFormatContext *s, const uint8_t *buf) buf[1] == 'A' && buf[2] == 'G')) return -1; - id3_get_string(s->title, sizeof(s->title), buf + 3, 30); - id3_get_string(s->author, sizeof(s->author), buf + 33, 30); - id3_get_string(s->album, sizeof(s->album), buf + 63, 30); - id3_get_string(str, sizeof(str), buf + 93, 4); + id3v1_get_string(s->title, sizeof(s->title), buf + 3, 30); + id3v1_get_string(s->author, sizeof(s->author), buf + 33, 30); + id3v1_get_string(s->album, sizeof(s->album), buf + 63, 30); + id3v1_get_string(str, sizeof(str), buf + 93, 4); s->year = atoi(str); - id3_get_string(s->comment, sizeof(s->comment), buf + 97, 30); + id3v1_get_string(s->comment, sizeof(s->comment), buf + 97, 30); if (buf[125] == 0 && buf[126] != 0) s->track = buf[126]; genre = buf[127]; - if (genre <= ID3_GENRE_MAX) - pstrcpy(s->genre, sizeof(s->genre), id3_genre_str[genre]); + if (genre <= ID3v1_GENRE_MAX) + av_strlcpy(s->genre, id3v1_genre_str[genre], sizeof(s->genre)); return 0; } -static void id3_create_tag(AVFormatContext *s, uint8_t *buf) +static void id3v1_create_tag(AVFormatContext *s, uint8_t *buf) { int v, i; - memset(buf, 0, ID3_TAG_SIZE); /* fail safe */ + memset(buf, 0, ID3v1_TAG_SIZE); /* fail safe */ buf[0] = 'T'; buf[1] = 'A'; buf[2] = 'G'; @@ -234,8 +380,8 @@ static void id3_create_tag(AVFormatContext *s, uint8_t *buf) buf[125] = 0; buf[126] = s->track; } - for(i = 0; i <= ID3_GENRE_MAX; i++) { - if (!strcasecmp(s->genre, id3_genre_str[i])) { + for(i = 0; i <= ID3v1_GENRE_MAX; i++) { + if (!strcasecmp(s->genre, id3v1_genre_str[i])) { buf[127] = i; break; } @@ -246,28 +392,25 @@ static void id3_create_tag(AVFormatContext *s, uint8_t *buf) static int mp3_read_probe(AVProbeData *p) { - int max_frames, first_frames; + int max_frames, first_frames = 0; int fsize, frames, sample_rate; uint32_t header; uint8_t *buf, *buf2, *end; AVCodecContext avctx; - if(p->buf_size < ID3_HEADER_SIZE) - return 0; - - if(id3_match(p->buf)) - return AVPROBE_SCORE_MAX/2+1; // this must be less then mpeg-ps because some retards put id3 tage before mpeg-ps files + if(id3v2_match(p->buf)) + return AVPROBE_SCORE_MAX/2+1; // this must be less than mpeg-ps because some retards put id3v2 tags before mpeg-ps files max_frames = 0; buf = p->buf; - end = buf + FFMIN(4096, p->buf_size - sizeof(uint32_t)); + end = buf + p->buf_size - sizeof(uint32_t); - for(; buf < end; buf++) { + for(; buf < end; buf= buf2+1) { buf2 = buf; for(frames = 0; buf2 < end; frames++) { - header = (buf2[0] << 24) | (buf2[1] << 16) | (buf2[2] << 8) | buf2[3]; - fsize = mpa_decode_header(&avctx, header, &sample_rate); + header = AV_RB32(buf2); + fsize = ff_mpa_decode_header(&avctx, header, &sample_rate); if(fsize < 0) break; buf2 += fsize; @@ -277,55 +420,109 @@ static int mp3_read_probe(AVProbeData *p) first_frames= frames; } if (first_frames>=3) return AVPROBE_SCORE_MAX/2+1; + else if(max_frames>500)return AVPROBE_SCORE_MAX/2; else if(max_frames>=3) return AVPROBE_SCORE_MAX/4; else if(max_frames>=1) return 1; else return 0; } +/** + * Try to find Xing/Info/VBRI tags and compute duration from info therein + */ +static void mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, offset_t base) +{ + uint32_t v, spf; + int frames = -1; /* Total number of frames in file */ + const offset_t xing_offtbl[2][2] = {{32, 17}, {17,9}}; + MPADecodeContext c; + + v = get_be32(s->pb); + if(ff_mpa_check_header(v) < 0) + return; + + ff_mpegaudio_decode_header(&c, v); + if(c.layer != 3) + return; + + /* Check for Xing / Info tag */ + url_fseek(s->pb, xing_offtbl[c.lsf == 1][c.nb_channels == 1], SEEK_CUR); + v = get_be32(s->pb); + if(v == MKBETAG('X', 'i', 'n', 'g') || v == MKBETAG('I', 'n', 'f', 'o')) { + v = get_be32(s->pb); + if(v & 0x1) + frames = get_be32(s->pb); + } + + /* Check for VBRI tag (always 32 bytes after end of mpegaudio header) */ + url_fseek(s->pb, base + 4 + 32, SEEK_SET); + v = get_be32(s->pb); + if(v == MKBETAG('V', 'B', 'R', 'I')) { + /* Check tag version */ + if(get_be16(s->pb) == 1) { + /* skip delay, quality and total bytes */ + url_fseek(s->pb, 8, SEEK_CUR); + frames = get_be32(s->pb); + } + } + + if(frames < 0) + return; + + spf = c.lsf ? 576 : 1152; /* Samples per frame, layer 3 */ + st->duration = av_rescale_q(frames, (AVRational){spf, c.sample_rate}, + st->time_base); +} + static int mp3_read_header(AVFormatContext *s, AVFormatParameters *ap) { AVStream *st; - uint8_t buf[ID3_TAG_SIZE]; + uint8_t buf[ID3v1_TAG_SIZE]; int len, ret, filesize; + offset_t off; st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_MP3; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; + st->start_time = 0; /* try to get the TAG */ - if (!url_is_streamed(&s->pb)) { + if (!url_is_streamed(s->pb)) { /* XXX: change that */ - filesize = url_fsize(&s->pb); + filesize = url_fsize(s->pb); if (filesize > 128) { - url_fseek(&s->pb, filesize - 128, SEEK_SET); - ret = get_buffer(&s->pb, buf, ID3_TAG_SIZE); - if (ret == ID3_TAG_SIZE) { - id3_parse_tag(s, buf); + url_fseek(s->pb, filesize - 128, SEEK_SET); + ret = get_buffer(s->pb, buf, ID3v1_TAG_SIZE); + if (ret == ID3v1_TAG_SIZE) { + id3v1_parse_tag(s, buf); } - url_fseek(&s->pb, 0, SEEK_SET); + url_fseek(s->pb, 0, SEEK_SET); } } - /* if ID3 header found, skip it */ - ret = get_buffer(&s->pb, buf, ID3_HEADER_SIZE); - if (ret != ID3_HEADER_SIZE) + /* if ID3v2 header found, skip it */ + ret = get_buffer(s->pb, buf, ID3v2_HEADER_SIZE); + if (ret != ID3v2_HEADER_SIZE) return -1; - if (id3_match(buf)) { - /* skip ID3 header */ + if (id3v2_match(buf)) { + /* parse ID3v2 header */ len = ((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f); - url_fskip(&s->pb, len); + id3v2_parse(s, len, buf[3], buf[5]); } else { - url_fseek(&s->pb, 0, SEEK_SET); + url_fseek(s->pb, 0, SEEK_SET); } + off = url_ftell(s->pb); + mp3_parse_vbr_tags(s, st, off); + url_fseek(s->pb, off, SEEK_SET); + /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -339,11 +536,11 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt) size= MP3_PACKET_SIZE; - ret= av_get_packet(&s->pb, pkt, size); + ret= av_get_packet(s->pb, pkt, size); pkt->stream_index = 0; if (ret <= 0) { - return AVERROR_IO; + return AVERROR(EIO); } /* note: we need to modify the packet size here to handle the last packet */ @@ -358,27 +555,88 @@ static int mp3_read_close(AVFormatContext *s) #ifdef CONFIG_MUXERS /* simple formats */ + +static void id3v2_put_size(AVFormatContext *s, int size) +{ + put_byte(s->pb, size >> 21 & 0x7f); + put_byte(s->pb, size >> 14 & 0x7f); + put_byte(s->pb, size >> 7 & 0x7f); + put_byte(s->pb, size & 0x7f); +} + +static void id3v2_put_ttag(AVFormatContext *s, const char *string, uint32_t tag) +{ + int len = strlen(string); + put_be32(s->pb, tag); + id3v2_put_size(s, len + 1); + put_be16(s->pb, 0); + put_byte(s->pb, 3); /* UTF-8 */ + put_buffer(s->pb, string, len); +} + + +/** + * Write an ID3v2.4 header at beginning of stream + */ + static int mp3_write_header(struct AVFormatContext *s) { + int totlen = 0; + char tracktxt[10]; + char yeartxt[10]; + + if(s->track) + snprintf(tracktxt, sizeof(tracktxt), "%d", s->track); + if(s->year) + snprintf( yeartxt, sizeof(yeartxt) , "%d", s->year ); + + if(s->title[0]) totlen += 11 + strlen(s->title); + if(s->author[0]) totlen += 11 + strlen(s->author); + if(s->album[0]) totlen += 11 + strlen(s->album); + if(s->genre[0]) totlen += 11 + strlen(s->genre); + if(s->copyright[0]) totlen += 11 + strlen(s->copyright); + if(s->track) totlen += 11 + strlen(tracktxt); + if(s->year) totlen += 11 + strlen(yeartxt); + if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) + totlen += strlen(LIBAVFORMAT_IDENT) + 11; + + if(totlen == 0) + return 0; + + put_be32(s->pb, MKBETAG('I', 'D', '3', 0x04)); /* ID3v2.4 */ + put_byte(s->pb, 0); + put_byte(s->pb, 0); /* flags */ + + id3v2_put_size(s, totlen); + + if(s->title[0]) id3v2_put_ttag(s, s->title, MKBETAG('T', 'I', 'T', '2')); + if(s->author[0]) id3v2_put_ttag(s, s->author, MKBETAG('T', 'P', 'E', '1')); + if(s->album[0]) id3v2_put_ttag(s, s->album, MKBETAG('T', 'A', 'L', 'B')); + if(s->genre[0]) id3v2_put_ttag(s, s->genre, MKBETAG('T', 'C', 'O', 'N')); + if(s->copyright[0]) id3v2_put_ttag(s, s->copyright, MKBETAG('T', 'C', 'O', 'P')); + if(s->track) id3v2_put_ttag(s, tracktxt, MKBETAG('T', 'R', 'C', 'K')); + if(s->year) id3v2_put_ttag(s, yeartxt, MKBETAG('T', 'Y', 'E', 'R')); + if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) + id3v2_put_ttag(s, LIBAVFORMAT_IDENT, MKBETAG('T', 'E', 'N', 'C')); return 0; } static int mp3_write_packet(struct AVFormatContext *s, AVPacket *pkt) { - put_buffer(&s->pb, pkt->data, pkt->size); - put_flush_packet(&s->pb); + put_buffer(s->pb, pkt->data, pkt->size); + put_flush_packet(s->pb); return 0; } static int mp3_write_trailer(struct AVFormatContext *s) { - uint8_t buf[ID3_TAG_SIZE]; + uint8_t buf[ID3v1_TAG_SIZE]; - /* write the id3 header */ + /* write the id3v1 tag */ if (s->title[0] != '\0') { - id3_create_tag(s, buf); - put_buffer(&s->pb, buf, ID3_TAG_SIZE); - put_flush_packet(&s->pb); + id3v1_create_tag(s, buf); + put_buffer(s->pb, buf, ID3v1_TAG_SIZE); + put_flush_packet(s->pb); } return 0; } @@ -410,7 +668,7 @@ AVOutputFormat mp2_muxer = { 0, CODEC_ID_MP2, 0, - mp3_write_header, + NULL, mp3_write_packet, mp3_write_trailer, }; diff --git a/contrib/ffmpeg/libavformat/mpc.c b/contrib/ffmpeg/libavformat/mpc.c index a28efb16d..8e6c573df 100644 --- a/contrib/ffmpeg/libavformat/mpc.c +++ b/contrib/ffmpeg/libavformat/mpc.c @@ -16,7 +16,7 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" #include "bitstream.h" @@ -42,8 +42,6 @@ typedef struct { static int mpc_probe(AVProbeData *p) { const uint8_t *d = p->buf; - if (p->buf_size < 32) - return 0; if (d[0] == 'M' && d[1] == 'P' && d[2] == '+' && (d[3] == 0x17 || d[3] == 0x7)) return AVPROBE_SCORE_MAX; if (d[0] == 'I' && d[1] == 'D' && d[2] == '3') @@ -57,31 +55,31 @@ static int mpc_read_header(AVFormatContext *s, AVFormatParameters *ap) AVStream *st; int t; - t = get_le24(&s->pb); + t = get_le24(s->pb); if(t != MKTAG('M', 'P', '+', 0)){ if(t != MKTAG('I', 'D', '3', 0)){ av_log(s, AV_LOG_ERROR, "Not a Musepack file\n"); return -1; } /* skip ID3 tags and try again */ - url_fskip(&s->pb, 3); - t = get_byte(&s->pb) << 21; - t |= get_byte(&s->pb) << 14; - t |= get_byte(&s->pb) << 7; - t |= get_byte(&s->pb); + url_fskip(s->pb, 3); + t = get_byte(s->pb) << 21; + t |= get_byte(s->pb) << 14; + t |= get_byte(s->pb) << 7; + t |= get_byte(s->pb); av_log(s, AV_LOG_DEBUG, "Skipping %d(%X) bytes of ID3 data\n", t, t); - url_fskip(&s->pb, t); - if(get_le24(&s->pb) != MKTAG('M', 'P', '+', 0)){ + url_fskip(s->pb, t); + if(get_le24(s->pb) != MKTAG('M', 'P', '+', 0)){ av_log(s, AV_LOG_ERROR, "Not a Musepack file\n"); return -1; } } - c->ver = get_byte(&s->pb); + c->ver = get_byte(s->pb); if(c->ver != 0x07 && c->ver != 0x17){ av_log(s, AV_LOG_ERROR, "Can demux Musepack SV7, got version %02X\n", c->ver); return -1; } - c->fcount = get_le32(&s->pb); + c->fcount = get_le32(s->pb); if((int64_t)c->fcount * sizeof(MPCFrame) >= UINT_MAX){ av_log(s, AV_LOG_ERROR, "Too many frames, seeking is not possible\n"); return -1; @@ -94,7 +92,7 @@ static int mpc_read_header(AVFormatContext *s, AVFormatParameters *ap) st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_MUSEPACK7; st->codec->channels = 2; @@ -102,7 +100,7 @@ static int mpc_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->extradata_size = 16; st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(&s->pb, st->codec->extradata, 16); + get_buffer(s->pb, st->codec->extradata, 16); st->codec->sample_rate = mpc_rate[st->codec->extradata[2] & 3]; av_set_pts_info(st, 32, MPC_FRAMESIZE, st->codec->sample_rate); /* scan for seekpoints */ @@ -122,22 +120,22 @@ static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt) return -1; if(c->curframe != c->lastframe + 1){ - url_fseek(&s->pb, c->frames[c->curframe].pos, SEEK_SET); + url_fseek(s->pb, c->frames[c->curframe].pos, SEEK_SET); c->curbits = c->frames[c->curframe].skip; } c->lastframe = c->curframe; c->curframe++; curbits = c->curbits; - pos = url_ftell(&s->pb); - tmp = get_le32(&s->pb); + pos = url_ftell(s->pb); + tmp = get_le32(s->pb); if(curbits <= 12){ size2 = (tmp >> (12 - curbits)) & 0xFFFFF; }else{ - tmp = (tmp << 32) | get_le32(&s->pb); + tmp = (tmp << 32) | get_le32(s->pb); size2 = (tmp >> (44 - curbits)) & 0xFFFFF; } curbits += 20; - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); size = ((size2 + curbits + 31) & ~31) >> 3; if(cur == c->frames_noted){ @@ -150,19 +148,19 @@ static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt) c->curbits = (curbits + size2) & 0x1F; if (av_new_packet(pkt, size) < 0) - return AVERROR_IO; + return AVERROR(EIO); pkt->data[0] = curbits; pkt->data[1] = (c->curframe > c->fcount); pkt->stream_index = 0; pkt->pts = cur; - ret = get_buffer(&s->pb, pkt->data + 4, size); + ret = get_buffer(s->pb, pkt->data + 4, size); if(c->curbits) - url_fseek(&s->pb, -4, SEEK_CUR); + url_fseek(s->pb, -4, SEEK_CUR); if(ret < size){ av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } pkt->size = ret + 4; diff --git a/contrib/ffmpeg/libavformat/mpc8.c b/contrib/ffmpeg/libavformat/mpc8.c new file mode 100644 index 000000000..879c7d236 --- /dev/null +++ b/contrib/ffmpeg/libavformat/mpc8.c @@ -0,0 +1,244 @@ +/* + * Musepack SV8 demuxer + * Copyright (c) 2007 Konstantin Shishkov + * + * 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 "bitstream.h" +#include "unary.h" + +/// Two-byte MPC tag +#define MKMPCTAG(a, b) (a | (b << 8)) + +#define TAG_MPCK MKTAG('M','P','C','K') + +/// Reserved MPC tags +enum MPCPacketTags{ + TAG_STREAMHDR = MKMPCTAG('S','H'), + TAG_STREAMEND = MKMPCTAG('S','E'), + + TAG_AUDIOPACKET = MKMPCTAG('A','P'), + + TAG_SEEKTBLOFF = MKMPCTAG('S','O'), + TAG_SEEKTABLE = MKMPCTAG('S','T'), + + TAG_REPLAYGAIN = MKMPCTAG('R','G'), + TAG_ENCINFO = MKMPCTAG('E','I'), +}; + +static const int mpc8_rate[8] = { 44100, 48000, 37800, 32000, -1, -1, -1, -1 }; + +typedef struct { + int ver; + int frame; + int64_t header_pos; + int64_t samples; +} MPCContext; + +static int mpc8_probe(AVProbeData *p) +{ + if (AV_RL32(p->buf) == TAG_MPCK) + return AVPROBE_SCORE_MAX; + return 0; +} + +static inline int64_t gb_get_v(GetBitContext *gb) +{ + int64_t v = 0; + int bits = 0; + while(get_bits1(gb) && bits < 64-7){ + v <<= 7; + v |= get_bits(gb, 7); + bits += 7; + } + v <<= 7; + v |= get_bits(gb, 7); + + return v; +} + +static void mpc8_get_chunk_header(ByteIOContext *pb, int *tag, int64_t *size) +{ + int64_t pos; + pos = url_ftell(pb); + *tag = get_le16(pb); + *size = ff_get_v(pb); + *size -= url_ftell(pb) - pos; +} + +static void mpc8_parse_seektable(AVFormatContext *s, int64_t off) +{ + MPCContext *c = s->priv_data; + int tag; + int64_t size, pos, ppos[2]; + uint8_t *buf; + int i, t, seekd; + GetBitContext gb; + + url_fseek(s->pb, off, SEEK_SET); + mpc8_get_chunk_header(s->pb, &tag, &size); + if(tag != TAG_SEEKTABLE){ + av_log(s, AV_LOG_ERROR, "No seek table at given position\n"); + return; + } + if(!(buf = av_malloc(size))) + return; + get_buffer(s->pb, buf, size); + init_get_bits(&gb, buf, size * 8); + size = gb_get_v(&gb); + if(size > UINT_MAX/4 || size > c->samples/1152){ + av_log(s, AV_LOG_ERROR, "Seek table is too big\n"); + return; + } + seekd = get_bits(&gb, 4); + for(i = 0; i < 2; i++){ + pos = gb_get_v(&gb) + c->header_pos; + ppos[1 - i] = pos; + av_add_index_entry(s->streams[0], pos, i, 0, 0, AVINDEX_KEYFRAME); + } + for(; i < size; i++){ + t = get_unary(&gb, 1, 33) << 12; + t += get_bits(&gb, 12); + if(t & 1) + t = -(t & ~1); + pos = (t >> 1) + ppos[0]*2 - ppos[1]; + av_add_index_entry(s->streams[0], pos, i << seekd, 0, 0, AVINDEX_KEYFRAME); + ppos[1] = ppos[0]; + ppos[0] = pos; + } + av_free(buf); +} + +static void mpc8_handle_chunk(AVFormatContext *s, int tag, int64_t chunk_pos, int64_t size) +{ + ByteIOContext *pb = s->pb; + int64_t pos, off; + + switch(tag){ + case TAG_SEEKTBLOFF: + pos = url_ftell(pb) + size; + off = ff_get_v(pb); + mpc8_parse_seektable(s, chunk_pos + off); + url_fseek(pb, pos, SEEK_SET); + break; + default: + url_fskip(pb, size); + } +} + +static int mpc8_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + MPCContext *c = s->priv_data; + ByteIOContext *pb = s->pb; + AVStream *st; + int tag = 0; + int64_t size, pos; + + c->header_pos = url_ftell(pb); + if(get_le32(pb) != TAG_MPCK){ + av_log(s, AV_LOG_ERROR, "Not a Musepack8 file\n"); + return -1; + } + + while(!url_feof(pb)){ + pos = url_ftell(pb); + mpc8_get_chunk_header(pb, &tag, &size); + if(tag == TAG_STREAMHDR) + break; + mpc8_handle_chunk(s, tag, pos, size); + } + if(tag != TAG_STREAMHDR){ + av_log(s, AV_LOG_ERROR, "Stream header not found\n"); + return -1; + } + pos = url_ftell(pb); + url_fskip(pb, 4); //CRC + c->ver = get_byte(pb); + if(c->ver != 8){ + av_log(s, AV_LOG_ERROR, "Unknown stream version %d\n", c->ver); + return -1; + } + c->samples = ff_get_v(pb); + ff_get_v(pb); //silence samples at the beginning + + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_MUSEPACK8; + st->codec->bits_per_sample = 16; + + st->codec->extradata_size = 2; + st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + + st->codec->channels = (st->codec->extradata[1] >> 4) + 1; + st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5]; + av_set_pts_info(st, 32, 1152 << (st->codec->extradata[1]&3)*2, st->codec->sample_rate); + st->duration = c->samples / (1152 << (st->codec->extradata[1]&3)*2); + size -= url_ftell(pb) - pos; + + return 0; +} + +static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + MPCContext *c = s->priv_data; + int tag; + int64_t pos, size; + + while(!url_feof(s->pb)){ + pos = url_ftell(s->pb); + mpc8_get_chunk_header(s->pb, &tag, &size); + if(tag == TAG_AUDIOPACKET){ + if(av_get_packet(s->pb, pkt, size) < 0) + return AVERROR(ENOMEM); + pkt->stream_index = 0; + pkt->pts = c->frame; + return 0; + } + if(tag == TAG_STREAMEND) + return AVERROR(EIO); + mpc8_handle_chunk(s, tag, pos, size); + } + return 0; +} + +static int mpc8_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +{ + AVStream *st = s->streams[stream_index]; + MPCContext *c = s->priv_data; + int index = av_index_search_timestamp(st, timestamp, flags); + + if(index < 0) return -1; + url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); + c->frame = st->index_entries[index].timestamp; + return 0; +} + + +AVInputFormat mpc8_demuxer = { + "mpc8", + "musepack8", + sizeof(MPCContext), + mpc8_probe, + mpc8_read_header, + mpc8_read_packet, + NULL, + mpc8_read_seek, +}; diff --git a/contrib/ffmpeg/libavformat/mpeg.c b/contrib/ffmpeg/libavformat/mpeg.c index ae47fa60a..97b2a637a 100644 --- a/contrib/ffmpeg/libavformat/mpeg.c +++ b/contrib/ffmpeg/libavformat/mpeg.c @@ -1,5 +1,5 @@ /* - * MPEG1/2 muxer and demuxer + * MPEG1/2 demuxer * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. * * This file is part of FFmpeg. @@ -18,1290 +18,72 @@ * 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 "bitstream.h" -#include "fifo.h" +#include "mpeg.h" -#define MAX_PAYLOAD_SIZE 4096 //#define DEBUG_SEEK #undef NDEBUG #include <assert.h> -typedef struct PacketDesc { - int64_t pts; - int64_t dts; - int size; - int unwritten_size; - int flags; - struct PacketDesc *next; -} PacketDesc; - -typedef struct { - AVFifoBuffer fifo; - uint8_t id; - int max_buffer_size; /* in bytes */ - int buffer_index; - PacketDesc *predecode_packet; - PacketDesc *premux_packet; - PacketDesc **next_packet; - int packet_number; - uint8_t lpcm_header[3]; - int lpcm_align; - int bytes_to_iframe; - int align_iframe; - int64_t vobu_start_pts; -} StreamInfo; - -typedef struct { - int packet_size; /* required packet size */ - int packet_number; - int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */ - int system_header_freq; - int system_header_size; - int mux_rate; /* bitrate in units of 50 bytes/s */ - /* stream info */ - int audio_bound; - int video_bound; - int is_mpeg2; - int is_vcd; - int is_svcd; - int is_dvd; - int64_t last_scr; /* current system clock */ - - double vcd_padding_bitrate; //FIXME floats - int64_t vcd_padding_bytes_written; - -} MpegMuxContext; - -#define PACK_START_CODE ((unsigned int)0x000001ba) -#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb) -#define SEQUENCE_END_CODE ((unsigned int)0x000001b7) -#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00) -#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100) -#define ISO_11172_END_CODE ((unsigned int)0x000001b9) - -/* mpeg2 */ -#define PROGRAM_STREAM_MAP 0x1bc -#define PRIVATE_STREAM_1 0x1bd -#define PADDING_STREAM 0x1be -#define PRIVATE_STREAM_2 0x1bf - - -#define AUDIO_ID 0xc0 -#define VIDEO_ID 0xe0 -#define AC3_ID 0x80 -#define DTS_ID 0x8a -#define LPCM_ID 0xa0 -#define SUB_ID 0x20 - -#define STREAM_TYPE_VIDEO_MPEG1 0x01 -#define STREAM_TYPE_VIDEO_MPEG2 0x02 -#define STREAM_TYPE_AUDIO_MPEG1 0x03 -#define STREAM_TYPE_AUDIO_MPEG2 0x04 -#define STREAM_TYPE_PRIVATE_SECTION 0x05 -#define STREAM_TYPE_PRIVATE_DATA 0x06 -#define STREAM_TYPE_AUDIO_AAC 0x0f -#define STREAM_TYPE_VIDEO_MPEG4 0x10 -#define STREAM_TYPE_VIDEO_H264 0x1b - -#define STREAM_TYPE_AUDIO_AC3 0x81 -#define STREAM_TYPE_AUDIO_DTS 0x8a - -static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 }; - -#ifdef CONFIG_MUXERS -AVOutputFormat mpeg1system_muxer; -AVOutputFormat mpeg1vcd_muxer; -AVOutputFormat mpeg2vob_muxer; -AVOutputFormat mpeg2svcd_muxer; -AVOutputFormat mpeg2dvd_muxer; - -static int put_pack_header(AVFormatContext *ctx, - uint8_t *buf, int64_t timestamp) -{ - MpegMuxContext *s = ctx->priv_data; - PutBitContext pb; - - init_put_bits(&pb, buf, 128); - - put_bits(&pb, 32, PACK_START_CODE); - if (s->is_mpeg2) { - put_bits(&pb, 2, 0x1); - } else { - put_bits(&pb, 4, 0x2); - } - put_bits(&pb, 3, (uint32_t)((timestamp >> 30) & 0x07)); - put_bits(&pb, 1, 1); - put_bits(&pb, 15, (uint32_t)((timestamp >> 15) & 0x7fff)); - put_bits(&pb, 1, 1); - put_bits(&pb, 15, (uint32_t)((timestamp) & 0x7fff)); - put_bits(&pb, 1, 1); - if (s->is_mpeg2) { - /* clock extension */ - put_bits(&pb, 9, 0); - } - put_bits(&pb, 1, 1); - put_bits(&pb, 22, s->mux_rate); - put_bits(&pb, 1, 1); - if (s->is_mpeg2) { - put_bits(&pb, 1, 1); - put_bits(&pb, 5, 0x1f); /* reserved */ - put_bits(&pb, 3, 0); /* stuffing length */ - } - flush_put_bits(&pb); - return pbBufPtr(&pb) - pb.buf; -} - -static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_stream_id) -{ - MpegMuxContext *s = ctx->priv_data; - int size, i, private_stream_coded, id; - PutBitContext pb; - - init_put_bits(&pb, buf, 128); - - put_bits(&pb, 32, SYSTEM_HEADER_START_CODE); - put_bits(&pb, 16, 0); - put_bits(&pb, 1, 1); - - put_bits(&pb, 22, s->mux_rate); /* maximum bit rate of the multiplexed stream */ - put_bits(&pb, 1, 1); /* marker */ - if (s->is_vcd && only_for_stream_id==VIDEO_ID) { - /* This header applies only to the video stream (see VCD standard p. IV-7)*/ - put_bits(&pb, 6, 0); - } else - put_bits(&pb, 6, s->audio_bound); - - if (s->is_vcd) { - /* see VCD standard, p. IV-7*/ - put_bits(&pb, 1, 0); - put_bits(&pb, 1, 1); - } else { - put_bits(&pb, 1, 0); /* variable bitrate*/ - put_bits(&pb, 1, 0); /* non constrainted bit stream */ - } - - if (s->is_vcd || s->is_dvd) { - /* see VCD standard p IV-7 */ - put_bits(&pb, 1, 1); /* audio locked */ - put_bits(&pb, 1, 1); /* video locked */ - } else { - put_bits(&pb, 1, 0); /* audio locked */ - put_bits(&pb, 1, 0); /* video locked */ - } - - put_bits(&pb, 1, 1); /* marker */ - - if (s->is_vcd && only_for_stream_id==AUDIO_ID) { - /* This header applies only to the audio stream (see VCD standard p. IV-7)*/ - put_bits(&pb, 5, 0); - } else - put_bits(&pb, 5, s->video_bound); - - if (s->is_dvd) { - put_bits(&pb, 1, 0); /* packet_rate_restriction_flag */ - put_bits(&pb, 7, 0x7f); /* reserved byte */ - } else - put_bits(&pb, 8, 0xff); /* reserved byte */ - - /* DVD-Video Stream_bound entries - id (0xB9) video, maximum P-STD for stream 0xE0. (P-STD_buffer_bound_scale = 1) - id (0xB8) audio, maximum P-STD for any MPEG audio (0xC0 to 0xC7) streams. If there are none set to 4096 (32x128). (P-STD_buffer_bound_scale = 0) - id (0xBD) private stream 1 (audio other than MPEG and subpictures). (P-STD_buffer_bound_scale = 1) - id (0xBF) private stream 2, NAV packs, set to 2x1024. */ - if (s->is_dvd) { - - int P_STD_max_video = 0; - int P_STD_max_mpeg_audio = 0; - int P_STD_max_mpeg_PS1 = 0; - - for(i=0;i<ctx->nb_streams;i++) { - StreamInfo *stream = ctx->streams[i]->priv_data; - - id = stream->id; - if (id == 0xbd && stream->max_buffer_size > P_STD_max_mpeg_PS1) { - P_STD_max_mpeg_PS1 = stream->max_buffer_size; - } else if (id >= 0xc0 && id <= 0xc7 && stream->max_buffer_size > P_STD_max_mpeg_audio) { - P_STD_max_mpeg_audio = stream->max_buffer_size; - } else if (id == 0xe0 && stream->max_buffer_size > P_STD_max_video) { - P_STD_max_video = stream->max_buffer_size; - } - } - - /* video */ - put_bits(&pb, 8, 0xb9); /* stream ID */ - put_bits(&pb, 2, 3); - put_bits(&pb, 1, 1); - put_bits(&pb, 13, P_STD_max_video / 1024); - - /* audio */ - if (P_STD_max_mpeg_audio == 0) - P_STD_max_mpeg_audio = 4096; - put_bits(&pb, 8, 0xb8); /* stream ID */ - put_bits(&pb, 2, 3); - put_bits(&pb, 1, 0); - put_bits(&pb, 13, P_STD_max_mpeg_audio / 128); - - /* private stream 1 */ - put_bits(&pb, 8, 0xbd); /* stream ID */ - put_bits(&pb, 2, 3); - put_bits(&pb, 1, 0); - put_bits(&pb, 13, P_STD_max_mpeg_PS1 / 128); - - /* private stream 2 */ - put_bits(&pb, 8, 0xbf); /* stream ID */ - put_bits(&pb, 2, 3); - put_bits(&pb, 1, 1); - put_bits(&pb, 13, 2); - } - else { - /* audio stream info */ - private_stream_coded = 0; - for(i=0;i<ctx->nb_streams;i++) { - StreamInfo *stream = ctx->streams[i]->priv_data; - - - /* For VCDs, only include the stream info for the stream - that the pack which contains this system belongs to. - (see VCD standard p. IV-7) */ - if ( !s->is_vcd || stream->id==only_for_stream_id - || only_for_stream_id==0) { - - id = stream->id; - if (id < 0xc0) { - /* special case for private streams (AC3 use that) */ - if (private_stream_coded) - continue; - private_stream_coded = 1; - id = 0xbd; - } - put_bits(&pb, 8, id); /* stream ID */ - put_bits(&pb, 2, 3); - if (id < 0xe0) { - /* audio */ - put_bits(&pb, 1, 0); - put_bits(&pb, 13, stream->max_buffer_size / 128); - } else { - /* video */ - put_bits(&pb, 1, 1); - put_bits(&pb, 13, stream->max_buffer_size / 1024); - } - } - } - } - - flush_put_bits(&pb); - size = pbBufPtr(&pb) - pb.buf; - /* patch packet size */ - buf[4] = (size - 6) >> 8; - buf[5] = (size - 6) & 0xff; - - return size; -} - -static int get_system_header_size(AVFormatContext *ctx) -{ - int buf_index, i, private_stream_coded; - StreamInfo *stream; - MpegMuxContext *s = ctx->priv_data; - - if (s->is_dvd) - return 18; // DVD-Video system headers are 18 bytes fixed length. - - buf_index = 12; - private_stream_coded = 0; - for(i=0;i<ctx->nb_streams;i++) { - stream = ctx->streams[i]->priv_data; - if (stream->id < 0xc0) { - if (private_stream_coded) - continue; - private_stream_coded = 1; - } - buf_index += 3; - } - return buf_index; -} - -static int mpeg_mux_init(AVFormatContext *ctx) -{ - MpegMuxContext *s = ctx->priv_data; - int bitrate, i, mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id, j; - AVStream *st; - StreamInfo *stream; - int audio_bitrate; - int video_bitrate; - - s->packet_number = 0; - s->is_vcd = (ctx->oformat == &mpeg1vcd_muxer); - s->is_svcd = (ctx->oformat == &mpeg2svcd_muxer); - s->is_mpeg2 = (ctx->oformat == &mpeg2vob_muxer || ctx->oformat == &mpeg2svcd_muxer || ctx->oformat == &mpeg2dvd_muxer); - s->is_dvd = (ctx->oformat == &mpeg2dvd_muxer); - - if(ctx->packet_size) - s->packet_size = ctx->packet_size; - else - s->packet_size = 2048; - - s->vcd_padding_bytes_written = 0; - s->vcd_padding_bitrate=0; - - s->audio_bound = 0; - s->video_bound = 0; - mpa_id = AUDIO_ID; - ac3_id = AC3_ID; - dts_id = DTS_ID; - mpv_id = VIDEO_ID; - mps_id = SUB_ID; - lpcm_id = LPCM_ID; - for(i=0;i<ctx->nb_streams;i++) { - st = ctx->streams[i]; - stream = av_mallocz(sizeof(StreamInfo)); - if (!stream) - goto fail; - st->priv_data = stream; - - av_set_pts_info(st, 64, 1, 90000); - - switch(st->codec->codec_type) { - case CODEC_TYPE_AUDIO: - if (st->codec->codec_id == CODEC_ID_AC3) { - stream->id = ac3_id++; - } else if (st->codec->codec_id == CODEC_ID_DTS) { - stream->id = dts_id++; - } else if (st->codec->codec_id == CODEC_ID_PCM_S16BE) { - stream->id = lpcm_id++; - for(j = 0; j < 4; j++) { - if (lpcm_freq_tab[j] == st->codec->sample_rate) - break; - } - if (j == 4) - goto fail; - if (st->codec->channels > 8) - return -1; - stream->lpcm_header[0] = 0x0c; - stream->lpcm_header[1] = (st->codec->channels - 1) | (j << 4); - stream->lpcm_header[2] = 0x80; - stream->lpcm_align = st->codec->channels * 2; - } else { - stream->id = mpa_id++; - } - - /* This value HAS to be used for VCD (see VCD standard, p. IV-7). - Right now it is also used for everything else.*/ - stream->max_buffer_size = 4 * 1024; - s->audio_bound++; - break; - case CODEC_TYPE_VIDEO: - stream->id = mpv_id++; - if (st->codec->rc_buffer_size) - stream->max_buffer_size = 6*1024 + st->codec->rc_buffer_size/8; - else - stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default -#if 0 - /* see VCD standard, p. IV-7*/ - stream->max_buffer_size = 46 * 1024; - else - /* This value HAS to be used for SVCD (see SVCD standard, p. 26 V.2.3.2). - Right now it is also used for everything else.*/ - stream->max_buffer_size = 230 * 1024; -#endif - s->video_bound++; - break; - case CODEC_TYPE_SUBTITLE: - stream->id = mps_id++; - stream->max_buffer_size = 16 * 1024; - break; - default: - return -1; - } - av_fifo_init(&stream->fifo, 16); - } - bitrate = 0; - audio_bitrate = 0; - video_bitrate = 0; - for(i=0;i<ctx->nb_streams;i++) { - int codec_rate; - st = ctx->streams[i]; - stream = (StreamInfo*) st->priv_data; - - if(st->codec->rc_max_rate || stream->id==VIDEO_ID) - codec_rate= st->codec->rc_max_rate; - else - codec_rate= st->codec->bit_rate; - - if(!codec_rate) - codec_rate= (1<<21)*8*50/ctx->nb_streams; - - bitrate += codec_rate; - - if (stream->id==AUDIO_ID) - audio_bitrate += codec_rate; - else if (stream->id==VIDEO_ID) - video_bitrate += codec_rate; - } - - if(ctx->mux_rate){ - s->mux_rate= (ctx->mux_rate + (8 * 50) - 1) / (8 * 50); - } else { - /* we increase slightly the bitrate to take into account the - headers. XXX: compute it exactly */ - bitrate += bitrate*5/100; - bitrate += 10000; - s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); - } - - if (s->is_vcd) { - double overhead_rate; - - /* The VCD standard mandates that the mux_rate field is 3528 - (see standard p. IV-6). - The value is actually "wrong", i.e. if you calculate - it using the normal formula and the 75 sectors per second transfer - rate you get a different value because the real pack size is 2324, - not 2352. But the standard explicitly specifies that the mux_rate - field in the header must have this value.*/ -// s->mux_rate=2352 * 75 / 50; /* = 3528*/ - - /* The VCD standard states that the muxed stream must be - exactly 75 packs / second (the data rate of a single speed cdrom). - Since the video bitrate (probably 1150000 bits/sec) will be below - the theoretical maximum we have to add some padding packets - to make up for the lower data rate. - (cf. VCD standard p. IV-6 )*/ - - /* Add the header overhead to the data rate. - 2279 data bytes per audio pack, 2294 data bytes per video pack*/ - overhead_rate = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279); - overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294); - overhead_rate *= 8; - - /* Add padding so that the full bitrate is 2324*75 bytes/sec */ - s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate); - } - - if (s->is_vcd || s->is_mpeg2) - /* every packet */ - s->pack_header_freq = 1; - else - /* every 2 seconds */ - s->pack_header_freq = 2 * bitrate / s->packet_size / 8; - - /* the above seems to make pack_header_freq zero sometimes */ - if (s->pack_header_freq == 0) - s->pack_header_freq = 1; - - if (s->is_mpeg2) - /* every 200 packets. Need to look at the spec. */ - s->system_header_freq = s->pack_header_freq * 40; - else if (s->is_vcd) - /* the standard mandates that there are only two system headers - in the whole file: one in the first packet of each stream. - (see standard p. IV-7 and IV-8) */ - s->system_header_freq = 0x7fffffff; - else - s->system_header_freq = s->pack_header_freq * 5; - - for(i=0;i<ctx->nb_streams;i++) { - stream = ctx->streams[i]->priv_data; - stream->packet_number = 0; - } - s->system_header_size = get_system_header_size(ctx); - s->last_scr = 0; - return 0; - fail: - for(i=0;i<ctx->nb_streams;i++) { - av_free(ctx->streams[i]->priv_data); - } - return AVERROR(ENOMEM); -} - -static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp) -{ - put_byte(pb, - (id << 4) | - (((timestamp >> 30) & 0x07) << 1) | - 1); - put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1)); - put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1)); -} - - -/* return the number of padding bytes that should be inserted into - the multiplexed stream.*/ -static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts) -{ - MpegMuxContext *s = ctx->priv_data; - int pad_bytes = 0; - - if (s->vcd_padding_bitrate > 0 && pts!=AV_NOPTS_VALUE) - { - int64_t full_pad_bytes; - - full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); //FIXME this is wrong - pad_bytes = (int) (full_pad_bytes - s->vcd_padding_bytes_written); - - if (pad_bytes<0) - /* might happen if we have already padded to a later timestamp. This - can occur if another stream has already advanced further.*/ - pad_bytes=0; - } - - return pad_bytes; -} - - -#if 0 /* unused, remove? */ -/* return the exact available payload size for the next packet for - stream 'stream_index'. 'pts' and 'dts' are only used to know if - timestamps are needed in the packet header. */ -static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, - int64_t pts, int64_t dts) -{ - MpegMuxContext *s = ctx->priv_data; - int buf_index; - StreamInfo *stream; - - stream = ctx->streams[stream_index]->priv_data; - - buf_index = 0; - if (((s->packet_number % s->pack_header_freq) == 0)) { - /* pack header size */ - if (s->is_mpeg2) - buf_index += 14; - else - buf_index += 12; - - if (s->is_vcd) { - /* there is exactly one system header for each stream in a VCD MPEG, - One in the very first video packet and one in the very first - audio packet (see VCD standard p. IV-7 and IV-8).*/ - - if (stream->packet_number==0) - /* The system headers refer only to the stream they occur in, - so they have a constant size.*/ - buf_index += 15; - - } else { - if ((s->packet_number % s->system_header_freq) == 0) - buf_index += s->system_header_size; - } - } - - if ((s->is_vcd && stream->packet_number==0) - || (s->is_svcd && s->packet_number==0)) - /* the first pack of each stream contains only the pack header, - the system header and some padding (see VCD standard p. IV-6) - Add the padding size, so that the actual payload becomes 0.*/ - buf_index += s->packet_size - buf_index; - else { - /* packet header size */ - buf_index += 6; - if (s->is_mpeg2) { - buf_index += 3; - if (stream->packet_number==0) - buf_index += 3; /* PES extension */ - buf_index += 1; /* obligatory stuffing byte */ - } - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) - buf_index += 5 + 5; - else - buf_index += 5; - - } else { - if (!s->is_mpeg2) - buf_index++; - } - - if (stream->id < 0xc0) { - /* AC3/LPCM private data header */ - buf_index += 4; - if (stream->id >= 0xa0) { - int n; - buf_index += 3; - /* NOTE: we round the payload size to an integer number of - LPCM samples */ - n = (s->packet_size - buf_index) % stream->lpcm_align; - if (n) - buf_index += (stream->lpcm_align - n); - } - } - - if (s->is_vcd && stream->id == AUDIO_ID) - /* The VCD standard demands that 20 zero bytes follow - each audio packet (see standard p. IV-8).*/ - buf_index+=20; - } - return s->packet_size - buf_index; -} -#endif - -/* Write an MPEG padding packet header. */ -static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes) -{ - MpegMuxContext *s = ctx->priv_data; - int i; - - put_be32(pb, PADDING_STREAM); - put_be16(pb, packet_bytes - 6); - if (!s->is_mpeg2) { - put_byte(pb, 0x0f); - packet_bytes -= 7; - } else - packet_bytes -= 6; - - for(i=0;i<packet_bytes;i++) - put_byte(pb, 0xff); -} - -static int get_nb_frames(AVFormatContext *ctx, StreamInfo *stream, int len){ - int nb_frames=0; - PacketDesc *pkt_desc= stream->premux_packet; - - while(len>0){ - if(pkt_desc->size == pkt_desc->unwritten_size) - nb_frames++; - len -= pkt_desc->unwritten_size; - pkt_desc= pkt_desc->next; - } - - return nb_frames; -} - -/* flush the packet on stream stream_index */ -static int flush_packet(AVFormatContext *ctx, int stream_index, - int64_t pts, int64_t dts, int64_t scr, int trailer_size) -{ - MpegMuxContext *s = ctx->priv_data; - StreamInfo *stream = ctx->streams[stream_index]->priv_data; - uint8_t *buf_ptr; - int size, payload_size, startcode, id, stuffing_size, i, header_len; - int packet_size; - uint8_t buffer[128]; - int zero_trail_bytes = 0; - int pad_packet_bytes = 0; - int pes_flags; - int general_pack = 0; /*"general" pack without data specific to one stream?*/ - int nb_frames; - - id = stream->id; - -#if 0 - printf("packet ID=%2x PTS=%0.3f\n", - id, pts / 90000.0); -#endif - - buf_ptr = buffer; - - if ((s->packet_number % s->pack_header_freq) == 0 || s->last_scr != scr) { - /* output pack and systems header if needed */ - size = put_pack_header(ctx, buf_ptr, scr); - buf_ptr += size; - s->last_scr= scr; - - if (s->is_vcd) { - /* there is exactly one system header for each stream in a VCD MPEG, - One in the very first video packet and one in the very first - audio packet (see VCD standard p. IV-7 and IV-8).*/ - - if (stream->packet_number==0) { - size = put_system_header(ctx, buf_ptr, id); - buf_ptr += size; - } - } else if (s->is_dvd) { - if (stream->align_iframe || s->packet_number == 0){ - int PES_bytes_to_fill = s->packet_size - size - 10; - - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) - PES_bytes_to_fill -= 5 + 5; - else - PES_bytes_to_fill -= 5; - } - - if (stream->bytes_to_iframe == 0 || s->packet_number == 0) { - size = put_system_header(ctx, buf_ptr, 0); - buf_ptr += size; - size = buf_ptr - buffer; - put_buffer(&ctx->pb, buffer, size); - - put_be32(&ctx->pb, PRIVATE_STREAM_2); - put_be16(&ctx->pb, 0x03d4); // length - put_byte(&ctx->pb, 0x00); // substream ID, 00=PCI - for (i = 0; i < 979; i++) - put_byte(&ctx->pb, 0x00); - - put_be32(&ctx->pb, PRIVATE_STREAM_2); - put_be16(&ctx->pb, 0x03fa); // length - put_byte(&ctx->pb, 0x01); // substream ID, 01=DSI - for (i = 0; i < 1017; i++) - put_byte(&ctx->pb, 0x00); - - memset(buffer, 0, 128); - buf_ptr = buffer; - s->packet_number++; - stream->align_iframe = 0; - scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet - size = put_pack_header(ctx, buf_ptr, scr); - s->last_scr= scr; - buf_ptr += size; - /* GOP Start */ - } else if (stream->bytes_to_iframe < PES_bytes_to_fill) { - pad_packet_bytes = PES_bytes_to_fill - stream->bytes_to_iframe; - } - } - } else { - if ((s->packet_number % s->system_header_freq) == 0) { - size = put_system_header(ctx, buf_ptr, 0); - buf_ptr += size; - } - } - } - size = buf_ptr - buffer; - put_buffer(&ctx->pb, buffer, size); - - packet_size = s->packet_size - size; - - if (s->is_vcd && id == AUDIO_ID) - /* The VCD standard demands that 20 zero bytes follow - each audio pack (see standard p. IV-8).*/ - zero_trail_bytes += 20; - - if ((s->is_vcd && stream->packet_number==0) - || (s->is_svcd && s->packet_number==0)) { - /* for VCD the first pack of each stream contains only the pack header, - the system header and lots of padding (see VCD standard p. IV-6). - In the case of an audio pack, 20 zero bytes are also added at - the end.*/ - /* For SVCD we fill the very first pack to increase compatibility with - some DVD players. Not mandated by the standard.*/ - if (s->is_svcd) - general_pack = 1; /* the system header refers to both streams and no stream data*/ - pad_packet_bytes = packet_size - zero_trail_bytes; - } - - packet_size -= pad_packet_bytes + zero_trail_bytes; - - if (packet_size > 0) { - - /* packet header size */ - packet_size -= 6; - - /* packet header */ - if (s->is_mpeg2) { - header_len = 3; - if (stream->packet_number==0) - header_len += 3; /* PES extension */ - header_len += 1; /* obligatory stuffing byte */ - } else { - header_len = 0; - } - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) - header_len += 5 + 5; - else - header_len += 5; - } else { - if (!s->is_mpeg2) - header_len++; - } - - payload_size = packet_size - header_len; - if (id < 0xc0) { - startcode = PRIVATE_STREAM_1; - payload_size -= 1; - if (id >= 0x40) { - payload_size -= 3; - if (id >= 0xa0) - payload_size -= 3; - } - } else { - startcode = 0x100 + id; - } - - stuffing_size = payload_size - av_fifo_size(&stream->fifo); - - // first byte doesnt fit -> reset pts/dts + stuffing - if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){ - int timestamp_len=0; - if(dts != pts) - timestamp_len += 5; - if(pts != AV_NOPTS_VALUE) - timestamp_len += s->is_mpeg2 ? 5 : 4; - pts=dts= AV_NOPTS_VALUE; - header_len -= timestamp_len; - if (s->is_dvd && stream->align_iframe) { - pad_packet_bytes += timestamp_len; - packet_size -= timestamp_len; - } else { - payload_size += timestamp_len; - } - stuffing_size += timestamp_len; - if(payload_size > trailer_size) - stuffing_size += payload_size - trailer_size; - } - - if (pad_packet_bytes > 0 && pad_packet_bytes <= 7) { // can't use padding, so use stuffing - packet_size += pad_packet_bytes; - payload_size += pad_packet_bytes; // undo the previous adjustment - if (stuffing_size < 0) { - stuffing_size = pad_packet_bytes; - } else { - stuffing_size += pad_packet_bytes; - } - pad_packet_bytes = 0; - } - - if (stuffing_size < 0) - stuffing_size = 0; - if (stuffing_size > 16) { /*<=16 for MPEG-1, <=32 for MPEG-2*/ - pad_packet_bytes += stuffing_size; - packet_size -= stuffing_size; - payload_size -= stuffing_size; - stuffing_size = 0; - } - - nb_frames= get_nb_frames(ctx, stream, payload_size - stuffing_size); - - put_be32(&ctx->pb, startcode); - - put_be16(&ctx->pb, packet_size); - - if (!s->is_mpeg2) - for(i=0;i<stuffing_size;i++) - put_byte(&ctx->pb, 0xff); - - if (s->is_mpeg2) { - put_byte(&ctx->pb, 0x80); /* mpeg2 id */ - - pes_flags=0; - - if (pts != AV_NOPTS_VALUE) { - pes_flags |= 0x80; - if (dts != pts) - pes_flags |= 0x40; - } - - /* Both the MPEG-2 and the SVCD standards demand that the - P-STD_buffer_size field be included in the first packet of - every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2 - and MPEG-2 standard 2.7.7) */ - if (stream->packet_number == 0) - pes_flags |= 0x01; - - put_byte(&ctx->pb, pes_flags); /* flags */ - put_byte(&ctx->pb, header_len - 3 + stuffing_size); - - if (pes_flags & 0x80) /*write pts*/ - put_timestamp(&ctx->pb, (pes_flags & 0x40) ? 0x03 : 0x02, pts); - if (pes_flags & 0x40) /*write dts*/ - put_timestamp(&ctx->pb, 0x01, dts); - - if (pes_flags & 0x01) { /*write pes extension*/ - put_byte(&ctx->pb, 0x10); /* flags */ - - /* P-STD buffer info */ - if (id == AUDIO_ID) - put_be16(&ctx->pb, 0x4000 | stream->max_buffer_size/128); - else - put_be16(&ctx->pb, 0x6000 | stream->max_buffer_size/1024); - } - - } else { - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) { - put_timestamp(&ctx->pb, 0x03, pts); - put_timestamp(&ctx->pb, 0x01, dts); - } else { - put_timestamp(&ctx->pb, 0x02, pts); - } - } else { - put_byte(&ctx->pb, 0x0f); - } - } - - if (s->is_mpeg2) { - /* special stuffing byte that is always written - to prevent accidental generation of start codes. */ - put_byte(&ctx->pb, 0xff); - - for(i=0;i<stuffing_size;i++) - put_byte(&ctx->pb, 0xff); - } - - if (startcode == PRIVATE_STREAM_1) { - put_byte(&ctx->pb, id); - if (id >= 0xa0) { - /* LPCM (XXX: check nb_frames) */ - put_byte(&ctx->pb, 7); - put_be16(&ctx->pb, 4); /* skip 3 header bytes */ - put_byte(&ctx->pb, stream->lpcm_header[0]); - put_byte(&ctx->pb, stream->lpcm_header[1]); - put_byte(&ctx->pb, stream->lpcm_header[2]); - } else if (id >= 0x40) { - /* AC3 */ - put_byte(&ctx->pb, nb_frames); - put_be16(&ctx->pb, trailer_size+1); - } - } - - /* output data */ - if(av_fifo_generic_read(&stream->fifo, payload_size - stuffing_size, &put_buffer, &ctx->pb) < 0) - return -1; - stream->bytes_to_iframe -= payload_size - stuffing_size; - }else{ - payload_size= - stuffing_size= 0; - } - - if (pad_packet_bytes > 0) - put_padding_packet(ctx,&ctx->pb, pad_packet_bytes); - - for(i=0;i<zero_trail_bytes;i++) - put_byte(&ctx->pb, 0x00); - - put_flush_packet(&ctx->pb); - - s->packet_number++; - - /* only increase the stream packet number if this pack actually contains - something that is specific to this stream! I.e. a dedicated header - or some data.*/ - if (!general_pack) - stream->packet_number++; - - return payload_size - stuffing_size; -} - -static void put_vcd_padding_sector(AVFormatContext *ctx) -{ - /* There are two ways to do this padding: writing a sector/pack - of 0 values, or writing an MPEG padding pack. Both seem to - work with most decoders, BUT the VCD standard only allows a 0-sector - (see standard p. IV-4, IV-5). - So a 0-sector it is...*/ - - MpegMuxContext *s = ctx->priv_data; - int i; - - for(i=0;i<s->packet_size;i++) - put_byte(&ctx->pb, 0); - - s->vcd_padding_bytes_written += s->packet_size; - - put_flush_packet(&ctx->pb); - - /* increasing the packet number is correct. The SCR of the following packs - is calculated from the packet_number and it has to include the padding - sector (it represents the sector index, not the MPEG pack index) - (see VCD standard p. IV-6)*/ - s->packet_number++; -} - -#if 0 /* unused, remove? */ -static int64_t get_vcd_scr(AVFormatContext *ctx,int stream_index,int64_t pts) -{ - MpegMuxContext *s = ctx->priv_data; - int64_t scr; - - /* Since the data delivery rate is constant, SCR is computed - using the formula C + i * 1200 where C is the start constant - and i is the pack index. - It is recommended that SCR 0 is at the beginning of the VCD front - margin (a sequence of empty Form 2 sectors on the CD). - It is recommended that the front margin is 30 sectors long, so - we use C = 30*1200 = 36000 - (Note that even if the front margin is not 30 sectors the file - will still be correct according to the standard. It just won't have - the "recommended" value).*/ - scr = 36000 + s->packet_number * 1200; - - return scr; -} -#endif - -static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr){ -// MpegMuxContext *s = ctx->priv_data; - int i; - - for(i=0; i<ctx->nb_streams; i++){ - AVStream *st = ctx->streams[i]; - StreamInfo *stream = st->priv_data; - PacketDesc *pkt_desc= stream->predecode_packet; - - while(pkt_desc && scr > pkt_desc->dts){ //FIXME > vs >= - if(stream->buffer_index < pkt_desc->size || - stream->predecode_packet == stream->premux_packet){ - av_log(ctx, AV_LOG_ERROR, "buffer underflow\n"); - break; - } - stream->buffer_index -= pkt_desc->size; - - stream->predecode_packet= pkt_desc->next; - av_freep(&pkt_desc); - } - } - - return 0; -} - -static int output_packet(AVFormatContext *ctx, int flush){ - MpegMuxContext *s = ctx->priv_data; - AVStream *st; - StreamInfo *stream; - int i, avail_space, es_size, trailer_size; - int best_i= -1; - int best_score= INT_MIN; - int ignore_constraints=0; - int64_t scr= s->last_scr; - PacketDesc *timestamp_packet; - const int64_t max_delay= av_rescale(ctx->max_delay, 90000, AV_TIME_BASE); - -retry: - for(i=0; i<ctx->nb_streams; i++){ - AVStream *st = ctx->streams[i]; - 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; - PacketDesc *next_pkt= stream->premux_packet; - - /* for subtitle, a single PES packet must be generated, - so we flush after every single subtitle packet */ - if(s->packet_size > avail_data && !flush - && st->codec->codec_type != CODEC_TYPE_SUBTITLE) - return 0; - if(avail_data==0) - continue; - assert(avail_data>0); - - if(space < s->packet_size && !ignore_constraints) - continue; - - if(next_pkt && next_pkt->dts - scr > max_delay) - continue; - - if(rel_space > best_score){ - best_score= rel_space; - best_i = i; - avail_space= space; - } - } - - if(best_i < 0){ - int64_t best_dts= INT64_MAX; - - for(i=0; i<ctx->nb_streams; i++){ - AVStream *st = ctx->streams[i]; - StreamInfo *stream = st->priv_data; - PacketDesc *pkt_desc= stream->predecode_packet; - if(pkt_desc && pkt_desc->dts < best_dts) - best_dts= pkt_desc->dts; - } - -#if 0 - av_log(ctx, AV_LOG_DEBUG, "bumping scr, scr:%f, dts:%f\n", - scr/90000.0, best_dts/90000.0); -#endif - if(best_dts == INT64_MAX) - return 0; - - if(scr >= best_dts+1 && !ignore_constraints){ - av_log(ctx, AV_LOG_ERROR, "packet too large, ignoring buffer limits to mux it\n"); - ignore_constraints= 1; - } - scr= FFMAX(best_dts+1, scr); - if(remove_decoded_packets(ctx, scr) < 0) - return -1; - goto retry; - } - - assert(best_i >= 0); - - st = ctx->streams[best_i]; - stream = st->priv_data; - - assert(av_fifo_size(&stream->fifo) > 0); - - assert(avail_space >= s->packet_size || ignore_constraints); - - timestamp_packet= stream->premux_packet; - if(timestamp_packet->unwritten_size == timestamp_packet->size){ - trailer_size= 0; - }else{ - trailer_size= timestamp_packet->unwritten_size; - timestamp_packet= timestamp_packet->next; - } - - if(timestamp_packet){ -//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f scr:%f stream:%d\n", timestamp_packet->dts/90000.0, timestamp_packet->pts/90000.0, scr/90000.0, best_i); - es_size= flush_packet(ctx, best_i, timestamp_packet->pts, timestamp_packet->dts, scr, trailer_size); - }else{ - assert(av_fifo_size(&stream->fifo) == trailer_size); - es_size= flush_packet(ctx, best_i, AV_NOPTS_VALUE, AV_NOPTS_VALUE, scr, trailer_size); - } - - if (s->is_vcd) { - /* Write one or more padding sectors, if necessary, to reach - the constant overall bitrate.*/ - int vcd_pad_bytes; - - while((vcd_pad_bytes = get_vcd_padding_size(ctx,stream->premux_packet->pts) ) >= s->packet_size){ //FIXME pts cannot be correct here - put_vcd_padding_sector(ctx); - s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet - } - } - - stream->buffer_index += es_size; - s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet - - while(stream->premux_packet && stream->premux_packet->unwritten_size <= es_size){ - es_size -= stream->premux_packet->unwritten_size; - stream->premux_packet= stream->premux_packet->next; - } - if(es_size) - stream->premux_packet->unwritten_size -= es_size; - - if(remove_decoded_packets(ctx, s->last_scr) < 0) - return -1; - - return 1; -} - -static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) -{ - MpegMuxContext *s = ctx->priv_data; - int stream_index= pkt->stream_index; - int size= pkt->size; - uint8_t *buf= pkt->data; - AVStream *st = ctx->streams[stream_index]; - StreamInfo *stream = st->priv_data; - int64_t pts, dts; - PacketDesc *pkt_desc; - const int preload= av_rescale(ctx->preload, 90000, AV_TIME_BASE); - const int is_iframe = st->codec->codec_type == CODEC_TYPE_VIDEO && (pkt->flags & PKT_FLAG_KEY); - - pts= pkt->pts; - dts= pkt->dts; - - if(pts != AV_NOPTS_VALUE) pts += preload; - if(dts != AV_NOPTS_VALUE) dts += preload; - -//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f flags:%d stream:%d nopts:%d\n", dts/90000.0, pts/90000.0, pkt->flags, pkt->stream_index, pts != AV_NOPTS_VALUE); - if (!stream->premux_packet) - stream->next_packet = &stream->premux_packet; - *stream->next_packet= - pkt_desc= av_mallocz(sizeof(PacketDesc)); - pkt_desc->pts= pts; - pkt_desc->dts= dts; - pkt_desc->unwritten_size= - pkt_desc->size= size; - if(!stream->predecode_packet) - stream->predecode_packet= pkt_desc; - stream->next_packet= &pkt_desc->next; - - av_fifo_realloc(&stream->fifo, av_fifo_size(&stream->fifo) + size + 1); - - if (s->is_dvd){ - if (is_iframe && (s->packet_number == 0 || (pts - stream->vobu_start_pts >= 36000))) { // min VOBU length 0.4 seconds (mpucoder) - stream->bytes_to_iframe = av_fifo_size(&stream->fifo); - stream->align_iframe = 1; - stream->vobu_start_pts = pts; - } else { - stream->align_iframe = 0; - } - } - - av_fifo_write(&stream->fifo, buf, size); - - for(;;){ - int ret= output_packet(ctx, 0); - if(ret<=0) - return ret; - } -} - -static int mpeg_mux_end(AVFormatContext *ctx) -{ -// MpegMuxContext *s = ctx->priv_data; - StreamInfo *stream; - int i; - - for(;;){ - int ret= output_packet(ctx, 1); - if(ret<0) - return ret; - else if(ret==0) - break; - } - - /* End header according to MPEG1 systems standard. We do not write - it as it is usually not needed by decoders and because it - complicates MPEG stream concatenation. */ - //put_be32(&ctx->pb, ISO_11172_END_CODE); - //put_flush_packet(&ctx->pb); - - for(i=0;i<ctx->nb_streams;i++) { - stream = ctx->streams[i]->priv_data; - - assert(av_fifo_size(&stream->fifo) == 0); - av_fifo_free(&stream->fifo); - } - return 0; -} -#endif //CONFIG_MUXERS - /*********************************************/ /* demux code */ #define MAX_SYNC_SIZE 100000 -static int cdxa_probe(AVProbeData *p) -{ - /* check file header */ - if (p->buf_size <= 32) - return 0; - if (p->buf[0] == 'R' && p->buf[1] == 'I' && - p->buf[2] == 'F' && p->buf[3] == 'F' && - p->buf[8] == 'C' && p->buf[9] == 'D' && - p->buf[10] == 'X' && p->buf[11] == 'A') - return AVPROBE_SCORE_MAX; - else - return 0; +static int check_pes(uint8_t *p, uint8_t *end){ + int pes1; + int pes2= (p[3] & 0xC0) == 0x80 + && (p[4] & 0xC0) != 0x40 + &&((p[4] & 0xC0) == 0x00 || (p[4]&0xC0)>>2 == (p[6]&0xF0)); + + for(p+=3; p<end && *p == 0xFF; p++); + if((*p&0xC0) == 0x40) p+=2; + if((*p&0xF0) == 0x20){ + pes1= p[0]&p[2]&p[4]&1; + p+=5; + }else if((*p&0xF0) == 0x30){ + pes1= p[0]&p[2]&p[4]&p[5]&p[7]&p[9]&1; + p+=10; + }else + pes1 = *p == 0x0F; + + return pes1||pes2; } static int mpegps_probe(AVProbeData *p) { uint32_t code= -1; - int sys=0, pspack=0, priv1=0, vid=0, audio=0; + int sys=0, pspack=0, priv1=0, vid=0, audio=0, invalid=0; int i; int score=0; - score = cdxa_probe(p); - if (score > 0) return score; - - /* Search for MPEG stream */ for(i=0; i<p->buf_size; i++){ code = (code<<8) + p->buf[i]; if ((code & 0xffffff00) == 0x100) { + int pes= check_pes(p->buf+i, p->buf+p->buf_size); + if(code == SYSTEM_HEADER_START_CODE) sys++; else if(code == PRIVATE_STREAM_1) priv1++; else if(code == PACK_START_CODE) pspack++; - else if((code & 0xf0) == VIDEO_ID) vid++; - else if((code & 0xe0) == AUDIO_ID) audio++; + else if((code & 0xf0) == VIDEO_ID && pes) vid++; + else if((code & 0xe0) == AUDIO_ID && pes) audio++; + + else if((code & 0xf0) == VIDEO_ID && !pes) invalid++; + else if((code & 0xe0) == AUDIO_ID && !pes) invalid++; } } - if(vid || audio) /* invalid VDR files nd short PES streams */ + if(vid+audio > invalid) /* invalid VDR files nd short PES streams */ score= AVPROBE_SCORE_MAX/4; -//av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d\n", sys, priv1, pspack,vid, audio); - if(sys && sys*9 <= pspack*10) +//av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d len:%d\n", sys, priv1, pspack,vid, audio, p->buf_size); + if(sys>invalid && sys*9 <= pspack*10) return AVPROBE_SCORE_MAX/2+2; // +1 for .mpg - if((priv1 || vid || audio) && (priv1+vid+audio)*9 <= pspack*10) + if(priv1 + vid + audio > invalid && (priv1+vid+audio)*9 <= pspack*10) return AVPROBE_SCORE_MAX/2+2; // +1 for .mpg - if((!!vid ^ !!audio) && (audio+vid > 1) && !sys && !pspack) /* PES stream */ + if((!!vid ^ !!audio) && (audio+vid > 1) && !sys && !pspack && p->buf_size>2048) /* PES stream */ return AVPROBE_SCORE_MAX/2+2; //02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1 @@ -1312,32 +94,38 @@ static int mpegps_probe(AVProbeData *p) typedef struct MpegDemuxContext { int32_t header_state; unsigned char psm_es_type[256]; + int sofdec; } MpegDemuxContext; static int mpegps_read_header(AVFormatContext *s, AVFormatParameters *ap) { MpegDemuxContext *m = s->priv_data; + const char *sofdec = "Sofdec"; + int v, i = 0; + m->header_state = 0xff; s->ctx_flags |= AVFMTCTX_NOHEADER; + m->sofdec = -1; + do { + v = get_byte(s->pb); + m->header_state = m->header_state << 8 | v; + m->sofdec++; + } while (v == sofdec[i] && i++ < 6); + /* no need to do more */ return 0; } static int64_t get_pts(ByteIOContext *pb, int c) { - int64_t pts; - int val; + uint8_t buf[5]; + + buf[0] = c<0 ? get_byte(pb) : c; + get_buffer(pb, buf+1, 4); - if (c < 0) - c = get_byte(pb); - pts = (int64_t)((c >> 1) & 0x07) << 30; - val = get_be16(pb); - pts |= (int64_t)(val >> 1) << 15; - val = get_be16(pb); - pts |= (int64_t)(val >> 1); - return pts; + return ff_parse_pes_pts(buf); } static int find_next_start_code(ByteIOContext *pb, int *size_ptr, @@ -1447,32 +235,46 @@ static int mpegps_read_pes_header(AVFormatContext *s, int len, size, startcode, c, flags, header_len; int pes_ext, ext2_len, id_ext, skip; int64_t pts, dts; - int64_t last_sync= url_ftell(&s->pb); + int64_t last_sync= url_ftell(s->pb); error_redo: - url_fseek(&s->pb, last_sync, SEEK_SET); + url_fseek(s->pb, last_sync, SEEK_SET); redo: /* next start code (should be immediately after) */ m->header_state = 0xff; size = MAX_SYNC_SIZE; - startcode = find_next_start_code(&s->pb, &size, &m->header_state); - last_sync = url_ftell(&s->pb); - //printf("startcode=%x pos=0x%"PRIx64"\n", startcode, url_ftell(&s->pb)); + startcode = find_next_start_code(s->pb, &size, &m->header_state); + last_sync = url_ftell(s->pb); + //printf("startcode=%x pos=0x%"PRIx64"\n", startcode, url_ftell(s->pb)); if (startcode < 0) - return AVERROR_IO; + return AVERROR(EIO); if (startcode == PACK_START_CODE) goto redo; if (startcode == SYSTEM_HEADER_START_CODE) goto redo; - if (startcode == PADDING_STREAM || - startcode == PRIVATE_STREAM_2) { - /* skip them */ - len = get_be16(&s->pb); - url_fskip(&s->pb, len); + if (startcode == PADDING_STREAM) { + url_fskip(s->pb, get_be16(s->pb)); + goto redo; + } + if (startcode == PRIVATE_STREAM_2) { + len = get_be16(s->pb); + if (!m->sofdec) { + while (len-- >= 6) { + if (get_byte(s->pb) == 'S') { + uint8_t buf[5]; + get_buffer(s->pb, buf, sizeof(buf)); + m->sofdec = !memcmp(buf, "ofdec", 5); + len -= sizeof(buf); + break; + } + } + m->sofdec -= !m->sofdec; + } + url_fskip(s->pb, len); goto redo; } if (startcode == PROGRAM_STREAM_MAP) { - mpegps_psm_parse(m, &s->pb); + mpegps_psm_parse(m, s->pb); goto redo; } @@ -1482,16 +284,16 @@ static int mpegps_read_pes_header(AVFormatContext *s, (startcode == 0x1bd) || (startcode == 0x1fd))) goto redo; if (ppos) { - *ppos = url_ftell(&s->pb) - 4; + *ppos = url_ftell(s->pb) - 4; } - len = get_be16(&s->pb); + len = get_be16(s->pb); pts = dts = AV_NOPTS_VALUE; /* stuffing */ for(;;) { if (len < 1) goto error_redo; - c = get_byte(&s->pb); + c = get_byte(s->pb); len--; /* XXX: for mpeg1, should test only bit 7 */ if (c != 0xff) @@ -1499,15 +301,15 @@ static int mpegps_read_pes_header(AVFormatContext *s, } if ((c & 0xc0) == 0x40) { /* buffer scale & size */ - get_byte(&s->pb); - c = get_byte(&s->pb); + get_byte(s->pb); + c = get_byte(s->pb); len -= 2; } if ((c & 0xe0) == 0x20) { - dts = pts = get_pts(&s->pb, c); + dts = pts = get_pts(s->pb, c); len -= 4; if (c & 0x10){ - dts = get_pts(&s->pb, -1); + dts = get_pts(s->pb, -1); len -= 5; } } else if ((c & 0xc0) == 0x80) { @@ -1518,22 +320,22 @@ static int mpegps_read_pes_header(AVFormatContext *s, goto redo; } #endif - flags = get_byte(&s->pb); - header_len = get_byte(&s->pb); + flags = get_byte(s->pb); + header_len = get_byte(s->pb); len -= 2; if (header_len > len) goto error_redo; len -= header_len; if (flags & 0x80) { - dts = pts = get_pts(&s->pb, -1); + dts = pts = get_pts(s->pb, -1); header_len -= 5; if (flags & 0x40) { - dts = get_pts(&s->pb, -1); + dts = get_pts(s->pb, -1); header_len -= 5; } } if (flags & 0x01) { /* PES extension */ - pes_ext = get_byte(&s->pb); + pes_ext = get_byte(s->pb); header_len--; if (pes_ext & 0x40) { /* pack header - should be zero in PS */ goto error_redo; @@ -1541,14 +343,14 @@ static int mpegps_read_pes_header(AVFormatContext *s, /* Skip PES private data, program packet sequence counter and P-STD buffer */ skip = (pes_ext >> 4) & 0xb; skip += skip & 0x9; - url_fskip(&s->pb, skip); + url_fskip(s->pb, skip); header_len -= skip; if (pes_ext & 0x01) { /* PES extension 2 */ - ext2_len = get_byte(&s->pb); + ext2_len = get_byte(s->pb); header_len--; if ((ext2_len & 0x7f) > 0) { - id_ext = get_byte(&s->pb); + id_ext = get_byte(s->pb); if ((id_ext & 0x80) == 0) startcode = ((startcode & 0xff) << 8) | id_ext; header_len--; @@ -1557,23 +359,23 @@ static int mpegps_read_pes_header(AVFormatContext *s, } if(header_len < 0) goto error_redo; - url_fskip(&s->pb, header_len); + url_fskip(s->pb, header_len); } else if( c!= 0xf ) goto redo; if (startcode == PRIVATE_STREAM_1 && !m->psm_es_type[startcode & 0xff]) { - startcode = get_byte(&s->pb); + startcode = get_byte(s->pb); len--; if (startcode >= 0x80 && startcode <= 0xcf) { /* audio: skip header */ - get_byte(&s->pb); - get_byte(&s->pb); - get_byte(&s->pb); + get_byte(s->pb); + get_byte(s->pb); + get_byte(s->pb); len -= 3; if (startcode >= 0xb0 && startcode <= 0xbf) { /* MLP/TrueHD audio has a 4-byte header */ - get_byte(&s->pb); + get_byte(s->pb); len--; } } @@ -1583,7 +385,9 @@ static int mpegps_read_pes_header(AVFormatContext *s, if(dts != AV_NOPTS_VALUE && ppos){ int i; for(i=0; i<s->nb_streams; i++){ - if(startcode == s->streams[i]->id) { + if(startcode == s->streams[i]->id && + !url_is_streamed(s->pb) /* index useless on streams anyway */) { + ff_reduce_index(s, i); av_add_index_entry(s->streams[i], *ppos, dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */); } } @@ -1645,8 +449,8 @@ static int mpegps_read_packet(AVFormatContext *s, } else if (startcode >= 0x1e0 && startcode <= 0x1ef) { static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 }; unsigned char buf[8]; - get_buffer(&s->pb, buf, 8); - url_fseek(&s->pb, -8, SEEK_CUR); + get_buffer(s->pb, buf, 8); + url_fseek(s->pb, -8, SEEK_CUR); if(!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1)) codec_id = CODEC_ID_CAVS; else @@ -1654,7 +458,7 @@ static int mpegps_read_packet(AVFormatContext *s, type = CODEC_TYPE_VIDEO; } else if (startcode >= 0x1c0 && startcode <= 0x1df) { type = CODEC_TYPE_AUDIO; - codec_id = CODEC_ID_MP2; + codec_id = m->sofdec > 0 ? CODEC_ID_ADPCM_ADX : CODEC_ID_MP2; } else if (startcode >= 0x80 && startcode <= 0x87) { type = CODEC_TYPE_AUDIO; codec_id = CODEC_ID_AC3; @@ -1682,7 +486,7 @@ static int mpegps_read_packet(AVFormatContext *s, } else { skip: /* skip packet */ - url_fskip(&s->pb, len); + url_fskip(s->pb, len); goto redo; } /* no stream found: add a new stream */ @@ -1692,7 +496,7 @@ static int mpegps_read_packet(AVFormatContext *s, st->codec->codec_type = type; st->codec->codec_id = codec_id; if (codec_id != CODEC_ID_PCM_S16BE) - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; found: if(st->discard >= AVDISCARD_ALL) goto skip; @@ -1703,9 +507,9 @@ static int mpegps_read_packet(AVFormatContext *s, audio data */ if (len <= 3) goto skip; - get_byte(&s->pb); /* emphasis (1), muse(1), reserved(1), frame number(5) */ - b1 = get_byte(&s->pb); /* quant (2), freq(2), reserved(1), channels(3) */ - get_byte(&s->pb); /* dynamic range control (0x80 = off) */ + get_byte(s->pb); /* emphasis (1), muse(1), reserved(1), frame number(5) */ + b1 = get_byte(s->pb); /* quant (2), freq(2), reserved(1), channels(3) */ + get_byte(s->pb); /* dynamic range control (0x80 = off) */ len -= 3; freq = (b1 >> 4) & 3; st->codec->sample_rate = lpcm_freq_tab[freq]; @@ -1713,7 +517,7 @@ static int mpegps_read_packet(AVFormatContext *s, st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * 2; } av_new_packet(pkt, len); - get_buffer(&s->pb, pkt->data, pkt->size); + get_buffer(s->pb, pkt->data, pkt->size); pkt->pts = pts; pkt->dts = dts; pkt->stream_index = st->index; @@ -1740,7 +544,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, #ifdef DEBUG_SEEK printf("read_dts: pos=0x%"PRIx64" next=%d -> ", pos, find_next); #endif - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); for(;;) { len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts); if (len < 0) { @@ -1753,7 +557,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, dts != AV_NOPTS_VALUE) { break; } - url_fskip(&s->pb, len); + url_fskip(s->pb, len); } #ifdef DEBUG_SEEK printf("pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n", pos, dts, dts / 90000.0); @@ -1762,82 +566,6 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, return dts; } -#ifdef CONFIG_MPEG1SYSTEM_MUXER -AVOutputFormat mpeg1system_muxer = { - "mpeg", - "MPEG1 System format", - "video/mpeg", - "mpg,mpeg", - sizeof(MpegMuxContext), - CODEC_ID_MP2, - CODEC_ID_MPEG1VIDEO, - mpeg_mux_init, - mpeg_mux_write_packet, - mpeg_mux_end, -}; -#endif -#ifdef CONFIG_MPEG1VCD_MUXER -AVOutputFormat mpeg1vcd_muxer = { - "vcd", - "MPEG1 System format (VCD)", - "video/mpeg", - NULL, - sizeof(MpegMuxContext), - CODEC_ID_MP2, - CODEC_ID_MPEG1VIDEO, - mpeg_mux_init, - mpeg_mux_write_packet, - mpeg_mux_end, -}; -#endif -#ifdef CONFIG_MPEG2VOB_MUXER -AVOutputFormat mpeg2vob_muxer = { - "vob", - "MPEG2 PS format (VOB)", - "video/mpeg", - "vob", - sizeof(MpegMuxContext), - CODEC_ID_MP2, - CODEC_ID_MPEG2VIDEO, - mpeg_mux_init, - mpeg_mux_write_packet, - mpeg_mux_end, -}; -#endif - -/* Same as mpeg2vob_mux except that the pack size is 2324 */ -#ifdef CONFIG_MPEG2SVCD_MUXER -AVOutputFormat mpeg2svcd_muxer = { - "svcd", - "MPEG2 PS format (VOB)", - "video/mpeg", - "vob", - sizeof(MpegMuxContext), - CODEC_ID_MP2, - CODEC_ID_MPEG2VIDEO, - mpeg_mux_init, - mpeg_mux_write_packet, - mpeg_mux_end, -}; -#endif - -/* Same as mpeg2vob_mux except the 'is_dvd' flag is set to produce NAV pkts */ -#ifdef CONFIG_MPEG2DVD_MUXER -AVOutputFormat mpeg2dvd_muxer = { - "dvd", - "MPEG2 PS format (DVD VOB)", - "video/mpeg", - "dvd", - sizeof(MpegMuxContext), - CODEC_ID_MP2, - CODEC_ID_MPEG2VIDEO, - mpeg_mux_init, - mpeg_mux_write_packet, - mpeg_mux_end, -}; -#endif - -#ifdef CONFIG_MPEGPS_DEMUXER AVInputFormat mpegps_demuxer = { "mpeg", "MPEG PS format", @@ -1850,4 +578,3 @@ AVInputFormat mpegps_demuxer = { mpegps_read_dts, .flags = AVFMT_SHOW_IDS, }; -#endif diff --git a/contrib/ffmpeg/libavformat/mpeg.h b/contrib/ffmpeg/libavformat/mpeg.h new file mode 100644 index 000000000..9283101d1 --- /dev/null +++ b/contrib/ffmpeg/libavformat/mpeg.h @@ -0,0 +1,69 @@ +/* + * MPEG1/2 muxer and demuxer common defines + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. + * + * 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 FFMPEG_MPEG_H +#define FFMPEG_MPEG_H + +#define PACK_START_CODE ((unsigned int)0x000001ba) +#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb) +#define SEQUENCE_END_CODE ((unsigned int)0x000001b7) +#define PACKET_START_CODE_MASK ((unsigned int)0xffffff00) +#define PACKET_START_CODE_PREFIX ((unsigned int)0x00000100) +#define ISO_11172_END_CODE ((unsigned int)0x000001b9) + +/* mpeg2 */ +#define PROGRAM_STREAM_MAP 0x1bc +#define PRIVATE_STREAM_1 0x1bd +#define PADDING_STREAM 0x1be +#define PRIVATE_STREAM_2 0x1bf + +#define AUDIO_ID 0xc0 +#define VIDEO_ID 0xe0 +#define AC3_ID 0x80 +#define DTS_ID 0x8a +#define LPCM_ID 0xa0 +#define SUB_ID 0x20 + +#define STREAM_TYPE_VIDEO_MPEG1 0x01 +#define STREAM_TYPE_VIDEO_MPEG2 0x02 +#define STREAM_TYPE_AUDIO_MPEG1 0x03 +#define STREAM_TYPE_AUDIO_MPEG2 0x04 +#define STREAM_TYPE_PRIVATE_SECTION 0x05 +#define STREAM_TYPE_PRIVATE_DATA 0x06 +#define STREAM_TYPE_AUDIO_AAC 0x0f +#define STREAM_TYPE_VIDEO_MPEG4 0x10 +#define STREAM_TYPE_VIDEO_H264 0x1b + +#define STREAM_TYPE_AUDIO_AC3 0x81 +#define STREAM_TYPE_AUDIO_DTS 0x8a + +static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 }; + +/** + * Parse MPEG-PES five-byte timestamp + */ +static inline int64_t ff_parse_pes_pts(uint8_t *buf) { + return (int64_t)(*buf & 0x0e) << 29 | + (AV_RB16(buf+1) >> 1) << 15 | + AV_RB16(buf+3) >> 1; +} + +#endif /* FFMPEG_MPEG_H */ diff --git a/contrib/ffmpeg/libavformat/mpegenc.c b/contrib/ffmpeg/libavformat/mpegenc.c new file mode 100644 index 000000000..0558226b8 --- /dev/null +++ b/contrib/ffmpeg/libavformat/mpegenc.c @@ -0,0 +1,1294 @@ +/* + * MPEG1/2 muxer + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard. + * + * 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 "bitstream.h" +#include "fifo.h" +#include "mpeg.h" + +#define MAX_PAYLOAD_SIZE 4096 +//#define DEBUG_SEEK + +#undef NDEBUG +#include <assert.h> + +typedef struct PacketDesc { + int64_t pts; + int64_t dts; + int size; + int unwritten_size; + int flags; + struct PacketDesc *next; +} PacketDesc; + +typedef struct { + AVFifoBuffer fifo; + uint8_t id; + int max_buffer_size; /* in bytes */ + int buffer_index; + PacketDesc *predecode_packet; + PacketDesc *premux_packet; + PacketDesc **next_packet; + int packet_number; + uint8_t lpcm_header[3]; + int lpcm_align; + int bytes_to_iframe; + int align_iframe; + int64_t vobu_start_pts; +} StreamInfo; + +typedef struct { + int packet_size; /* required packet size */ + int packet_number; + int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */ + int system_header_freq; + int system_header_size; + int mux_rate; /* bitrate in units of 50 bytes/s */ + /* stream info */ + int audio_bound; + int video_bound; + int is_mpeg2; + int is_vcd; + int is_svcd; + int is_dvd; + int64_t last_scr; /* current system clock */ + + double vcd_padding_bitrate; //FIXME floats + int64_t vcd_padding_bytes_written; + +} MpegMuxContext; + +extern AVOutputFormat mpeg1vcd_muxer; +extern AVOutputFormat mpeg2dvd_muxer; +extern AVOutputFormat mpeg2svcd_muxer; +extern AVOutputFormat mpeg2vob_muxer; + +static int put_pack_header(AVFormatContext *ctx, + uint8_t *buf, int64_t timestamp) +{ + MpegMuxContext *s = ctx->priv_data; + PutBitContext pb; + + init_put_bits(&pb, buf, 128); + + put_bits(&pb, 32, PACK_START_CODE); + if (s->is_mpeg2) { + put_bits(&pb, 2, 0x1); + } else { + put_bits(&pb, 4, 0x2); + } + put_bits(&pb, 3, (uint32_t)((timestamp >> 30) & 0x07)); + put_bits(&pb, 1, 1); + put_bits(&pb, 15, (uint32_t)((timestamp >> 15) & 0x7fff)); + put_bits(&pb, 1, 1); + put_bits(&pb, 15, (uint32_t)((timestamp) & 0x7fff)); + put_bits(&pb, 1, 1); + if (s->is_mpeg2) { + /* clock extension */ + put_bits(&pb, 9, 0); + } + put_bits(&pb, 1, 1); + put_bits(&pb, 22, s->mux_rate); + put_bits(&pb, 1, 1); + if (s->is_mpeg2) { + put_bits(&pb, 1, 1); + put_bits(&pb, 5, 0x1f); /* reserved */ + put_bits(&pb, 3, 0); /* stuffing length */ + } + flush_put_bits(&pb); + return pbBufPtr(&pb) - pb.buf; +} + +static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_stream_id) +{ + MpegMuxContext *s = ctx->priv_data; + int size, i, private_stream_coded, id; + PutBitContext pb; + + init_put_bits(&pb, buf, 128); + + put_bits(&pb, 32, SYSTEM_HEADER_START_CODE); + put_bits(&pb, 16, 0); + put_bits(&pb, 1, 1); + + put_bits(&pb, 22, s->mux_rate); /* maximum bit rate of the multiplexed stream */ + put_bits(&pb, 1, 1); /* marker */ + if (s->is_vcd && only_for_stream_id==VIDEO_ID) { + /* This header applies only to the video stream (see VCD standard p. IV-7)*/ + put_bits(&pb, 6, 0); + } else + put_bits(&pb, 6, s->audio_bound); + + if (s->is_vcd) { + /* see VCD standard, p. IV-7*/ + put_bits(&pb, 1, 0); + put_bits(&pb, 1, 1); + } else { + put_bits(&pb, 1, 0); /* variable bitrate*/ + put_bits(&pb, 1, 0); /* non constrainted bit stream */ + } + + if (s->is_vcd || s->is_dvd) { + /* see VCD standard p IV-7 */ + put_bits(&pb, 1, 1); /* audio locked */ + put_bits(&pb, 1, 1); /* video locked */ + } else { + put_bits(&pb, 1, 0); /* audio locked */ + put_bits(&pb, 1, 0); /* video locked */ + } + + put_bits(&pb, 1, 1); /* marker */ + + if (s->is_vcd && only_for_stream_id==AUDIO_ID) { + /* This header applies only to the audio stream (see VCD standard p. IV-7)*/ + put_bits(&pb, 5, 0); + } else + put_bits(&pb, 5, s->video_bound); + + if (s->is_dvd) { + put_bits(&pb, 1, 0); /* packet_rate_restriction_flag */ + put_bits(&pb, 7, 0x7f); /* reserved byte */ + } else + put_bits(&pb, 8, 0xff); /* reserved byte */ + + /* DVD-Video Stream_bound entries + id (0xB9) video, maximum P-STD for stream 0xE0. (P-STD_buffer_bound_scale = 1) + id (0xB8) audio, maximum P-STD for any MPEG audio (0xC0 to 0xC7) streams. If there are none set to 4096 (32x128). (P-STD_buffer_bound_scale = 0) + id (0xBD) private stream 1 (audio other than MPEG and subpictures). (P-STD_buffer_bound_scale = 1) + id (0xBF) private stream 2, NAV packs, set to 2x1024. */ + if (s->is_dvd) { + + int P_STD_max_video = 0; + int P_STD_max_mpeg_audio = 0; + int P_STD_max_mpeg_PS1 = 0; + + for(i=0;i<ctx->nb_streams;i++) { + StreamInfo *stream = ctx->streams[i]->priv_data; + + id = stream->id; + if (id == 0xbd && stream->max_buffer_size > P_STD_max_mpeg_PS1) { + P_STD_max_mpeg_PS1 = stream->max_buffer_size; + } else if (id >= 0xc0 && id <= 0xc7 && stream->max_buffer_size > P_STD_max_mpeg_audio) { + P_STD_max_mpeg_audio = stream->max_buffer_size; + } else if (id == 0xe0 && stream->max_buffer_size > P_STD_max_video) { + P_STD_max_video = stream->max_buffer_size; + } + } + + /* video */ + put_bits(&pb, 8, 0xb9); /* stream ID */ + put_bits(&pb, 2, 3); + put_bits(&pb, 1, 1); + put_bits(&pb, 13, P_STD_max_video / 1024); + + /* audio */ + if (P_STD_max_mpeg_audio == 0) + P_STD_max_mpeg_audio = 4096; + put_bits(&pb, 8, 0xb8); /* stream ID */ + put_bits(&pb, 2, 3); + put_bits(&pb, 1, 0); + put_bits(&pb, 13, P_STD_max_mpeg_audio / 128); + + /* private stream 1 */ + put_bits(&pb, 8, 0xbd); /* stream ID */ + put_bits(&pb, 2, 3); + put_bits(&pb, 1, 0); + put_bits(&pb, 13, P_STD_max_mpeg_PS1 / 128); + + /* private stream 2 */ + put_bits(&pb, 8, 0xbf); /* stream ID */ + put_bits(&pb, 2, 3); + put_bits(&pb, 1, 1); + put_bits(&pb, 13, 2); + } + else { + /* audio stream info */ + private_stream_coded = 0; + for(i=0;i<ctx->nb_streams;i++) { + StreamInfo *stream = ctx->streams[i]->priv_data; + + + /* For VCDs, only include the stream info for the stream + that the pack which contains this system belongs to. + (see VCD standard p. IV-7) */ + if ( !s->is_vcd || stream->id==only_for_stream_id + || only_for_stream_id==0) { + + id = stream->id; + if (id < 0xc0) { + /* special case for private streams (AC3 use that) */ + if (private_stream_coded) + continue; + private_stream_coded = 1; + id = 0xbd; + } + put_bits(&pb, 8, id); /* stream ID */ + put_bits(&pb, 2, 3); + if (id < 0xe0) { + /* audio */ + put_bits(&pb, 1, 0); + put_bits(&pb, 13, stream->max_buffer_size / 128); + } else { + /* video */ + put_bits(&pb, 1, 1); + put_bits(&pb, 13, stream->max_buffer_size / 1024); + } + } + } + } + + flush_put_bits(&pb); + size = pbBufPtr(&pb) - pb.buf; + /* patch packet size */ + buf[4] = (size - 6) >> 8; + buf[5] = (size - 6) & 0xff; + + return size; +} + +static int get_system_header_size(AVFormatContext *ctx) +{ + int buf_index, i, private_stream_coded; + StreamInfo *stream; + MpegMuxContext *s = ctx->priv_data; + + if (s->is_dvd) + return 18; // DVD-Video system headers are 18 bytes fixed length. + + buf_index = 12; + private_stream_coded = 0; + for(i=0;i<ctx->nb_streams;i++) { + stream = ctx->streams[i]->priv_data; + if (stream->id < 0xc0) { + if (private_stream_coded) + continue; + private_stream_coded = 1; + } + buf_index += 3; + } + return buf_index; +} + +static int mpeg_mux_init(AVFormatContext *ctx) +{ + MpegMuxContext *s = ctx->priv_data; + int bitrate, i, mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id, j; + AVStream *st; + StreamInfo *stream; + int audio_bitrate; + int video_bitrate; + + s->packet_number = 0; + s->is_vcd = (ENABLE_MPEG1VCD_MUXER && ctx->oformat == &mpeg1vcd_muxer); + s->is_svcd = (ENABLE_MPEG2SVCD_MUXER && ctx->oformat == &mpeg2svcd_muxer); + s->is_mpeg2 = ((ENABLE_MPEG2VOB_MUXER && ctx->oformat == &mpeg2vob_muxer) || + (ENABLE_MPEG2DVD_MUXER && ctx->oformat == &mpeg2dvd_muxer) || + (ENABLE_MPEG2SVCD_MUXER && ctx->oformat == &mpeg2svcd_muxer)); + s->is_dvd = (ENABLE_MPEG2DVD_MUXER && ctx->oformat == &mpeg2dvd_muxer); + + if(ctx->packet_size) + s->packet_size = ctx->packet_size; + else + s->packet_size = 2048; + + s->vcd_padding_bytes_written = 0; + s->vcd_padding_bitrate=0; + + s->audio_bound = 0; + s->video_bound = 0; + mpa_id = AUDIO_ID; + ac3_id = AC3_ID; + dts_id = DTS_ID; + mpv_id = VIDEO_ID; + mps_id = SUB_ID; + lpcm_id = LPCM_ID; + for(i=0;i<ctx->nb_streams;i++) { + st = ctx->streams[i]; + stream = av_mallocz(sizeof(StreamInfo)); + if (!stream) + goto fail; + st->priv_data = stream; + + av_set_pts_info(st, 64, 1, 90000); + + switch(st->codec->codec_type) { + case CODEC_TYPE_AUDIO: + if (st->codec->codec_id == CODEC_ID_AC3) { + stream->id = ac3_id++; + } else if (st->codec->codec_id == CODEC_ID_DTS) { + stream->id = dts_id++; + } else if (st->codec->codec_id == CODEC_ID_PCM_S16BE) { + stream->id = lpcm_id++; + for(j = 0; j < 4; j++) { + if (lpcm_freq_tab[j] == st->codec->sample_rate) + break; + } + if (j == 4) + goto fail; + if (st->codec->channels > 8) + return -1; + stream->lpcm_header[0] = 0x0c; + stream->lpcm_header[1] = (st->codec->channels - 1) | (j << 4); + stream->lpcm_header[2] = 0x80; + stream->lpcm_align = st->codec->channels * 2; + } else { + stream->id = mpa_id++; + } + + /* This value HAS to be used for VCD (see VCD standard, p. IV-7). + Right now it is also used for everything else.*/ + stream->max_buffer_size = 4 * 1024; + s->audio_bound++; + break; + case CODEC_TYPE_VIDEO: + stream->id = mpv_id++; + if (st->codec->rc_buffer_size) + stream->max_buffer_size = 6*1024 + st->codec->rc_buffer_size/8; + else + stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default +#if 0 + /* see VCD standard, p. IV-7*/ + stream->max_buffer_size = 46 * 1024; + else + /* This value HAS to be used for SVCD (see SVCD standard, p. 26 V.2.3.2). + Right now it is also used for everything else.*/ + stream->max_buffer_size = 230 * 1024; +#endif + s->video_bound++; + break; + case CODEC_TYPE_SUBTITLE: + stream->id = mps_id++; + stream->max_buffer_size = 16 * 1024; + break; + default: + return -1; + } + av_fifo_init(&stream->fifo, 16); + } + bitrate = 0; + audio_bitrate = 0; + video_bitrate = 0; + for(i=0;i<ctx->nb_streams;i++) { + int codec_rate; + st = ctx->streams[i]; + stream = (StreamInfo*) st->priv_data; + + if(st->codec->rc_max_rate || stream->id==VIDEO_ID) + codec_rate= st->codec->rc_max_rate; + else + codec_rate= st->codec->bit_rate; + + if(!codec_rate) + codec_rate= (1<<21)*8*50/ctx->nb_streams; + + bitrate += codec_rate; + + if (stream->id==AUDIO_ID) + audio_bitrate += codec_rate; + else if (stream->id==VIDEO_ID) + video_bitrate += codec_rate; + } + + if(ctx->mux_rate){ + s->mux_rate= (ctx->mux_rate + (8 * 50) - 1) / (8 * 50); + } else { + /* we increase slightly the bitrate to take into account the + headers. XXX: compute it exactly */ + bitrate += bitrate*5/100; + bitrate += 10000; + s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); + } + + if (s->is_vcd) { + double overhead_rate; + + /* The VCD standard mandates that the mux_rate field is 3528 + (see standard p. IV-6). + The value is actually "wrong", i.e. if you calculate + it using the normal formula and the 75 sectors per second transfer + rate you get a different value because the real pack size is 2324, + not 2352. But the standard explicitly specifies that the mux_rate + field in the header must have this value.*/ +// s->mux_rate=2352 * 75 / 50; /* = 3528*/ + + /* The VCD standard states that the muxed stream must be + exactly 75 packs / second (the data rate of a single speed cdrom). + Since the video bitrate (probably 1150000 bits/sec) will be below + the theoretical maximum we have to add some padding packets + to make up for the lower data rate. + (cf. VCD standard p. IV-6 )*/ + + /* Add the header overhead to the data rate. + 2279 data bytes per audio pack, 2294 data bytes per video pack*/ + overhead_rate = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279); + overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294); + overhead_rate *= 8; + + /* Add padding so that the full bitrate is 2324*75 bytes/sec */ + s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate); + } + + if (s->is_vcd || s->is_mpeg2) + /* every packet */ + s->pack_header_freq = 1; + else + /* every 2 seconds */ + s->pack_header_freq = 2 * bitrate / s->packet_size / 8; + + /* the above seems to make pack_header_freq zero sometimes */ + if (s->pack_header_freq == 0) + s->pack_header_freq = 1; + + if (s->is_mpeg2) + /* every 200 packets. Need to look at the spec. */ + s->system_header_freq = s->pack_header_freq * 40; + else if (s->is_vcd) + /* the standard mandates that there are only two system headers + in the whole file: one in the first packet of each stream. + (see standard p. IV-7 and IV-8) */ + s->system_header_freq = 0x7fffffff; + else + s->system_header_freq = s->pack_header_freq * 5; + + for(i=0;i<ctx->nb_streams;i++) { + stream = ctx->streams[i]->priv_data; + stream->packet_number = 0; + } + s->system_header_size = get_system_header_size(ctx); + s->last_scr = 0; + return 0; + fail: + for(i=0;i<ctx->nb_streams;i++) { + av_free(ctx->streams[i]->priv_data); + } + return AVERROR(ENOMEM); +} + +static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp) +{ + put_byte(pb, + (id << 4) | + (((timestamp >> 30) & 0x07) << 1) | + 1); + put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1)); + put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1)); +} + + +/* return the number of padding bytes that should be inserted into + the multiplexed stream.*/ +static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts) +{ + MpegMuxContext *s = ctx->priv_data; + int pad_bytes = 0; + + if (s->vcd_padding_bitrate > 0 && pts!=AV_NOPTS_VALUE) + { + int64_t full_pad_bytes; + + full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); //FIXME this is wrong + pad_bytes = (int) (full_pad_bytes - s->vcd_padding_bytes_written); + + if (pad_bytes<0) + /* might happen if we have already padded to a later timestamp. This + can occur if another stream has already advanced further.*/ + pad_bytes=0; + } + + return pad_bytes; +} + + +#if 0 /* unused, remove? */ +/* return the exact available payload size for the next packet for + stream 'stream_index'. 'pts' and 'dts' are only used to know if + timestamps are needed in the packet header. */ +static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, + int64_t pts, int64_t dts) +{ + MpegMuxContext *s = ctx->priv_data; + int buf_index; + StreamInfo *stream; + + stream = ctx->streams[stream_index]->priv_data; + + buf_index = 0; + if (((s->packet_number % s->pack_header_freq) == 0)) { + /* pack header size */ + if (s->is_mpeg2) + buf_index += 14; + else + buf_index += 12; + + if (s->is_vcd) { + /* there is exactly one system header for each stream in a VCD MPEG, + One in the very first video packet and one in the very first + audio packet (see VCD standard p. IV-7 and IV-8).*/ + + if (stream->packet_number==0) + /* The system headers refer only to the stream they occur in, + so they have a constant size.*/ + buf_index += 15; + + } else { + if ((s->packet_number % s->system_header_freq) == 0) + buf_index += s->system_header_size; + } + } + + if ((s->is_vcd && stream->packet_number==0) + || (s->is_svcd && s->packet_number==0)) + /* the first pack of each stream contains only the pack header, + the system header and some padding (see VCD standard p. IV-6) + Add the padding size, so that the actual payload becomes 0.*/ + buf_index += s->packet_size - buf_index; + else { + /* packet header size */ + buf_index += 6; + if (s->is_mpeg2) { + buf_index += 3; + if (stream->packet_number==0) + buf_index += 3; /* PES extension */ + buf_index += 1; /* obligatory stuffing byte */ + } + if (pts != AV_NOPTS_VALUE) { + if (dts != pts) + buf_index += 5 + 5; + else + buf_index += 5; + + } else { + if (!s->is_mpeg2) + buf_index++; + } + + if (stream->id < 0xc0) { + /* AC3/LPCM private data header */ + buf_index += 4; + if (stream->id >= 0xa0) { + int n; + buf_index += 3; + /* NOTE: we round the payload size to an integer number of + LPCM samples */ + n = (s->packet_size - buf_index) % stream->lpcm_align; + if (n) + buf_index += (stream->lpcm_align - n); + } + } + + if (s->is_vcd && stream->id == AUDIO_ID) + /* The VCD standard demands that 20 zero bytes follow + each audio packet (see standard p. IV-8).*/ + buf_index+=20; + } + return s->packet_size - buf_index; +} +#endif + +/* Write an MPEG padding packet header. */ +static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes) +{ + MpegMuxContext *s = ctx->priv_data; + int i; + + put_be32(pb, PADDING_STREAM); + put_be16(pb, packet_bytes - 6); + if (!s->is_mpeg2) { + put_byte(pb, 0x0f); + packet_bytes -= 7; + } else + packet_bytes -= 6; + + for(i=0;i<packet_bytes;i++) + put_byte(pb, 0xff); +} + +static int get_nb_frames(AVFormatContext *ctx, StreamInfo *stream, int len){ + int nb_frames=0; + PacketDesc *pkt_desc= stream->premux_packet; + + while(len>0){ + if(pkt_desc->size == pkt_desc->unwritten_size) + nb_frames++; + len -= pkt_desc->unwritten_size; + pkt_desc= pkt_desc->next; + } + + return nb_frames; +} + +/* flush the packet on stream stream_index */ +static int flush_packet(AVFormatContext *ctx, int stream_index, + int64_t pts, int64_t dts, int64_t scr, int trailer_size) +{ + MpegMuxContext *s = ctx->priv_data; + StreamInfo *stream = ctx->streams[stream_index]->priv_data; + uint8_t *buf_ptr; + int size, payload_size, startcode, id, stuffing_size, i, header_len; + int packet_size; + uint8_t buffer[128]; + int zero_trail_bytes = 0; + int pad_packet_bytes = 0; + int pes_flags; + int general_pack = 0; /*"general" pack without data specific to one stream?*/ + int nb_frames; + + id = stream->id; + +#if 0 + printf("packet ID=%2x PTS=%0.3f\n", + id, pts / 90000.0); +#endif + + buf_ptr = buffer; + + if ((s->packet_number % s->pack_header_freq) == 0 || s->last_scr != scr) { + /* output pack and systems header if needed */ + size = put_pack_header(ctx, buf_ptr, scr); + buf_ptr += size; + s->last_scr= scr; + + if (s->is_vcd) { + /* there is exactly one system header for each stream in a VCD MPEG, + One in the very first video packet and one in the very first + audio packet (see VCD standard p. IV-7 and IV-8).*/ + + if (stream->packet_number==0) { + size = put_system_header(ctx, buf_ptr, id); + buf_ptr += size; + } + } else if (s->is_dvd) { + if (stream->align_iframe || s->packet_number == 0){ + int PES_bytes_to_fill = s->packet_size - size - 10; + + if (pts != AV_NOPTS_VALUE) { + if (dts != pts) + PES_bytes_to_fill -= 5 + 5; + else + PES_bytes_to_fill -= 5; + } + + if (stream->bytes_to_iframe == 0 || s->packet_number == 0) { + size = put_system_header(ctx, buf_ptr, 0); + buf_ptr += size; + size = buf_ptr - buffer; + put_buffer(ctx->pb, buffer, size); + + put_be32(ctx->pb, PRIVATE_STREAM_2); + put_be16(ctx->pb, 0x03d4); // length + put_byte(ctx->pb, 0x00); // substream ID, 00=PCI + for (i = 0; i < 979; i++) + put_byte(ctx->pb, 0x00); + + put_be32(ctx->pb, PRIVATE_STREAM_2); + put_be16(ctx->pb, 0x03fa); // length + put_byte(ctx->pb, 0x01); // substream ID, 01=DSI + for (i = 0; i < 1017; i++) + put_byte(ctx->pb, 0x00); + + memset(buffer, 0, 128); + buf_ptr = buffer; + s->packet_number++; + stream->align_iframe = 0; + scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet + size = put_pack_header(ctx, buf_ptr, scr); + s->last_scr= scr; + buf_ptr += size; + /* GOP Start */ + } else if (stream->bytes_to_iframe < PES_bytes_to_fill) { + pad_packet_bytes = PES_bytes_to_fill - stream->bytes_to_iframe; + } + } + } else { + if ((s->packet_number % s->system_header_freq) == 0) { + size = put_system_header(ctx, buf_ptr, 0); + buf_ptr += size; + } + } + } + size = buf_ptr - buffer; + put_buffer(ctx->pb, buffer, size); + + packet_size = s->packet_size - size; + + if (s->is_vcd && id == AUDIO_ID) + /* The VCD standard demands that 20 zero bytes follow + each audio pack (see standard p. IV-8).*/ + zero_trail_bytes += 20; + + if ((s->is_vcd && stream->packet_number==0) + || (s->is_svcd && s->packet_number==0)) { + /* for VCD the first pack of each stream contains only the pack header, + the system header and lots of padding (see VCD standard p. IV-6). + In the case of an audio pack, 20 zero bytes are also added at + the end.*/ + /* For SVCD we fill the very first pack to increase compatibility with + some DVD players. Not mandated by the standard.*/ + if (s->is_svcd) + general_pack = 1; /* the system header refers to both streams and no stream data*/ + pad_packet_bytes = packet_size - zero_trail_bytes; + } + + packet_size -= pad_packet_bytes + zero_trail_bytes; + + if (packet_size > 0) { + + /* packet header size */ + packet_size -= 6; + + /* packet header */ + if (s->is_mpeg2) { + header_len = 3; + if (stream->packet_number==0) + header_len += 3; /* PES extension */ + header_len += 1; /* obligatory stuffing byte */ + } else { + header_len = 0; + } + if (pts != AV_NOPTS_VALUE) { + if (dts != pts) + header_len += 5 + 5; + else + header_len += 5; + } else { + if (!s->is_mpeg2) + header_len++; + } + + payload_size = packet_size - header_len; + if (id < 0xc0) { + startcode = PRIVATE_STREAM_1; + payload_size -= 1; + if (id >= 0x40) { + payload_size -= 3; + if (id >= 0xa0) + payload_size -= 3; + } + } else { + startcode = 0x100 + id; + } + + stuffing_size = payload_size - av_fifo_size(&stream->fifo); + + // first byte does not fit -> reset pts/dts + stuffing + if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){ + int timestamp_len=0; + if(dts != pts) + timestamp_len += 5; + if(pts != AV_NOPTS_VALUE) + timestamp_len += s->is_mpeg2 ? 5 : 4; + pts=dts= AV_NOPTS_VALUE; + header_len -= timestamp_len; + if (s->is_dvd && stream->align_iframe) { + pad_packet_bytes += timestamp_len; + packet_size -= timestamp_len; + } else { + payload_size += timestamp_len; + } + stuffing_size += timestamp_len; + if(payload_size > trailer_size) + stuffing_size += payload_size - trailer_size; + } + + if (pad_packet_bytes > 0 && pad_packet_bytes <= 7) { // can't use padding, so use stuffing + packet_size += pad_packet_bytes; + payload_size += pad_packet_bytes; // undo the previous adjustment + if (stuffing_size < 0) { + stuffing_size = pad_packet_bytes; + } else { + stuffing_size += pad_packet_bytes; + } + pad_packet_bytes = 0; + } + + if (stuffing_size < 0) + stuffing_size = 0; + if (stuffing_size > 16) { /*<=16 for MPEG-1, <=32 for MPEG-2*/ + pad_packet_bytes += stuffing_size; + packet_size -= stuffing_size; + payload_size -= stuffing_size; + stuffing_size = 0; + } + + nb_frames= get_nb_frames(ctx, stream, payload_size - stuffing_size); + + put_be32(ctx->pb, startcode); + + put_be16(ctx->pb, packet_size); + + if (!s->is_mpeg2) + for(i=0;i<stuffing_size;i++) + put_byte(ctx->pb, 0xff); + + if (s->is_mpeg2) { + put_byte(ctx->pb, 0x80); /* mpeg2 id */ + + pes_flags=0; + + if (pts != AV_NOPTS_VALUE) { + pes_flags |= 0x80; + if (dts != pts) + pes_flags |= 0x40; + } + + /* Both the MPEG-2 and the SVCD standards demand that the + P-STD_buffer_size field be included in the first packet of + every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2 + and MPEG-2 standard 2.7.7) */ + if (stream->packet_number == 0) + pes_flags |= 0x01; + + put_byte(ctx->pb, pes_flags); /* flags */ + put_byte(ctx->pb, header_len - 3 + stuffing_size); + + if (pes_flags & 0x80) /*write pts*/ + put_timestamp(ctx->pb, (pes_flags & 0x40) ? 0x03 : 0x02, pts); + if (pes_flags & 0x40) /*write dts*/ + put_timestamp(ctx->pb, 0x01, dts); + + if (pes_flags & 0x01) { /*write pes extension*/ + put_byte(ctx->pb, 0x10); /* flags */ + + /* P-STD buffer info */ + if (id == AUDIO_ID) + put_be16(ctx->pb, 0x4000 | stream->max_buffer_size/128); + else + put_be16(ctx->pb, 0x6000 | stream->max_buffer_size/1024); + } + + } else { + if (pts != AV_NOPTS_VALUE) { + if (dts != pts) { + put_timestamp(ctx->pb, 0x03, pts); + put_timestamp(ctx->pb, 0x01, dts); + } else { + put_timestamp(ctx->pb, 0x02, pts); + } + } else { + put_byte(ctx->pb, 0x0f); + } + } + + if (s->is_mpeg2) { + /* special stuffing byte that is always written + to prevent accidental generation of start codes. */ + put_byte(ctx->pb, 0xff); + + for(i=0;i<stuffing_size;i++) + put_byte(ctx->pb, 0xff); + } + + if (startcode == PRIVATE_STREAM_1) { + put_byte(ctx->pb, id); + if (id >= 0xa0) { + /* LPCM (XXX: check nb_frames) */ + put_byte(ctx->pb, 7); + put_be16(ctx->pb, 4); /* skip 3 header bytes */ + put_byte(ctx->pb, stream->lpcm_header[0]); + put_byte(ctx->pb, stream->lpcm_header[1]); + put_byte(ctx->pb, stream->lpcm_header[2]); + } else if (id >= 0x40) { + /* AC3 */ + put_byte(ctx->pb, nb_frames); + put_be16(ctx->pb, trailer_size+1); + } + } + + /* output data */ + if(av_fifo_generic_read(&stream->fifo, payload_size - stuffing_size, &put_buffer, ctx->pb) < 0) + return -1; + stream->bytes_to_iframe -= payload_size - stuffing_size; + }else{ + payload_size= + stuffing_size= 0; + } + + if (pad_packet_bytes > 0) + put_padding_packet(ctx,ctx->pb, pad_packet_bytes); + + for(i=0;i<zero_trail_bytes;i++) + put_byte(ctx->pb, 0x00); + + put_flush_packet(ctx->pb); + + s->packet_number++; + + /* only increase the stream packet number if this pack actually contains + something that is specific to this stream! I.e. a dedicated header + or some data.*/ + if (!general_pack) + stream->packet_number++; + + return payload_size - stuffing_size; +} + +static void put_vcd_padding_sector(AVFormatContext *ctx) +{ + /* There are two ways to do this padding: writing a sector/pack + of 0 values, or writing an MPEG padding pack. Both seem to + work with most decoders, BUT the VCD standard only allows a 0-sector + (see standard p. IV-4, IV-5). + So a 0-sector it is...*/ + + MpegMuxContext *s = ctx->priv_data; + int i; + + for(i=0;i<s->packet_size;i++) + put_byte(ctx->pb, 0); + + s->vcd_padding_bytes_written += s->packet_size; + + put_flush_packet(ctx->pb); + + /* increasing the packet number is correct. The SCR of the following packs + is calculated from the packet_number and it has to include the padding + sector (it represents the sector index, not the MPEG pack index) + (see VCD standard p. IV-6)*/ + s->packet_number++; +} + +#if 0 /* unused, remove? */ +static int64_t get_vcd_scr(AVFormatContext *ctx,int stream_index,int64_t pts) +{ + MpegMuxContext *s = ctx->priv_data; + int64_t scr; + + /* Since the data delivery rate is constant, SCR is computed + using the formula C + i * 1200 where C is the start constant + and i is the pack index. + It is recommended that SCR 0 is at the beginning of the VCD front + margin (a sequence of empty Form 2 sectors on the CD). + It is recommended that the front margin is 30 sectors long, so + we use C = 30*1200 = 36000 + (Note that even if the front margin is not 30 sectors the file + will still be correct according to the standard. It just won't have + the "recommended" value).*/ + scr = 36000 + s->packet_number * 1200; + + return scr; +} +#endif + +static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr){ +// MpegMuxContext *s = ctx->priv_data; + int i; + + for(i=0; i<ctx->nb_streams; i++){ + AVStream *st = ctx->streams[i]; + StreamInfo *stream = st->priv_data; + PacketDesc *pkt_desc; + + while((pkt_desc= stream->predecode_packet) + && scr > pkt_desc->dts){ //FIXME > vs >= + if(stream->buffer_index < pkt_desc->size || + stream->predecode_packet == stream->premux_packet){ + av_log(ctx, AV_LOG_ERROR, + "buffer underflow i=%d bufi=%d size=%d\n", + i, stream->buffer_index, pkt_desc->size); + break; + } + stream->buffer_index -= pkt_desc->size; + + stream->predecode_packet= pkt_desc->next; + av_freep(&pkt_desc); + } + } + + return 0; +} + +static int output_packet(AVFormatContext *ctx, int flush){ + MpegMuxContext *s = ctx->priv_data; + AVStream *st; + StreamInfo *stream; + int i, avail_space=0, es_size, trailer_size; + int best_i= -1; + int best_score= INT_MIN; + int ignore_constraints=0; + int64_t scr= s->last_scr; + PacketDesc *timestamp_packet; + const int64_t max_delay= av_rescale(ctx->max_delay, 90000, AV_TIME_BASE); + +retry: + for(i=0; i<ctx->nb_streams; i++){ + AVStream *st = ctx->streams[i]; + 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; + PacketDesc *next_pkt= stream->premux_packet; + + /* for subtitle, a single PES packet must be generated, + so we flush after every single subtitle packet */ + if(s->packet_size > avail_data && !flush + && st->codec->codec_type != CODEC_TYPE_SUBTITLE) + return 0; + if(avail_data==0) + continue; + assert(avail_data>0); + + if(space < s->packet_size && !ignore_constraints) + continue; + + if(next_pkt && next_pkt->dts - scr > max_delay) + continue; + + if(rel_space > best_score){ + best_score= rel_space; + best_i = i; + avail_space= space; + } + } + + if(best_i < 0){ + int64_t best_dts= INT64_MAX; + + for(i=0; i<ctx->nb_streams; i++){ + AVStream *st = ctx->streams[i]; + StreamInfo *stream = st->priv_data; + PacketDesc *pkt_desc= stream->predecode_packet; + if(pkt_desc && pkt_desc->dts < best_dts) + best_dts= pkt_desc->dts; + } + +#if 0 + av_log(ctx, AV_LOG_DEBUG, "bumping scr, scr:%f, dts:%f\n", + scr/90000.0, best_dts/90000.0); +#endif + if(best_dts == INT64_MAX) + return 0; + + if(scr >= best_dts+1 && !ignore_constraints){ + av_log(ctx, AV_LOG_ERROR, "packet too large, ignoring buffer limits to mux it\n"); + ignore_constraints= 1; + } + scr= FFMAX(best_dts+1, scr); + if(remove_decoded_packets(ctx, scr) < 0) + return -1; + goto retry; + } + + assert(best_i >= 0); + + st = ctx->streams[best_i]; + stream = st->priv_data; + + assert(av_fifo_size(&stream->fifo) > 0); + + assert(avail_space >= s->packet_size || ignore_constraints); + + timestamp_packet= stream->premux_packet; + if(timestamp_packet->unwritten_size == timestamp_packet->size){ + trailer_size= 0; + }else{ + trailer_size= timestamp_packet->unwritten_size; + timestamp_packet= timestamp_packet->next; + } + + if(timestamp_packet){ +//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f scr:%f stream:%d\n", timestamp_packet->dts/90000.0, timestamp_packet->pts/90000.0, scr/90000.0, best_i); + es_size= flush_packet(ctx, best_i, timestamp_packet->pts, timestamp_packet->dts, scr, trailer_size); + }else{ + assert(av_fifo_size(&stream->fifo) == trailer_size); + es_size= flush_packet(ctx, best_i, AV_NOPTS_VALUE, AV_NOPTS_VALUE, scr, trailer_size); + } + + if (s->is_vcd) { + /* Write one or more padding sectors, if necessary, to reach + the constant overall bitrate.*/ + int vcd_pad_bytes; + + while((vcd_pad_bytes = get_vcd_padding_size(ctx,stream->premux_packet->pts) ) >= s->packet_size){ //FIXME pts cannot be correct here + put_vcd_padding_sector(ctx); + s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet + } + } + + stream->buffer_index += es_size; + s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet + + while(stream->premux_packet && stream->premux_packet->unwritten_size <= es_size){ + es_size -= stream->premux_packet->unwritten_size; + stream->premux_packet= stream->premux_packet->next; + } + if(es_size) + stream->premux_packet->unwritten_size -= es_size; + + if(remove_decoded_packets(ctx, s->last_scr) < 0) + return -1; + + return 1; +} + +static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) +{ + MpegMuxContext *s = ctx->priv_data; + int stream_index= pkt->stream_index; + int size= pkt->size; + uint8_t *buf= pkt->data; + AVStream *st = ctx->streams[stream_index]; + StreamInfo *stream = st->priv_data; + int64_t pts, dts; + PacketDesc *pkt_desc; + const int preload= av_rescale(ctx->preload, 90000, AV_TIME_BASE); + const int is_iframe = st->codec->codec_type == CODEC_TYPE_VIDEO && (pkt->flags & PKT_FLAG_KEY); + + pts= pkt->pts; + dts= pkt->dts; + + if(pts != AV_NOPTS_VALUE) pts += preload; + if(dts != AV_NOPTS_VALUE) dts += preload; + +//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f flags:%d stream:%d nopts:%d\n", dts/90000.0, pts/90000.0, pkt->flags, pkt->stream_index, pts != AV_NOPTS_VALUE); + if (!stream->premux_packet) + stream->next_packet = &stream->premux_packet; + *stream->next_packet= + pkt_desc= av_mallocz(sizeof(PacketDesc)); + pkt_desc->pts= pts; + pkt_desc->dts= dts; + pkt_desc->unwritten_size= + pkt_desc->size= size; + if(!stream->predecode_packet) + stream->predecode_packet= pkt_desc; + stream->next_packet= &pkt_desc->next; + + av_fifo_realloc(&stream->fifo, av_fifo_size(&stream->fifo) + size + 1); + + if (s->is_dvd){ + if (is_iframe && (s->packet_number == 0 || (pts - stream->vobu_start_pts >= 36000))) { // min VOBU length 0.4 seconds (mpucoder) + stream->bytes_to_iframe = av_fifo_size(&stream->fifo); + stream->align_iframe = 1; + stream->vobu_start_pts = pts; + } + } + + av_fifo_write(&stream->fifo, buf, size); + + for(;;){ + int ret= output_packet(ctx, 0); + if(ret<=0) + return ret; + } +} + +static int mpeg_mux_end(AVFormatContext *ctx) +{ +// MpegMuxContext *s = ctx->priv_data; + StreamInfo *stream; + int i; + + for(;;){ + int ret= output_packet(ctx, 1); + if(ret<0) + return ret; + else if(ret==0) + break; + } + + /* End header according to MPEG1 systems standard. We do not write + it as it is usually not needed by decoders and because it + complicates MPEG stream concatenation. */ + //put_be32(ctx->pb, ISO_11172_END_CODE); + //put_flush_packet(ctx->pb); + + for(i=0;i<ctx->nb_streams;i++) { + stream = ctx->streams[i]->priv_data; + + assert(av_fifo_size(&stream->fifo) == 0); + av_fifo_free(&stream->fifo); + } + return 0; +} + +#ifdef CONFIG_MPEG1SYSTEM_MUXER +AVOutputFormat mpeg1system_muxer = { + "mpeg", + "MPEG1 System format", + "video/mpeg", + "mpg,mpeg", + sizeof(MpegMuxContext), + CODEC_ID_MP2, + CODEC_ID_MPEG1VIDEO, + mpeg_mux_init, + mpeg_mux_write_packet, + mpeg_mux_end, +}; +#endif +#ifdef CONFIG_MPEG1VCD_MUXER +AVOutputFormat mpeg1vcd_muxer = { + "vcd", + "MPEG1 System format (VCD)", + "video/mpeg", + NULL, + sizeof(MpegMuxContext), + CODEC_ID_MP2, + CODEC_ID_MPEG1VIDEO, + mpeg_mux_init, + mpeg_mux_write_packet, + mpeg_mux_end, +}; +#endif +#ifdef CONFIG_MPEG2VOB_MUXER +AVOutputFormat mpeg2vob_muxer = { + "vob", + "MPEG2 PS format (VOB)", + "video/mpeg", + "vob", + sizeof(MpegMuxContext), + CODEC_ID_MP2, + CODEC_ID_MPEG2VIDEO, + mpeg_mux_init, + mpeg_mux_write_packet, + mpeg_mux_end, +}; +#endif + +/* Same as mpeg2vob_mux except that the pack size is 2324 */ +#ifdef CONFIG_MPEG2SVCD_MUXER +AVOutputFormat mpeg2svcd_muxer = { + "svcd", + "MPEG2 PS format (VOB)", + "video/mpeg", + "vob", + sizeof(MpegMuxContext), + CODEC_ID_MP2, + CODEC_ID_MPEG2VIDEO, + mpeg_mux_init, + mpeg_mux_write_packet, + mpeg_mux_end, +}; +#endif + +/* Same as mpeg2vob_mux except the 'is_dvd' flag is set to produce NAV pkts */ +#ifdef CONFIG_MPEG2DVD_MUXER +AVOutputFormat mpeg2dvd_muxer = { + "dvd", + "MPEG2 PS format (DVD VOB)", + "video/mpeg", + "dvd", + sizeof(MpegMuxContext), + CODEC_ID_MP2, + CODEC_ID_MPEG2VIDEO, + mpeg_mux_init, + mpeg_mux_write_packet, + mpeg_mux_end, +}; +#endif diff --git a/contrib/ffmpeg/libavformat/mpegts.c b/contrib/ffmpeg/libavformat/mpegts.c index c466710ee..ab046199a 100644 --- a/contrib/ffmpeg/libavformat/mpegts.c +++ b/contrib/ffmpeg/libavformat/mpegts.c @@ -31,25 +31,30 @@ /* maximum size in which we look for synchronisation if synchronisation is lost */ #define MAX_RESYNC_SIZE 4096 +#define REGISTRATION_DESCRIPTOR 5 typedef struct PESContext PESContext; -static PESContext* add_pes_stream(MpegTSContext *ts, int pid, int stream_type); +static PESContext* add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid, int stream_type); static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code); +extern void av_set_program_name(AVProgram *program, char *provider_name, char *name); +extern void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx); enum MpegTSFilterType { MPEGTS_PES, MPEGTS_SECTION, }; -typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start); +typedef struct MpegTSFilter MpegTSFilter; + +typedef void PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start); typedef struct MpegTSPESFilter { PESCallback *pes_cb; void *opaque; } MpegTSPESFilter; -typedef void SectionCallback(void *opaque, const uint8_t *buf, int len); +typedef void SectionCallback(MpegTSFilter *f, const uint8_t *buf, int len); typedef void SetServiceCallback(void *opaque, int ret); @@ -63,7 +68,7 @@ typedef struct MpegTSSectionFilter { void *opaque; } MpegTSSectionFilter; -typedef struct MpegTSFilter { +struct MpegTSFilter { int pid; int last_cc; /* last cc code (-1 if first packet) */ enum MpegTSFilterType type; @@ -71,14 +76,14 @@ typedef struct MpegTSFilter { MpegTSPESFilter pes_filter; MpegTSSectionFilter section_filter; } u; -} MpegTSFilter; +}; -typedef struct MpegTSService { - int running:1; - int sid; /**< MPEG Program Number of stream */ - char *provider_name; /**< DVB Network name, "" if not DVB stream */ - char *name; /**< DVB Service name, "MPEG Program [sid]" if not DVB stream*/ -} MpegTSService; +#define MAX_PIDS_PER_PROGRAM 64 +typedef struct { + unsigned int id; //program id/service id + unsigned int nb_pids; + unsigned int pids[MAX_PIDS_PER_PROGRAM]; +} Program_t; struct MpegTSContext { /* user data */ @@ -87,16 +92,12 @@ struct MpegTSContext { int raw_packet_size; /** if true, all pids are analyzed to find streams */ int auto_guess; - int set_service_ret; - /** force raw MPEG2 transport stream output, if possible */ - int mpeg2ts_raw; /** compute exact PCR for each transport stream packet */ int mpeg2ts_compute_pcr; int64_t cur_pcr; /**< used to estimate the exact PCR */ int pcr_incr; /**< used to estimate the exact PCR */ - int pcr_pid; /**< used to estimate the exact PCR */ /* data needed to handle file based ts */ /** stop parsing loop */ @@ -107,26 +108,125 @@ struct MpegTSContext { /******************************************/ /* private mpegts data */ /* scan context */ - MpegTSFilter *sdt_filter; - /** number of PMTs in the last PAT seen */ - int nb_services; - /** list of PMTs in the last PAT seen */ - MpegTSService **services; - - /* set service context (XXX: allocated it ?) */ - SetServiceCallback *set_service_cb; - void *set_service_opaque; - /** filter for the PAT */ - MpegTSFilter *pat_filter; - /** filter for the PMT for the MPEG program number specified by req_sid */ - MpegTSFilter *pmt_filter; - /** MPEG program number of stream we want to decode */ - int req_sid; + /** structure to keep track of Program->pids mapping */ + unsigned int nb_prg; + Program_t *prg; + /** filters for various streams specified by PMT + for the PAT and PMT */ MpegTSFilter *pids[NB_PID_MAX]; }; +/* TS stream handling */ + +enum MpegTSState { + MPEGTS_HEADER = 0, + MPEGTS_PESHEADER_FILL, + MPEGTS_PAYLOAD, + MPEGTS_SKIP, +}; + +/* enough for PES header + length */ +#define PES_START_SIZE 9 +#define MAX_PES_HEADER_SIZE (9 + 255) + +struct PESContext { + int pid; + int pcr_pid; /**< if -1 then all packets containing PCR are considered */ + int stream_type; + MpegTSContext *ts; + AVFormatContext *stream; + AVStream *st; + enum MpegTSState state; + /* used to get the format */ + int data_index; + int total_size; + int pes_header_size; + int64_t pts, dts; + uint8_t header[MAX_PES_HEADER_SIZE]; +}; + +extern AVInputFormat mpegts_demuxer; + +static void clear_program(MpegTSContext *ts, unsigned int programid) +{ + int i; + + for(i=0; i<ts->nb_prg; i++) + if(ts->prg[i].id == programid) + ts->prg[i].nb_pids = 0; +} + +static void clear_programs(MpegTSContext *ts) +{ + av_freep(&ts->prg); + ts->nb_prg=0; +} + +static void add_pat_entry(MpegTSContext *ts, unsigned int programid) +{ + Program_t *p; + void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(Program_t)); + if(!tmp) + return; + ts->prg = tmp; + p = &ts->prg[ts->nb_prg]; + p->id = programid; + p->nb_pids = 0; + ts->nb_prg++; +} + +static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid) +{ + int i; + Program_t *p = NULL; + for(i=0; i<ts->nb_prg; i++) { + if(ts->prg[i].id == programid) { + p = &ts->prg[i]; + break; + } + } + if(!p) + return; + + if(p->nb_pids >= MAX_PIDS_PER_PROGRAM) + return; + p->pids[p->nb_pids++] = pid; +} + +/** + * \brief discard_pid() decides if the pid is to be discarded according + * to caller's programs selection + * \param ts : - TS context + * \param pid : - pid + * \return 1 if the pid is only comprised in programs that have .discard=AVDISCARD_ALL + * 0 otherwise + */ +static int discard_pid(MpegTSContext *ts, unsigned int pid) +{ + int i, j, k; + int used = 0, discarded = 0; + Program_t *p; + for(i=0; i<ts->nb_prg; i++) { + p = &ts->prg[i]; + for(j=0; j<p->nb_pids; j++) { + if(p->pids[j] != pid) + continue; + //is program with id p->id set to be discarded? + for(k=0; k<ts->stream->nb_programs; k++) { + if(ts->stream->programs[k]->id == p->id) { + if(ts->stream->programs[k]->discard == AVDISCARD_ALL) + discarded++; + else + used++; + } + } + } + } + + return (!used && discarded); +} + /** * Assembles PES packets out of TS packets, and then calls the "section_cb" * function when they are complete. @@ -154,7 +254,7 @@ static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1, /* compute section length if possible */ if (tss->section_h_size == -1 && tss->section_index >= 3) { - len = (((tss->section_buf[1] & 0xf) << 8) | tss->section_buf[2]) + 3; + len = (AV_RB16(tss->section_buf + 1) & 0xfff) + 3; if (len > 4096) return; tss->section_h_size = len; @@ -163,8 +263,9 @@ static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1, if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) { tss->end_of_section_reached = 1; if (!tss->check_crc || - av_crc(av_crc04C11DB7, -1, tss->section_buf, tss->section_h_size) == 0) - tss->section_cb(tss->opaque, tss->section_buf, tss->section_h_size); + av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, + tss->section_buf, tss->section_h_size) == 0) + tss->section_cb(tss1, tss->section_buf, tss->section_h_size); } } @@ -308,7 +409,7 @@ static inline int get16(const uint8_t **pp, const uint8_t *p_end) p = *pp; if ((p + 1) >= p_end) return -1; - c = (p[0] << 8) | p[1]; + c = AV_RB16(p); p += 2; *pp = p; return c; @@ -366,30 +467,10 @@ static int parse_section_header(SectionHeader *h, return 0; } -static MpegTSService *new_service(MpegTSContext *ts, int sid, - char *provider_name, char *name) -{ - MpegTSService *service; - -#ifdef DEBUG_SI - av_log(ts->stream, AV_LOG_DEBUG, "new_service: " - "sid=0x%04x provider='%s' name='%s'\n", - sid, provider_name, name); -#endif - - service = av_mallocz(sizeof(MpegTSService)); - if (!service) - return NULL; - service->sid = sid; - service->provider_name = provider_name; - service->name = name; - dynarray_add(&ts->services, &ts->nb_services, service); - return service; -} -static void pmt_cb(void *opaque, const uint8_t *section, int section_len) +static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { - MpegTSContext *ts = opaque; + MpegTSContext *ts = filter->u.section_filter.opaque; SectionHeader h1, *h = &h1; PESContext *pes; AVStream *st; @@ -397,7 +478,8 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) int program_info_length, pcr_pid, pid, stream_type; int desc_list_len, desc_len, desc_tag; int comp_page = 0, anc_page = 0; /* initialize to kill warnings */ - char language[4]; + char language[4] = {0}; /* initialize to kill warnings */ + int has_hdmv_descr = 0; #ifdef DEBUG_SI av_log(ts->stream, AV_LOG_DEBUG, "PMT: len %i\n", section_len); @@ -411,19 +493,41 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) av_log(ts->stream, AV_LOG_DEBUG, "sid=0x%x sec_num=%d/%d\n", h->id, h->sec_num, h->last_sec_num); #endif - if (h->tid != PMT_TID || (ts->req_sid >= 0 && h->id != ts->req_sid) ) + if (h->tid != PMT_TID) return; + clear_program(ts, h->id); pcr_pid = get16(&p, p_end) & 0x1fff; if (pcr_pid < 0) return; - ts->pcr_pid = pcr_pid; + add_pid_to_pmt(ts, h->id, pcr_pid); #ifdef DEBUG_SI av_log(ts->stream, AV_LOG_DEBUG, "pcr_pid=0x%x\n", pcr_pid); #endif program_info_length = get16(&p, p_end) & 0xfff; if (program_info_length < 0) return; + while(program_info_length >= 2) { + uint8_t tag, len; + tag = get8(&p, p_end); + len = get8(&p, p_end); + if(len > program_info_length - 2) + //something else is broken, exit the program_descriptors_loop + break; + program_info_length -= len + 2; + if(tag == REGISTRATION_DESCRIPTOR && len >= 4) { + uint8_t bytes[4]; + bytes[0] = get8(&p, p_end); + bytes[1] = get8(&p, p_end); + bytes[2] = get8(&p, p_end); + bytes[3] = get8(&p, p_end); + len -= 4; + if(bytes[0] == 'H' && bytes[1] == 'D' && + bytes[2] == 'M' && bytes[3] == 'V') + has_hdmv_descr = 1; + } + p += len; + } p += program_info_length; if (p >= p_end) return; @@ -507,10 +611,22 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) case STREAM_TYPE_AUDIO_AAC: case STREAM_TYPE_AUDIO_AC3: case STREAM_TYPE_AUDIO_DTS: + case STREAM_TYPE_AUDIO_HDMV_DTS: case STREAM_TYPE_SUBTITLE_DVB: - pes = add_pes_stream(ts, pid, stream_type); - if (pes) - st = new_pes_av_stream(pes, 0); + if(stream_type == STREAM_TYPE_AUDIO_HDMV_DTS && !has_hdmv_descr) + break; + if(ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES){ + pes= ts->pids[pid]->u.pes_filter.opaque; + st= pes->st; + }else{ + if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably + pes = add_pes_stream(ts, pid, pcr_pid, stream_type); + if (pes) + st = new_pes_av_stream(pes, 0); + } + add_pid_to_pmt(ts, h->id, pid); + if(st) + av_program_add_stream_index(ts->stream, h->id, st->index); break; default: /* we ignore the other streams */ @@ -519,10 +635,7 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) if (st) { if (language[0] != 0) { - st->language[0] = language[0]; - st->language[1] = language[1]; - st->language[2] = language[2]; - st->language[3] = language[3]; + memcpy(st->language, language, 4); } if (stream_type == STREAM_TYPE_SUBTITLE_DVB) { @@ -531,14 +644,13 @@ static void pmt_cb(void *opaque, const uint8_t *section, int section_len) } } /* all parameters are there */ - ts->set_service_cb(ts->set_service_opaque, 0); - mpegts_close_filter(ts, ts->pmt_filter); - ts->pmt_filter = NULL; + ts->stop_parse++; + mpegts_close_filter(ts, filter); } -static void pat_cb(void *opaque, const uint8_t *section, int section_len) +static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { - MpegTSContext *ts = opaque; + MpegTSContext *ts = filter->u.section_filter.opaque; SectionHeader h1, *h = &h1; const uint8_t *p, *p_end; int sid, pmt_pid; @@ -554,6 +666,7 @@ static void pat_cb(void *opaque, const uint8_t *section, int section_len) if (h->tid != PAT_TID) return; + clear_programs(ts); for(;;) { sid = get16(&p, p_end); if (sid < 0) @@ -567,87 +680,29 @@ static void pat_cb(void *opaque, const uint8_t *section, int section_len) if (sid == 0x0000) { /* NIT info */ } else { - if (ts->req_sid == sid) { - ts->pmt_filter = mpegts_open_section_filter(ts, pmt_pid, - pmt_cb, ts, 1); - goto found; - } + av_new_program(ts->stream, sid); + ts->stop_parse--; + mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); + add_pat_entry(ts, sid); + add_pid_to_pmt(ts, sid, 0); //add pat pid to program + add_pid_to_pmt(ts, sid, pmt_pid); } } /* not found */ - ts->set_service_cb(ts->set_service_opaque, -1); + ts->stop_parse++; - found: - mpegts_close_filter(ts, ts->pat_filter); - ts->pat_filter = NULL; + mpegts_close_filter(ts, filter); } -/* add all services found in the PAT */ -static void pat_scan_cb(void *opaque, const uint8_t *section, int section_len) +static void mpegts_set_service(MpegTSContext *ts) { - MpegTSContext *ts = opaque; - SectionHeader h1, *h = &h1; - const uint8_t *p, *p_end; - int sid, pmt_pid; - char *provider_name, *name; - char buf[256]; - -#ifdef DEBUG_SI - av_log(ts->stream, AV_LOG_DEBUG, "PAT:\n"); - av_hex_dump_log(ts->stream, AV_LOG_DEBUG, (uint8_t *)section, section_len); -#endif - p_end = section + section_len - 4; - p = section; - if (parse_section_header(h, &p, p_end) < 0) - return; - if (h->tid != PAT_TID) - return; - - for(;;) { - sid = get16(&p, p_end); - if (sid < 0) - break; - pmt_pid = get16(&p, p_end) & 0x1fff; - if (pmt_pid < 0) - break; -#ifdef DEBUG_SI - av_log(ts->stream, AV_LOG_DEBUG, "sid=0x%x pid=0x%x\n", sid, pmt_pid); -#endif - if (sid == 0x0000) { - /* NIT info */ - } else { - /* add the service with a dummy name */ - snprintf(buf, sizeof(buf), "Service %x\n", sid); - name = av_strdup(buf); - provider_name = av_strdup(""); - if (name && provider_name) { - new_service(ts, sid, provider_name, name); - } else { - av_freep(&name); - av_freep(&provider_name); - } - } - } - ts->stop_parse = 1; - - /* remove filter */ - mpegts_close_filter(ts, ts->pat_filter); - ts->pat_filter = NULL; -} - -static void mpegts_set_service(MpegTSContext *ts, int sid, - SetServiceCallback *set_service_cb, void *opaque) -{ - ts->set_service_cb = set_service_cb; - ts->set_service_opaque = opaque; - ts->req_sid = sid; - ts->pat_filter = mpegts_open_section_filter(ts, PAT_PID, + mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1); } -static void sdt_cb(void *opaque, const uint8_t *section, int section_len) +static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { - MpegTSContext *ts = opaque; + MpegTSContext *ts = filter->u.section_filter.opaque; SectionHeader h1, *h = &h1; const uint8_t *p, *p_end, *desc_list_end, *desc_end; int onid, val, sid, desc_list_len, desc_tag, desc_len, service_type; @@ -704,9 +759,11 @@ static void sdt_cb(void *opaque, const uint8_t *section, int section_len) if (!provider_name) break; name = getstr8(&p, p_end); - if (!name) - break; - new_service(ts, sid, provider_name, name); + if (name) { + AVProgram *program = av_new_program(ts->stream, sid); + if(program) + av_set_program_name(program, provider_name, name); + } break; default: break; @@ -715,78 +772,35 @@ static void sdt_cb(void *opaque, const uint8_t *section, int section_len) } p = desc_list_end; } - ts->stop_parse = 1; - - /* remove filter */ - mpegts_close_filter(ts, ts->sdt_filter); - ts->sdt_filter = NULL; } /* scan services in a transport stream by looking at the SDT */ static void mpegts_scan_sdt(MpegTSContext *ts) { - ts->sdt_filter = mpegts_open_section_filter(ts, SDT_PID, + mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); } -/* scan services in a transport stream by looking at the PAT (better - than nothing !) */ -static void mpegts_scan_pat(MpegTSContext *ts) -{ - ts->pat_filter = mpegts_open_section_filter(ts, PAT_PID, - pat_scan_cb, ts, 1); -} - -/* TS stream handling */ - -enum MpegTSState { - MPEGTS_HEADER = 0, - MPEGTS_PESHEADER_FILL, - MPEGTS_PAYLOAD, - MPEGTS_SKIP, -}; - -/* enough for PES header + length */ -#define PES_START_SIZE 9 -#define MAX_PES_HEADER_SIZE (9 + 255) - -struct PESContext { - int pid; - int stream_type; - MpegTSContext *ts; - AVFormatContext *stream; - AVStream *st; - enum MpegTSState state; - /* used to get the format */ - int data_index; - int total_size; - int pes_header_size; - int64_t pts, dts; - uint8_t header[MAX_PES_HEADER_SIZE]; -}; - static int64_t get_pts(const uint8_t *p) { - int64_t pts; - int val; - - pts = (int64_t)((p[0] >> 1) & 0x07) << 30; - val = (p[1] << 8) | p[2]; - pts |= (int64_t)(val >> 1) << 15; - val = (p[3] << 8) | p[4]; - pts |= (int64_t)(val >> 1); + int64_t pts = (int64_t)((p[0] >> 1) & 0x07) << 30; + pts |= (AV_RB16(p + 1) >> 1) << 15; + pts |= AV_RB16(p + 3) >> 1; return pts; } /* return non zero if a packet could be constructed */ -static void mpegts_push_data(void *opaque, +static void mpegts_push_data(MpegTSFilter *filter, const uint8_t *buf, int buf_size, int is_start) { - PESContext *pes = opaque; + PESContext *pes = filter->u.pes_filter.opaque; MpegTSContext *ts = pes->ts; const uint8_t *p; int len, code; + if(!ts->pkt) + return; + if (is_start) { pes->state = MPEGTS_HEADER; pes->data_index = 0; @@ -821,7 +835,7 @@ static void mpegts_push_data(void *opaque, new_pes_av_stream(pes, code); } pes->state = MPEGTS_PESHEADER_FILL; - pes->total_size = (pes->header[4] << 8) | pes->header[5]; + pes->total_size = AV_RB16(pes->header + 4); /* NOTE: a zero total size means the PES size is unbounded */ if (pes->total_size) @@ -935,6 +949,7 @@ static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code) codec_id = CODEC_ID_AC3; break; case STREAM_TYPE_AUDIO_DTS: + case STREAM_TYPE_AUDIO_HDMV_DTS: codec_type = CODEC_TYPE_AUDIO; codec_id = CODEC_ID_DTS; break; @@ -961,14 +976,14 @@ static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code) st->priv_data = pes; st->codec->codec_type = codec_type; st->codec->codec_id = codec_id; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; pes->st = st; } return st; } -static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int stream_type) +static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid, int stream_type) { MpegTSFilter *tss; PESContext *pes; @@ -980,6 +995,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int stream_type) pes->ts = ts; pes->stream = ts->stream; pes->pid = pid; + pes->pcr_pid = pcr_pid; pes->stream_type = stream_type; tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); if (!tss) { @@ -997,11 +1013,13 @@ static void handle_packet(MpegTSContext *ts, const uint8_t *packet) int len, pid, cc, cc_ok, afc, is_start; const uint8_t *p, *p_end; - pid = ((packet[1] & 0x1f) << 8) | packet[2]; + pid = AV_RB16(packet + 1) & 0x1fff; + if(pid && discard_pid(ts, pid)) + return; is_start = packet[1] & 0x40; tss = ts->pids[pid]; if (ts->auto_guess && tss == NULL && is_start) { - add_pes_stream(ts, pid, 0); + add_pes_stream(ts, pid, -1, 0); tss = ts->pids[pid]; } if (!tss) @@ -1054,7 +1072,7 @@ static void handle_packet(MpegTSContext *ts, const uint8_t *packet) } } } else { - tss->u.pes_filter.pes_cb(tss->u.pes_filter.opaque, + tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start); } } @@ -1086,7 +1104,7 @@ static int read_packet(ByteIOContext *pb, uint8_t *buf, int raw_packet_size) for(;;) { len = get_buffer(pb, buf, TS_PACKET_SIZE); if (len != TS_PACKET_SIZE) - return AVERROR_IO; + return AVERROR(EIO); /* check paquet sync byte */ if (buf[0] != 0x47) { /* find a new packet start */ @@ -1108,14 +1126,14 @@ static int read_packet(ByteIOContext *pb, uint8_t *buf, int raw_packet_size) static int handle_packets(MpegTSContext *ts, int nb_packets) { AVFormatContext *s = ts->stream; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint8_t packet[TS_PACKET_SIZE]; int packet_num, ret; ts->stop_parse = 0; packet_num = 0; for(;;) { - if (ts->stop_parse) + if (ts->stop_parse>0) break; packet_num++; if (nb_packets != 0 && packet_num >= nb_packets) @@ -1157,13 +1175,6 @@ static int mpegts_probe(AVProbeData *p) #endif } -static void set_service_cb(void *opaque, int ret) -{ - MpegTSContext *ts = opaque; - ts->set_service_ret = ret; - ts->stop_parse = 1; -} - /* return the 90 kHz PCR and the extension for the 27 MHz PCR. return (-1) if not available */ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, @@ -1187,7 +1198,7 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, return -1; if (len < 6) return -1; - v = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + v = AV_RB32(p); *ppcr_high = ((int64_t)v << 1) | (p[4] >> 7); *ppcr_low = ((p[4] & 1) << 8) | p[5]; return 0; @@ -1197,15 +1208,17 @@ static int mpegts_read_header(AVFormatContext *s, AVFormatParameters *ap) { MpegTSContext *ts = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint8_t buf[1024]; - int len, sid, i; + int len; int64_t pos; - MpegTSService *service; if (ap) { - ts->mpeg2ts_raw = ap->mpeg2ts_raw; ts->mpeg2ts_compute_pcr = ap->mpeg2ts_compute_pcr; + if(ap->mpeg2ts_raw){ + av_log(s, AV_LOG_ERROR, "use mpegtsraw_demuxer!\n"); + return -1; + } } /* read the first 1024 bytes to get packet size */ @@ -1219,73 +1232,23 @@ static int mpegts_read_header(AVFormatContext *s, ts->stream = s; ts->auto_guess = 0; -goto_auto_guess: - if (!ts->mpeg2ts_raw) { + if (s->iformat == &mpegts_demuxer) { /* normal demux */ - if (!ts->auto_guess) { - ts->set_service_ret = -1; - - /* first do a scaning to get all the services */ - url_fseek(pb, pos, SEEK_SET); - mpegts_scan_sdt(ts); + /* first do a scaning to get all the services */ + url_fseek(pb, pos, SEEK_SET); + mpegts_scan_sdt(ts); - handle_packets(ts, s->probesize); + mpegts_set_service(ts); - if (ts->nb_services <= 0) { - /* no SDT found, we try to look at the PAT */ + handle_packets(ts, s->probesize); + /* if could not find service, enable auto_guess */ - /* First remove the SDT filters from each PID */ - int i; - for (i=0; i < NB_PID_MAX; i++) { - if (ts->pids[i]) - mpegts_close_filter(ts, ts->pids[i]); - } - url_fseek(pb, pos, SEEK_SET); - mpegts_scan_pat(ts); - - handle_packets(ts, s->probesize); - } + ts->auto_guess = 1; - if (ts->nb_services <= 0) { - /* raw transport stream */ - ts->auto_guess = 1; - s->ctx_flags |= AVFMTCTX_NOHEADER; - goto do_pcr; - } - - /* tune to first service found */ - for(i=0; i<ts->nb_services && ts->set_service_ret; i++){ - service = ts->services[i]; - sid = service->sid; #ifdef DEBUG_SI - av_log(ts->stream, AV_LOG_DEBUG, "tuning to '%s'\n", service->name); + av_log(ts->stream, AV_LOG_DEBUG, "tuning done\n"); #endif - - /* now find the info for the first service if we found any, - otherwise try to filter all PATs */ - - url_fseek(pb, pos, SEEK_SET); - mpegts_set_service(ts, sid, set_service_cb, ts); - - handle_packets(ts, s->probesize); - } - /* if could not find service, exit */ - - if (ts->set_service_ret != 0) { - if(ts->auto_guess) - return -1; - else { - //let's retry with auto_guess set - ts->auto_guess = 1; - goto goto_auto_guess; - } - } - -#ifdef DEBUG_SI - av_log(ts->stream, AV_LOG_DEBUG, "tuning done\n"); -#endif - } s->ctx_flags |= AVFMTCTX_NOHEADER; } else { AVStream *st; @@ -1296,7 +1259,6 @@ goto_auto_guess: /* only read packets */ - do_pcr: st = av_new_stream(s, 0); if (!st) goto fail; @@ -1309,10 +1271,10 @@ goto_auto_guess: nb_pcrs = 0; nb_packets = 0; for(;;) { - ret = read_packet(&s->pb, packet, ts->raw_packet_size); + ret = read_packet(s->pb, packet, ts->raw_packet_size); if (ret < 0) return -1; - pid = ((packet[1] & 0x1f) << 8) | packet[2]; + pid = AV_RB16(packet + 1) & 0x1fff; if ((pcr_pid == -1 || pcr_pid == pid) && parse_pcr(&pcr_h, &pcr_l, packet) == 0) { pcr_pid = pid; @@ -1324,7 +1286,6 @@ goto_auto_guess: } nb_packets++; } - ts->pcr_pid = pcr_pid; /* NOTE1: the bitrate is computed without the FEC */ /* NOTE2: it is only the bitrate of the start of the stream */ @@ -1358,8 +1319,8 @@ static int mpegts_raw_read_packet(AVFormatContext *s, if (av_new_packet(pkt, TS_PACKET_SIZE) < 0) return AVERROR(ENOMEM); - pkt->pos= url_ftell(&s->pb); - ret = read_packet(&s->pb, pkt->data, ts->raw_packet_size); + pkt->pos= url_ftell(s->pb); + ret = read_packet(s->pb, pkt->data, ts->raw_packet_size); if (ret < 0) { av_free_packet(pkt); return ret; @@ -1368,10 +1329,10 @@ static int mpegts_raw_read_packet(AVFormatContext *s, /* compute exact PCR for each packet */ if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) { /* we read the next PCR (XXX: optimize it by using a bigger buffer */ - pos = url_ftell(&s->pb); + pos = url_ftell(s->pb); for(i = 0; i < MAX_PACKET_READAHEAD; i++) { - url_fseek(&s->pb, pos + i * ts->raw_packet_size, SEEK_SET); - get_buffer(&s->pb, pcr_buf, 12); + url_fseek(s->pb, pos + i * ts->raw_packet_size, SEEK_SET); + get_buffer(s->pb, pcr_buf, 12); if (parse_pcr(&next_pcr_h, &next_pcr_l, pcr_buf) == 0) { /* XXX: not precise enough */ ts->pcr_incr = ((next_pcr_h - pcr_h) * 300 + (next_pcr_l - pcr_l)) / @@ -1379,7 +1340,7 @@ static int mpegts_raw_read_packet(AVFormatContext *s, break; } } - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); /* no next PCR found: we use previous increment */ ts->cur_pcr = pcr_h * 300 + pcr_l; } @@ -1396,12 +1357,8 @@ static int mpegts_read_packet(AVFormatContext *s, { MpegTSContext *ts = s->priv_data; - if (!ts->mpeg2ts_raw) { - ts->pkt = pkt; - return handle_packets(ts, 0); - } else { - return mpegts_raw_read_packet(s, pkt); - } + ts->pkt = pkt; + return handle_packets(ts, 0); } static int mpegts_read_close(AVFormatContext *s) @@ -1411,13 +1368,6 @@ static int mpegts_read_close(AVFormatContext *s) for(i=0;i<NB_PID_MAX;i++) if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]); - for(i = 0; i < ts->nb_services; i++){ - av_free(ts->services[i]->provider_name); - av_free(ts->services[i]->name); - av_free(ts->services[i]); - } - av_freep(&ts->services); - return 0; } @@ -1427,16 +1377,15 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, MpegTSContext *ts = s->priv_data; int64_t pos, timestamp; uint8_t buf[TS_PACKET_SIZE]; - int pcr_l, pid; + 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->raw_packet_size) * ts->raw_packet_size; if (find_next) { for(;;) { - url_fseek(&s->pb, pos, SEEK_SET); - if (get_buffer(&s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) + url_fseek(s->pb, pos, SEEK_SET); + if (get_buffer(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) return AV_NOPTS_VALUE; - pid = ((buf[1] & 0x1f) << 8) | buf[2]; - if (pid == ts->pcr_pid && + if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) && parse_pcr(×tamp, &pcr_l, buf) == 0) { break; } @@ -1447,11 +1396,10 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index, pos -= ts->raw_packet_size; if (pos < 0) return AV_NOPTS_VALUE; - url_fseek(&s->pb, pos, SEEK_SET); - if (get_buffer(&s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) + url_fseek(s->pb, pos, SEEK_SET); + if (get_buffer(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) return AV_NOPTS_VALUE; - pid = ((buf[1] & 0x1f) << 8) | buf[2]; - if (pid == ts->pcr_pid && + if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) && parse_pcr(×tamp, &pcr_l, buf) == 0) { break; } @@ -1470,17 +1418,17 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, in if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0) return -1; - pos= url_ftell(&s->pb); + pos= url_ftell(s->pb); for(;;) { - url_fseek(&s->pb, pos, SEEK_SET); - if (get_buffer(&s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) + url_fseek(s->pb, pos, SEEK_SET); + if (get_buffer(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE) return -1; -// pid = ((buf[1] & 0x1f) << 8) | buf[2]; +// pid = AV_RB16(buf + 1) & 0x1fff; if(buf[1] & 0x40) break; pos += ts->raw_packet_size; } - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); return 0; } @@ -1513,7 +1461,7 @@ int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, ts->pkt = pkt; ts->stop_parse = 0; for(;;) { - if (ts->stop_parse) + if (ts->stop_parse>0) break; if (len < TS_PACKET_SIZE) return -1; @@ -1550,3 +1498,16 @@ AVInputFormat mpegts_demuxer = { mpegts_get_pcr, .flags = AVFMT_SHOW_IDS, }; + +AVInputFormat mpegtsraw_demuxer = { + "mpegtsraw", + "MPEG2 raw transport stream format", + sizeof(MpegTSContext), + mpegts_probe, + mpegts_read_header, + mpegts_raw_read_packet, + mpegts_read_close, + read_seek, + mpegts_get_pcr, + .flags = AVFMT_SHOW_IDS, +}; diff --git a/contrib/ffmpeg/libavformat/mpegts.h b/contrib/ffmpeg/libavformat/mpegts.h index 771becbd4..bdfc760b3 100644 --- a/contrib/ffmpeg/libavformat/mpegts.h +++ b/contrib/ffmpeg/libavformat/mpegts.h @@ -19,6 +19,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef FFMPEG_MPEGTS_H +#define FFMPEG_MPEGTS_H + +#include "avformat.h" + #define TS_FEC_PACKET_SIZE 204 #define TS_DVHS_PACKET_SIZE 192 #define TS_PACKET_SIZE 188 @@ -50,14 +55,15 @@ #define STREAM_TYPE_AUDIO_AC3 0x81 #define STREAM_TYPE_AUDIO_DTS 0x8a +#define STREAM_TYPE_AUDIO_HDMV_DTS 0x82 #define STREAM_TYPE_SUBTITLE_DVB 0x100 -extern AVOutputFormat mpegts_muxer; - typedef struct MpegTSContext MpegTSContext; MpegTSContext *mpegts_parse_open(AVFormatContext *s); int mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt, const uint8_t *buf, int len); void mpegts_parse_close(MpegTSContext *ts); + +#endif /* FFMPEG_MPEGTS_H */ diff --git a/contrib/ffmpeg/libavformat/mpegtsenc.c b/contrib/ffmpeg/libavformat/mpegtsenc.c index c521b68b8..49d29aa2b 100644 --- a/contrib/ffmpeg/libavformat/mpegtsenc.c +++ b/contrib/ffmpeg/libavformat/mpegtsenc.c @@ -43,7 +43,7 @@ static void mpegts_write_section(MpegTSSection *s, uint8_t *buf, int len) unsigned char *q; int first, b, len1, left; - crc = bswap_32(av_crc(av_crc04C11DB7, -1, buf, len - 4)); + crc = bswap_32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, buf, len - 4)); buf[len - 4] = (crc >> 24) & 0xff; buf[len - 3] = (crc >> 16) & 0xff; buf[len - 2] = (crc >> 8) & 0xff; @@ -353,7 +353,7 @@ static MpegTSService *mpegts_add_service(MpegTSWrite *ts, static void section_write_packet(MpegTSSection *s, const uint8_t *packet) { AVFormatContext *ctx = s->opaque; - put_buffer(&ctx->pb, packet, TS_PACKET_SIZE); + put_buffer(ctx->pb, packet, TS_PACKET_SIZE); } static int mpegts_write_header(AVFormatContext *s) @@ -431,7 +431,7 @@ static int mpegts_write_header(AVFormatContext *s) for(i = 0; i < ts->nb_services; i++) { mpegts_write_pmt(s, ts->services[i]); } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); return 0; @@ -608,9 +608,9 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, memcpy(buf + TS_PACKET_SIZE - len, payload, len); payload += len; payload_size -= len; - put_buffer(&s->pb, buf, TS_PACKET_SIZE); + put_buffer(s->pb, buf, TS_PACKET_SIZE); } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); } static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) @@ -668,7 +668,7 @@ static int mpegts_write_end(AVFormatContext *s) ts_st->payload_pts, ts_st->payload_dts); } } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); for(i = 0; i < ts->nb_services; i++) { service = ts->services[i]; diff --git a/contrib/ffmpeg/libavformat/mpjpeg.c b/contrib/ffmpeg/libavformat/mpjpeg.c index 937917313..2e745721b 100644 --- a/contrib/ffmpeg/libavformat/mpjpeg.c +++ b/contrib/ffmpeg/libavformat/mpjpeg.c @@ -29,8 +29,8 @@ static int mpjpeg_write_header(AVFormatContext *s) uint8_t buf1[256]; snprintf(buf1, sizeof(buf1), "--%s\n", BOUNDARY_TAG); - put_buffer(&s->pb, buf1, strlen(buf1)); - put_flush_packet(&s->pb); + put_buffer(s->pb, buf1, strlen(buf1)); + put_flush_packet(s->pb); return 0; } @@ -39,12 +39,12 @@ static int mpjpeg_write_packet(AVFormatContext *s, AVPacket *pkt) uint8_t buf1[256]; snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\n\n"); - put_buffer(&s->pb, buf1, strlen(buf1)); - put_buffer(&s->pb, pkt->data, pkt->size); + put_buffer(s->pb, buf1, strlen(buf1)); + put_buffer(s->pb, pkt->data, pkt->size); snprintf(buf1, sizeof(buf1), "\n--%s\n", BOUNDARY_TAG); - put_buffer(&s->pb, buf1, strlen(buf1)); - put_flush_packet(&s->pb); + put_buffer(s->pb, buf1, strlen(buf1)); + put_flush_packet(s->pb); return 0; } diff --git a/contrib/ffmpeg/libavformat/mtv.c b/contrib/ffmpeg/libavformat/mtv.c index 7a68ea97f..32057e623 100644 --- a/contrib/ffmpeg/libavformat/mtv.c +++ b/contrib/ffmpeg/libavformat/mtv.c @@ -54,9 +54,6 @@ typedef struct MTVDemuxContext { static int mtv_probe(AVProbeData *p) { - if(p->buf_size < 3) - return 0; - /* Magic is 'AMV' */ if(*(p->buf) != 'A' || *(p->buf+1) != 'M' || *(p->buf+2) != 'V') @@ -68,7 +65,7 @@ static int mtv_probe(AVProbeData *p) static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap) { MTVDemuxContext *mtv = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; @@ -89,7 +86,7 @@ static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap) /* FIXME Add sanity check here */ - /* first packet is allways audio*/ + /* first packet is always audio*/ mtv->audio_packet_count = 1; @@ -99,7 +96,7 @@ static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap) st = av_new_stream(s, VIDEO_SID); if(!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 64, 1, mtv->video_fps); st->codec->codec_type = CODEC_TYPE_VIDEO; @@ -114,18 +111,18 @@ static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap) st = av_new_stream(s, AUDIO_SID); if(!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_MP3; st->codec->bit_rate = mtv->audio_br; - st->need_parsing=1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* Jump over header */ if(url_fseek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE) - return AVERROR_IO; + return AVERROR(EIO); return(0); @@ -134,7 +131,7 @@ static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap) static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) { MTVDemuxContext *mtv = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int ret; #ifndef WORDS_BIGENDIAN int i; @@ -148,7 +145,7 @@ static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE); if(ret != MTV_ASUBCHUNK_DATA_SIZE) - return AVERROR_IO; + return AVERROR(EIO); mtv->audio_packet_count++; pkt->stream_index = AUDIO_SID; @@ -157,7 +154,7 @@ static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) { ret = av_get_packet(pb, pkt, mtv->img_segment_size); if(ret != mtv->img_segment_size) - return AVERROR_IO; + return AVERROR(EIO); #ifndef WORDS_BIGENDIAN diff --git a/contrib/ffmpeg/libavformat/mxf.c b/contrib/ffmpeg/libavformat/mxf.c index 677e023f0..0c69cd2e1 100644 --- a/contrib/ffmpeg/libavformat/mxf.c +++ b/contrib/ffmpeg/libavformat/mxf.c @@ -47,6 +47,7 @@ #include "avformat.h" #include "aes.h" +#include "bytestream.h" typedef uint8_t UID[16]; @@ -60,18 +61,16 @@ enum MXFMetadataSetType { MultipleDescriptor, Descriptor, Track, - EssenceContainerData, CryptoContext, }; -typedef struct MXFCryptoContext { +typedef struct { UID uid; enum MXFMetadataSetType type; - UID context_uid; UID source_container_ul; } MXFCryptoContext; -typedef struct MXFStructuralComponent { +typedef struct { UID uid; enum MXFMetadataSetType type; UID source_package_uid; @@ -81,7 +80,7 @@ typedef struct MXFStructuralComponent { int source_track_id; } MXFStructuralComponent; -typedef struct MXFSequence { +typedef struct { UID uid; enum MXFMetadataSetType type; UID data_definition_ul; @@ -90,7 +89,7 @@ typedef struct MXFSequence { int64_t duration; } MXFSequence; -typedef struct MXFTrack { +typedef struct { UID uid; enum MXFMetadataSetType type; MXFSequence *sequence; /* mandatory, and only one */ @@ -100,7 +99,7 @@ typedef struct MXFTrack { AVRational edit_rate; } MXFTrack; -typedef struct MXFDescriptor { +typedef struct { UID uid; enum MXFMetadataSetType type; UID essence_container_ul; @@ -118,7 +117,7 @@ typedef struct MXFDescriptor { int extradata_size; } MXFDescriptor; -typedef struct MXFPackage { +typedef struct { UID uid; enum MXFMetadataSetType type; UID package_uid; @@ -128,28 +127,23 @@ typedef struct MXFPackage { UID descriptor_ref; } MXFPackage; -typedef struct MXFEssenceContainerData { - UID uid; - enum MXFMetadataSetType type; - UID linked_package_uid; -} MXFEssenceContainerData; - typedef struct { UID uid; enum MXFMetadataSetType type; } MXFMetadataSet; -typedef struct MXFContext { +typedef struct { UID *packages_refs; int packages_count; MXFMetadataSet **metadata_sets; int metadata_sets_count; - const uint8_t *sync_key; AVFormatContext *fc; struct AVAES *aesc; + uint8_t *local_tags; + int local_tags_count; } MXFContext; -typedef struct KLVPacket { +typedef struct { UID key; offset_t offset; uint64_t length; @@ -160,18 +154,18 @@ enum MXFWrappingScheme { Clip, }; -typedef struct MXFCodecUL { +typedef struct { UID uid; + unsigned matching_len; enum CodecID id; - enum MXFWrappingScheme wrapping; } MXFCodecUL; -typedef struct MXFDataDefinitionUL { +typedef struct { UID uid; enum CodecType type; } MXFDataDefinitionUL; -typedef struct MXFMetadataReadTableEntry { +typedef struct { const UID key; int (*read)(); int ctx_size; @@ -181,9 +175,12 @@ typedef struct MXFMetadataReadTableEntry { /* partial keys to match */ static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 }; static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; +static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 }; /* complete keys to match */ +static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 }; static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }; +static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 }; #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y))) @@ -205,10 +202,26 @@ static int64_t klv_decode_ber_length(ByteIOContext *pb) return size; } +static int mxf_read_sync(ByteIOContext *pb, const uint8_t *key, unsigned size) +{ + int i, b; + for (i = 0; i < size && !url_feof(pb); i++) { + b = get_byte(pb); + if (b == key[0]) + i = 0; + else if (b != key[i]) + i = -1; + } + return i == size; +} + static int klv_read_packet(KLVPacket *klv, ByteIOContext *pb) { - klv->offset = url_ftell(pb); - get_buffer(pb, klv->key, 16); + if (!mxf_read_sync(pb, mxf_klv_key, 4)) + return -1; + klv->offset = url_ftell(pb) - 4; + memcpy(klv->key, mxf_klv_key, 4); + get_buffer(pb, klv->key + 4, 12); klv->length = klv_decode_ber_length(pb); return klv->length == -1 ? -1 : 0; } @@ -231,7 +244,9 @@ static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv) static int mxf_get_d10_aes3_packet(ByteIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length) { uint8_t buffer[61444]; - uint8_t *buf_ptr, *end_ptr, *data_ptr; + const uint8_t *buf_ptr, *end_ptr; + uint8_t *data_ptr; + int i; if (length > 61444) /* worst case PAL 1920 samples 8 channels */ return -1; @@ -240,17 +255,15 @@ static int mxf_get_d10_aes3_packet(ByteIOContext *pb, AVStream *st, AVPacket *pk data_ptr = pkt->data; end_ptr = buffer + length; buf_ptr = buffer + 4; /* skip SMPTE 331M header */ - for (; buf_ptr < end_ptr; buf_ptr += 4) { - if (st->codec->bits_per_sample == 24) { - data_ptr[0] = (buf_ptr[2] >> 4) | ((buf_ptr[3] & 0x0f) << 4); - data_ptr[1] = (buf_ptr[1] >> 4) | ((buf_ptr[2] & 0x0f) << 4); - data_ptr[2] = (buf_ptr[0] >> 4) | ((buf_ptr[1] & 0x0f) << 4); - data_ptr += 3; - } else { - data_ptr[0] = (buf_ptr[2] >> 4) | ((buf_ptr[3] & 0x0f) << 4); - data_ptr[1] = (buf_ptr[1] >> 4) | ((buf_ptr[2] & 0x0f) << 4); - data_ptr += 2; + for (; buf_ptr < end_ptr; ) { + for (i = 0; i < st->codec->channels; i++) { + uint32_t sample = bytestream_get_le32(&buf_ptr); + if (st->codec->bits_per_sample == 24) + bytestream_put_le24(&data_ptr, (sample >> 4) & 0xffffff); + else + bytestream_put_le16(&data_ptr, (sample >> 12) & 0xffff); } + buf_ptr += 32 - st->codec->channels*4; // always 8 channels stored SMPTE 331M } pkt->size = data_ptr - pkt->data; return 0; @@ -260,7 +273,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv { static const uint8_t checkv[16] = {0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b}; MXFContext *mxf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; offset_t end = url_ftell(pb) + klv->length; uint64_t size; uint64_t orig_size; @@ -271,6 +284,8 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv if (!mxf->aesc && s->key && s->keylen == 16) { mxf->aesc = av_malloc(av_aes_size); + if (!mxf->aesc) + return -1; av_aes_init(mxf->aesc, s->key, 128, 1); } // crypto context @@ -281,16 +296,20 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv // source klv key klv_decode_ber_length(pb); get_buffer(pb, klv->key, 16); - if (!IS_KLV_KEY(klv, mxf_essence_element_key)) goto err_out; + if (!IS_KLV_KEY(klv, mxf_essence_element_key)) + return -1; index = mxf_get_stream_index(s, klv); - if (index < 0) goto err_out; + if (index < 0) + return -1; // source size klv_decode_ber_length(pb); orig_size = get_be64(pb); - if (orig_size < plaintext_size) goto err_out; + if (orig_size < plaintext_size) + return -1; // enc. code size = klv_decode_ber_length(pb); - if (size < 32 || size - 32 < orig_size) goto err_out; + if (size < 32 || size - 32 < orig_size) + return -1; get_buffer(pb, ivec, 16); get_buffer(pb, tmpbuf, 16); if (mxf->aesc) @@ -307,28 +326,20 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv pkt->stream_index = index; url_fskip(pb, end - url_ftell(pb)); return 0; - -err_out: - url_fskip(pb, end - url_ftell(pb)); - return -1; } static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { - MXFContext *mxf = s->priv_data; KLVPacket klv; - while (!url_feof(&s->pb)) { - if (klv_read_packet(&klv, &s->pb) < 0) { - av_log(s, AV_LOG_ERROR, "error reading KLV packet\n"); + while (!url_feof(s->pb)) { + if (klv_read_packet(&klv, s->pb) < 0) return -1; - } #ifdef DEBUG PRINT_KEY(s, "read packet", klv.key); #endif if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { int res = mxf_decrypt_triplet(s, pkt, &klv); - mxf->sync_key = mxf_encrypted_triplet_key; if (res < 0) { av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); return -1; @@ -339,47 +350,66 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) int index = mxf_get_stream_index(s, &klv); if (index < 0) { av_log(s, AV_LOG_ERROR, "error getting stream index\n"); - url_fskip(&s->pb, klv.length); + url_fskip(s->pb, klv.length); return -1; } /* check for 8 channels AES3 element */ 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) { + 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; } } else - av_get_packet(&s->pb, pkt, klv.length); + av_get_packet(s->pb, pkt, klv.length); pkt->stream_index = index; + pkt->pos = klv.offset; return 0; } else - url_fskip(&s->pb, klv.length); + url_fskip(s->pb, klv.length); + } + return AVERROR(EIO); +} + +static int mxf_read_primer_pack(MXFContext *mxf) +{ + ByteIOContext *pb = mxf->fc->pb; + int item_num = get_be32(pb); + int item_len = get_be32(pb); + + if (item_len != 18) { + av_log(mxf->fc, AV_LOG_ERROR, "unsupported primer pack item length\n"); + return -1; } - return AVERROR_IO; + if (item_num > UINT_MAX / item_len) + return -1; + mxf->local_tags_count = item_num; + mxf->local_tags = av_malloc(item_num*item_len); + if (!mxf->local_tags) + return -1; + get_buffer(pb, mxf->local_tags, item_num*item_len); + return 0; } static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set) { mxf->metadata_sets = av_realloc(mxf->metadata_sets, (mxf->metadata_sets_count + 1) * sizeof(*mxf->metadata_sets)); + if (!mxf->metadata_sets) + return -1; mxf->metadata_sets[mxf->metadata_sets_count] = metadata_set; mxf->metadata_sets_count++; return 0; } -static int mxf_read_metadata_cryptographic_context(MXFCryptoContext *cryptocontext, ByteIOContext *pb, int tag) +static int mxf_read_cryptographic_context(MXFCryptoContext *cryptocontext, ByteIOContext *pb, int tag, int size, UID uid) { - switch(tag) { - case 0xFFFE: - get_buffer(pb, cryptocontext->context_uid, 16); - break; - case 0xFFFD: + if (size != 16) + return -1; + if (IS_KLV_KEY(uid, mxf_crypto_source_container_ul)) get_buffer(pb, cryptocontext->source_container_ul, 16); - break; - } return 0; } -static int mxf_read_metadata_content_storage(MXFContext *mxf, ByteIOContext *pb, int tag) +static int mxf_read_content_storage(MXFContext *mxf, ByteIOContext *pb, int tag) { switch (tag) { case 0x1901: @@ -387,6 +417,8 @@ static int mxf_read_metadata_content_storage(MXFContext *mxf, ByteIOContext *pb, if (mxf->packages_count >= UINT_MAX / sizeof(UID)) return -1; mxf->packages_refs = av_malloc(mxf->packages_count * sizeof(UID)); + if (!mxf->packages_refs) + return -1; url_fskip(pb, 4); /* useless size of objects, always 16 according to specs */ get_buffer(pb, (uint8_t *)mxf->packages_refs, mxf->packages_count * sizeof(UID)); break; @@ -394,7 +426,7 @@ static int mxf_read_metadata_content_storage(MXFContext *mxf, ByteIOContext *pb, return 0; } -static int mxf_read_metadata_source_clip(MXFStructuralComponent *source_clip, ByteIOContext *pb, int tag) +static int mxf_read_source_clip(MXFStructuralComponent *source_clip, ByteIOContext *pb, int tag) { switch(tag) { case 0x0202: @@ -415,7 +447,7 @@ static int mxf_read_metadata_source_clip(MXFStructuralComponent *source_clip, By return 0; } -static int mxf_read_metadata_material_package(MXFPackage *package, ByteIOContext *pb, int tag) +static int mxf_read_material_package(MXFPackage *package, ByteIOContext *pb, int tag) { switch(tag) { case 0x4403: @@ -423,6 +455,8 @@ static int mxf_read_metadata_material_package(MXFPackage *package, ByteIOContext if (package->tracks_count >= UINT_MAX / sizeof(UID)) return -1; package->tracks_refs = av_malloc(package->tracks_count * sizeof(UID)); + if (!package->tracks_refs) + return -1; url_fskip(pb, 4); /* useless size of objects, always 16 according to specs */ get_buffer(pb, (uint8_t *)package->tracks_refs, package->tracks_count * sizeof(UID)); break; @@ -430,7 +464,7 @@ static int mxf_read_metadata_material_package(MXFPackage *package, ByteIOContext return 0; } -static int mxf_read_metadata_track(MXFTrack *track, ByteIOContext *pb, int tag) +static int mxf_read_track(MXFTrack *track, ByteIOContext *pb, int tag) { switch(tag) { case 0x4801: @@ -450,7 +484,7 @@ static int mxf_read_metadata_track(MXFTrack *track, ByteIOContext *pb, int tag) return 0; } -static int mxf_read_metadata_sequence(MXFSequence *sequence, ByteIOContext *pb, int tag) +static int mxf_read_sequence(MXFSequence *sequence, ByteIOContext *pb, int tag) { switch(tag) { case 0x0202: @@ -464,6 +498,8 @@ static int mxf_read_metadata_sequence(MXFSequence *sequence, ByteIOContext *pb, if (sequence->structural_components_count >= UINT_MAX / sizeof(UID)) return -1; sequence->structural_components_refs = av_malloc(sequence->structural_components_count * sizeof(UID)); + if (!sequence->structural_components_refs) + return -1; url_fskip(pb, 4); /* useless size of objects, always 16 according to specs */ get_buffer(pb, (uint8_t *)sequence->structural_components_refs, sequence->structural_components_count * sizeof(UID)); break; @@ -471,7 +507,7 @@ static int mxf_read_metadata_sequence(MXFSequence *sequence, ByteIOContext *pb, return 0; } -static int mxf_read_metadata_source_package(MXFPackage *package, ByteIOContext *pb, int tag) +static int mxf_read_source_package(MXFPackage *package, ByteIOContext *pb, int tag) { switch(tag) { case 0x4403: @@ -479,6 +515,8 @@ static int mxf_read_metadata_source_package(MXFPackage *package, ByteIOContext * if (package->tracks_count >= UINT_MAX / sizeof(UID)) return -1; package->tracks_refs = av_malloc(package->tracks_count * sizeof(UID)); + if (!package->tracks_refs) + return -1; url_fskip(pb, 4); /* useless size of objects, always 16 according to specs */ get_buffer(pb, (uint8_t *)package->tracks_refs, package->tracks_count * sizeof(UID)); break; @@ -494,7 +532,7 @@ static int mxf_read_metadata_source_package(MXFPackage *package, ByteIOContext * return 0; } -static void mxf_read_metadata_pixel_layout(ByteIOContext *pb, MXFDescriptor *descriptor) +static void mxf_read_pixel_layout(ByteIOContext *pb, MXFDescriptor *descriptor) { int code; @@ -517,7 +555,7 @@ static void mxf_read_metadata_pixel_layout(ByteIOContext *pb, MXFDescriptor *des } while (code != 0); /* SMPTE 377M E.2.46 */ } -static int mxf_read_metadata_generic_descriptor(MXFDescriptor *descriptor, ByteIOContext *pb, int tag, int size) +static int mxf_read_generic_descriptor(MXFDescriptor *descriptor, ByteIOContext *pb, int tag, int size, UID uid) { switch(tag) { case 0x3F01: @@ -525,6 +563,8 @@ static int mxf_read_metadata_generic_descriptor(MXFDescriptor *descriptor, ByteI if (descriptor->sub_descriptors_count >= UINT_MAX / sizeof(UID)) return -1; descriptor->sub_descriptors_refs = av_malloc(descriptor->sub_descriptors_count * sizeof(UID)); + if (!descriptor->sub_descriptors_refs) + return -1; url_fskip(pb, 4); /* useless size of objects, always 16 according to specs */ get_buffer(pb, (uint8_t *)descriptor->sub_descriptors_refs, descriptor->sub_descriptors_count * sizeof(UID)); break; @@ -561,12 +601,17 @@ static int mxf_read_metadata_generic_descriptor(MXFDescriptor *descriptor, ByteI descriptor->bits_per_sample = get_be32(pb); break; case 0x3401: - mxf_read_metadata_pixel_layout(pb, descriptor); + mxf_read_pixel_layout(pb, descriptor); break; - case 0x8201: /* Private tag used by SONY C0023S01.mxf */ - descriptor->extradata = av_malloc(size); - descriptor->extradata_size = size; - get_buffer(pb, descriptor->extradata, size); + default: + /* Private uid used by SONY C0023S01.mxf */ + if (IS_KLV_KEY(uid, mxf_sony_mpeg4_extradata)) { + descriptor->extradata = av_malloc(size); + if (!descriptor->extradata) + return -1; + descriptor->extradata_size = size; + get_buffer(pb, descriptor->extradata, size); + } break; } return 0; @@ -582,55 +627,56 @@ static const MXFDataDefinitionUL mxf_data_definition_uls[] = { static const MXFCodecUL mxf_codec_uls[] = { /* PictureEssenceCoding */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x02,0x02,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* 422P@ML I-Frame */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x04,0x02,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* 422P@HL I-Frame */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x04,0x03,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* 422P@HL Long GoP */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x11,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* MP@ML Long GoP */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x02,0x03,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* 422P@ML Long GoP */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x03,0x03,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* MP@HL Long GoP */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x20,0x02,0x03 }, CODEC_ID_MPEG4, Frame }, /* XDCAM proxy_pal030926.mxf */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x20,0x02,0x04 }, CODEC_ID_MPEG4, Frame }, /* XDCAM Proxy C0023S01.mxf */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x01,0x02,0x01,0x05 }, CODEC_ID_MPEG2VIDEO, Frame }, /* D-10 30Mbps PAL */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x01,0x02,0x01,0x01 }, CODEC_ID_MPEG2VIDEO, Frame }, /* D-10 50Mbps PAL */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x04,0x00 }, CODEC_ID_DVVIDEO, Frame }, /* DVCPRO50 PAL */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x02,0x00 }, CODEC_ID_DVVIDEO, Frame }, /* DVCPRO25 PAL */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x01,0x02,0x00 }, CODEC_ID_DVVIDEO, Frame }, /* DV25 IEC PAL */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, CODEC_ID_JPEG2000, Frame }, /* JPEG2000 Codestream */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x01,0x7F,0x00,0x00,0x00 }, CODEC_ID_RAWVIDEO, Frame }, /* Uncompressed */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x11,0x00 }, 14, CODEC_ID_MPEG2VIDEO }, /* MP@ML Long GoP */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x01,0x02,0x01,0x01 }, 14, CODEC_ID_MPEG2VIDEO }, /* D-10 50Mbps PAL */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x03,0x03,0x00 }, 14, CODEC_ID_MPEG2VIDEO }, /* MP@HL Long GoP */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x04,0x02,0x00 }, 14, CODEC_ID_MPEG2VIDEO }, /* 422P@HL I-Frame */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x20,0x02,0x03 }, 14, CODEC_ID_MPEG4 }, /* XDCAM proxy_pal030926.mxf */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x01,0x02,0x00 }, 13, CODEC_ID_DVVIDEO }, /* DV25 IEC PAL */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x01,0x7F,0x00,0x00,0x00 }, 13, CODEC_ID_RAWVIDEO }, /* Uncompressed */ /* SoundEssenceCompression */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, CODEC_ID_PCM_S16LE, Frame }, /* Uncompressed */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x7F,0x00,0x00,0x00 }, CODEC_ID_PCM_S16LE, Frame }, - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x02,0x02,0x01,0x7E,0x00,0x00,0x00 }, CODEC_ID_PCM_S16BE, Frame }, /* From Omneon MXF file */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x01,0x01,0x00 }, CODEC_ID_PCM_ALAW, Frame }, - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x04,0x04,0x02,0x02,0x02,0x03,0x01,0x01,0x00 }, CODEC_ID_PCM_ALAW, Frame }, /* XDCAM Proxy C0023S01.mxf */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x02,0x01,0x00 }, CODEC_ID_AC3, Frame }, - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x02,0x05,0x00 }, CODEC_ID_MP2, Frame }, /* MP2 or MP3 */ - //{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x02,0x1C,0x00 }, CODEC_ID_DOLBY_E, Frame }, /* Dolby-E */ - { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, CODEC_ID_NONE, Frame }, + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, 13, CODEC_ID_PCM_S16LE }, /* Uncompressed */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x7F,0x00,0x00,0x00 }, 13, CODEC_ID_PCM_S16LE }, + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x02,0x02,0x01,0x7E,0x00,0x00,0x00 }, 13, CODEC_ID_PCM_S16BE }, /* From Omneon MXF file */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x04,0x04,0x02,0x02,0x02,0x03,0x01,0x01,0x00 }, 15, CODEC_ID_PCM_ALAW }, /* XDCAM Proxy C0023S01.mxf */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x02,0x01,0x00 }, 15, CODEC_ID_AC3 }, + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x02,0x05,0x00 }, 15, CODEC_ID_MP2 }, /* MP2 or MP3 */ + //{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x02,0x03,0x02,0x1C,0x00 }, 15, CODEC_ID_DOLBY_E }, /* Dolby-E */ + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; static const MXFCodecUL mxf_picture_essence_container_uls[] = { - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, CODEC_ID_MPEG2VIDEO, Frame }, /* MPEG-ES Frame wrapped */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0xe0,0x02 }, CODEC_ID_MPEG2VIDEO, Clip }, /* MPEG-ES Clip wrapped, 0xe0 MPV stream id */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x04,0x61,0x07 }, CODEC_ID_MPEG2VIDEO, Clip }, /* MPEG-ES Custom wrapped, 0x61 ??? stream id */ - { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, CODEC_ID_NONE, Frame }, + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; static const MXFCodecUL mxf_sound_essence_container_uls[] = { - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, CODEC_ID_PCM_S16LE, Frame }, /* BWF Frame wrapped */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x03,0x00 }, CODEC_ID_PCM_S16LE, Frame }, /* AES Frame wrapped */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, CODEC_ID_MP2, Frame }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0xc0,0x01 }, CODEC_ID_MP2, Frame }, /* MPEG-ES Frame wrapped, 0xc0 MPA stream id */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0xc0,0x02 }, CODEC_ID_MP2, Clip }, /* MPEG-ES Clip wrapped, 0xc0 MPA stream id */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x05,0x01 }, CODEC_ID_PCM_S16BE, Frame }, /* D-10 Mapping 30Mbps PAL Extended Template */ - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, CODEC_ID_PCM_S16BE, Frame }, /* D-10 Mapping 50Mbps PAL Extended Template */ - { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, CODEC_ID_NONE, Frame }, + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, CODEC_ID_MP2 }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, CODEC_ID_PCM_S16LE }, /* D-10 Mapping 50Mbps PAL Extended Template */ + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, CODEC_ID_NONE }, }; +/* + * Match an uid independently of the version byte and up to len common bytes + * Returns: boolean + */ +static int mxf_match_uid(const UID key, const UID uid, int len) +{ + int i; + for (i = 0; i < len; i++) { + if (i != 7 && key[i] != uid[i]) + return 0; + } + return 1; +} + static const MXFCodecUL *mxf_get_codec_ul(const MXFCodecUL *uls, UID *uid) { while (uls->id != CODEC_ID_NONE) { - if(!memcmp(uls->uid, *uid, 16)) + if(mxf_match_uid(uls->uid, *uid, uls->matching_len)) break; uls++; } @@ -640,7 +686,7 @@ static const MXFCodecUL *mxf_get_codec_ul(const MXFCodecUL *uls, UID *uid) static enum CodecType mxf_get_codec_type(const MXFDataDefinitionUL *uls, UID *uid) { while (uls->type != CODEC_TYPE_DATA) { - if(!memcmp(uls->uid, *uid, 16)) + if(mxf_match_uid(uls->uid, *uid, 16)) break; uls++; } @@ -740,6 +786,10 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) continue; st = av_new_stream(mxf->fc, source_track->track_id); + if (!st) { + av_log(mxf->fc, AV_LOG_ERROR, "could not allocate stream\n"); + return -1; + } st->priv_data = source_track; st->duration = component->duration; if (st->duration == -1) @@ -810,7 +860,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->width = descriptor->width; st->codec->height = descriptor->height; st->codec->bits_per_sample = descriptor->bits_per_sample; /* Uncompressed */ - st->need_parsing = 2; /* only parse headers */ + st->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul); if (st->codec->codec_id == CODEC_ID_NONE) @@ -829,71 +879,73 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->codec_id = CODEC_ID_PCM_S24BE; else if (descriptor->bits_per_sample == 32) st->codec->codec_id = CODEC_ID_PCM_S32BE; - if (descriptor->essence_container_ul[13] == 0x01) /* D-10 Mapping */ - st->codec->channels = 8; /* force channels to 8 */ } else if (st->codec->codec_id == CODEC_ID_MP2) { - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; } } - if (container_ul && container_ul->wrapping == Clip) { - dprintf(mxf->fc, "stream %d: clip wrapped essence\n", st->index); - st->need_parsing = 1; + if (st->codec->codec_type != CODEC_TYPE_DATA && (*essence_container_ul)[15] > 0x01) { + av_log(mxf->fc, AV_LOG_WARNING, "only frame wrapped mappings are correctly supported\n"); + st->need_parsing = AVSTREAM_PARSE_FULL; } } return 0; } static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_metadata_content_storage, 0, AnyType }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_metadata_source_package, sizeof(MXFPackage), SourcePackage }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_metadata_material_package, sizeof(MXFPackage), MaterialPackage }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, mxf_read_metadata_sequence, sizeof(MXFSequence), Sequence }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_metadata_source_clip, sizeof(MXFStructuralComponent), SourceClip }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor }, - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* CDCI */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x29,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* RGBA */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG 2 Video */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Wave */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_metadata_track, sizeof(MXFTrack), Track }, /* Static Track */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_metadata_track, sizeof(MXFTrack), Track }, /* Generic Track */ - { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_metadata_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_source_clip, sizeof(MXFStructuralComponent), SourceClip }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor }, + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* CDCI */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x29,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* RGBA */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG 2 Video */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Wave */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType }, }; -static int mxf_read_sync(ByteIOContext *pb, const uint8_t *key, unsigned size) -{ - int i, b; - for (i = 0; i < size && !url_feof(pb); i++) { - b = get_byte(pb); - if (b == key[0]) - i = 0; - else if (b != key[i]) - i = -1; - } - return i == size; -} - static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, int (*read_child)(), int ctx_size, enum MXFMetadataSetType type) { - ByteIOContext *pb = &mxf->fc->pb; + ByteIOContext *pb = mxf->fc->pb; MXFMetadataSet *ctx = ctx_size ? av_mallocz(ctx_size) : mxf; - uint64_t klv_end= url_ftell(pb) + klv->length; + uint64_t klv_end = url_ftell(pb) + klv->length; + if (!ctx) + return -1; while (url_ftell(pb) + 4 < klv_end) { int tag = get_be16(pb); int size = get_be16(pb); /* KLV specified by 0x53 */ - uint64_t next= url_ftell(pb) + size; + uint64_t next = url_ftell(pb) + size; + UID uid = {0}; if (!size) { /* ignore empty tag, needed for some files with empty UMID tag */ av_log(mxf->fc, AV_LOG_ERROR, "local tag 0x%04X with 0 size\n", tag); continue; } - if(ctx_size && tag == 0x3C0A) + if (tag > 0x7FFF) { /* dynamic tag */ + int i; + for (i = 0; i < mxf->local_tags_count; i++) { + int local_tag = AV_RB16(mxf->local_tags+i*18); + if (local_tag == tag) { + memcpy(uid, mxf->local_tags+i*18+2, 16); + dprintf(mxf->fc, "local tag 0x%04X\n", local_tag); +#ifdef DEBUG + PRINT_KEY(mxf->fc, "uid", uid); +#endif + } + } + } + if (ctx_size && tag == 0x3C0A) get_buffer(pb, ctx->uid, 16); - else - read_child(ctx, pb, tag, size); + else if (read_child(ctx, pb, tag, size, uid) < 0) + return -1; url_fseek(pb, next, SEEK_SET); } @@ -906,33 +958,31 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) MXFContext *mxf = s->priv_data; KLVPacket klv; - mxf->sync_key = mxf_essence_element_key; - if (!mxf_read_sync(&s->pb, mxf_header_partition_pack_key, 14)) { + 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"); return -1; } - url_fseek(&s->pb, -14, SEEK_CUR); + url_fseek(s->pb, -14, SEEK_CUR); mxf->fc = s; - while (!url_feof(&s->pb)) { + while (!url_feof(s->pb)) { const MXFMetadataReadTableEntry *metadata; - if (klv_read_packet(&klv, &s->pb) < 0) { - av_log(s, AV_LOG_ERROR, "error reading KLV packet\n"); + if (klv_read_packet(&klv, s->pb) < 0) return -1; - } #ifdef DEBUG PRINT_KEY(s, "read header", klv.key); #endif if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) || IS_KLV_KEY(klv.key, mxf_essence_element_key)) { /* FIXME avoid seek */ - url_fseek(&s->pb, klv.offset, SEEK_SET); + url_fseek(s->pb, klv.offset, SEEK_SET); break; } for (metadata = mxf_metadata_read_table; metadata->read; metadata++) { if (IS_KLV_KEY(klv.key, metadata->key)) { - if (mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type) < 0) { + int (*read)() = klv.key[5] == 0x53 ? mxf_read_local_tags : metadata->read; + if (read(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type) < 0) { av_log(s, AV_LOG_ERROR, "error reading header metadata\n"); return -1; } @@ -940,7 +990,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) } } if (!metadata->read) - url_fskip(&s->pb, klv.length); + url_fskip(s->pb, klv.length); } return mxf_parse_structural_metadata(mxf); } @@ -970,6 +1020,7 @@ static int mxf_read_close(AVFormatContext *s) } av_freep(&mxf->metadata_sets); av_freep(&mxf->aesc); + av_freep(&mxf->local_tags); return 0; } @@ -989,11 +1040,10 @@ static int mxf_probe(AVProbeData *p) { return 0; } -/* rudimentary binary seek */ +/* rudimentary byte seek */ /* XXX: use MXF Index */ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) { - MXFContext *mxf = s->priv_data; AVStream *st = s->streams[stream_index]; int64_t seconds; @@ -1002,12 +1052,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti if (sample_time < 0) sample_time = 0; seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den); - url_fseek(&s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET); - if (!mxf_read_sync(&s->pb, mxf->sync_key, 12)) - return -1; - - /* found KLV key */ - url_fseek(&s->pb, -12, SEEK_CUR); + url_fseek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET); av_update_cur_dts(s, st, sample_time); return 0; } diff --git a/contrib/ffmpeg/libavformat/network.h b/contrib/ffmpeg/libavformat/network.h index 3aa8ba836..d897722c9 100644 --- a/contrib/ffmpeg/libavformat/network.h +++ b/contrib/ffmpeg/libavformat/network.h @@ -18,20 +18,52 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef NETWORK_H -#define NETWORK_H +#ifndef FFMPEG_NETWORK_H +#define FFMPEG_NETWORK_H +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#include <ws2tcpip.h> + +#define ff_neterrno() WSAGetLastError() +#define FF_NETERROR(err) WSA##err +#define WSAEAGAIN WSAEWOULDBLOCK +#else #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> +#include <netdb.h> + +#define ff_neterrno() errno +#define FF_NETERROR(err) err +#endif + #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#include <netdb.h> + +int ff_socket_nonblock(int socket, int enable); + +static inline int ff_network_init(void) +{ +#ifdef HAVE_WINSOCK2_H + WSADATA wsaData; + if (WSAStartup(MAKEWORD(1,1), &wsaData)) + return 0; +#endif + return 1; +} + +static inline void ff_network_close(void) +{ +#ifdef HAVE_WINSOCK2_H + WSACleanup(); +#endif +} #if !defined(HAVE_INET_ATON) /* in os_support.c */ int inet_aton (const char * str, struct in_addr * add); #endif -#endif +#endif /* FFMPEG_NETWORK_H */ diff --git a/contrib/ffmpeg/libavformat/nsvdec.c b/contrib/ffmpeg/libavformat/nsvdec.c index 2753edbd9..a115fe571 100644 --- a/contrib/ffmpeg/libavformat/nsvdec.c +++ b/contrib/ffmpeg/libavformat/nsvdec.c @@ -91,7 +91,7 @@ struct NSVf_header { uint32_t chunk_tag; /* 'NSVf' */ uint32_t chunk_size; - uint32_t file_size; /* max 4GB ??? noone learns anything it seems :^) */ + uint32_t file_size; /* max 4GB ??? no one learns anything it seems :^) */ uint32_t file_length; //unknown1; /* what about MSB of file_size ? */ uint32_t info_strings_size; /* size of the info strings */ //unknown2; uint32_t table_entries; @@ -197,7 +197,7 @@ static const AVCodecTag nsv_codec_video_tags[] = { { CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') }, { CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') }, */ - { CODEC_ID_XVID, MKTAG('X', 'V', 'I', 'D') }, /* cf sample xvid decoder from nsv_codec_sdk.zip */ + { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, /* cf sample xvid decoder from nsv_codec_sdk.zip */ { CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', '3') }, { 0, 0 }, }; @@ -228,7 +228,7 @@ static void print_tag(const char *str, unsigned int tag, int size) static int nsv_resync(AVFormatContext *s) { NSVContext *nsv = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint32_t v = 0; int i; @@ -275,7 +275,7 @@ static int nsv_resync(AVFormatContext *s) static int nsv_parse_NSVf_header(AVFormatContext *s, AVFormatParameters *ap) { NSVContext *nsv = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; unsigned int file_size, size; int64_t duration; int strings_size; @@ -394,7 +394,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s, AVFormatParameters *ap) static int nsv_parse_NSVs_header(AVFormatContext *s, AVFormatParameters *ap) { NSVContext *nsv = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; uint32_t vtag, atag; uint16_t vwidth, vheight; AVRational framerate; @@ -474,7 +474,7 @@ static int nsv_parse_NSVs_header(AVFormatContext *s, AVFormatParameters *ap) st->codec->codec_tag = atag; st->codec->codec_id = codec_get_id(nsv_codec_audio_tags, atag); - st->need_parsing = 1; /* for PCM we will read a chunk later and put correct info */ + st->need_parsing = AVSTREAM_PARSE_FULL; /* for PCM we will read a chunk later and put correct info */ /* set timebase to common denominator of ms and framerate */ av_set_pts_info(st, 64, 1, framerate.num*1000); @@ -533,7 +533,7 @@ static int nsv_read_header(AVFormatContext *s, AVFormatParameters *ap) static int nsv_read_chunk(AVFormatContext *s, int fill_header) { NSVContext *nsv = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st[2] = {NULL, NULL}; NSVStream *nst; AVPacket *pkt; @@ -609,7 +609,8 @@ null_chunk_retry: PRINT(("NSV video: [%d] = %02x\n", i, pkt->data[i])); */ } - ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++; + if(st[NSV_ST_VIDEO]) + ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++; if (asize/*st[NSV_ST_AUDIO]*/) { nst = st[NSV_ST_AUDIO]->priv_data; @@ -626,7 +627,7 @@ null_chunk_retry: asize-=4; PRINT(("NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate)); if (fill_header) { - st[NSV_ST_AUDIO]->need_parsing = 0; /* we know everything */ + st[NSV_ST_AUDIO]->need_parsing = AVSTREAM_PARSE_NONE; /* we know everything */ if (bps != 16) { PRINT(("NSV AUDIO bit/sample != 16 (%d)!!!\n", bps)); } @@ -728,14 +729,9 @@ static int nsv_probe(AVProbeData *p) int i; // PRINT(("nsv_probe(), buf_size %d\n", p->buf_size)); /* check file header */ - if (p->buf_size <= 32) - return 0; - if (p->buf[0] == 'N' && p->buf[1] == 'S' && - p->buf[2] == 'V' && p->buf[3] == 'f') - return AVPROBE_SCORE_MAX; /* streamed files might not have any header */ if (p->buf[0] == 'N' && p->buf[1] == 'S' && - p->buf[2] == 'V' && p->buf[3] == 's') + p->buf[2] == 'V' && (p->buf[3] == 'f' || p->buf[3] == 's')) return AVPROBE_SCORE_MAX; /* XXX: do streamed files always start at chunk boundary ?? */ /* or do we need to search NSVs in the byte stream ? */ @@ -748,7 +744,7 @@ static int nsv_probe(AVProbeData *p) } /* so we'll have more luck on extension... */ if (match_ext(p->filename, "nsv")) - return AVPROBE_SCORE_MAX-20; + return AVPROBE_SCORE_MAX/2; /* FIXME: add mime-type check */ return 0; } diff --git a/contrib/ffmpeg/libavformat/nut.c b/contrib/ffmpeg/libavformat/nut.c index 995149951..fdcaac6a3 100644 --- a/contrib/ffmpeg/libavformat/nut.c +++ b/contrib/ffmpeg/libavformat/nut.c @@ -1,7 +1,6 @@ /* - * "NUT" Container Format muxer and demuxer (DRAFT-200403??) - * Copyright (c) 2003 Alex Beregszaszi - * Copyright (c) 2004 Michael Niedermayer + * nut + * Copyright (c) 2004-2007 Michael Niedermayer * * This file is part of FFmpeg. * @@ -18,1440 +17,46 @@ * 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 - * - * - * Visit the official site at http://www.nut.hu/ - * */ -/* - * TODO: - * - index writing - * - index packet reading support -*/ - -//#define DEBUG 1 - -#include <limits.h> -#include "avformat.h" -#include "mpegaudio.h" -#include "riff.h" -#include "adler32.h" - -#undef NDEBUG -#include <assert.h> - -//#define TRACE - -//from /dev/random - -#define MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48)) -#define STREAM_STARTCODE (0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48)) -#define KEYFRAME_STARTCODE (0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48)) -#define INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48)) -#define INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48)) - -#define ID_STRING "nut/multimedia container\0" - -#define MAX_DISTANCE (1024*16-1) -#define MAX_SHORT_DISTANCE (1024*4-1) - -#define FLAG_DATA_SIZE 1 -#define FLAG_KEY_FRAME 2 -#define FLAG_INVALID 4 - -typedef struct { - uint8_t flags; - uint8_t stream_id_plus1; - uint16_t size_mul; - uint16_t size_lsb; - int16_t timestamp_delta; - uint8_t reserved_count; -} FrameCode; - -typedef struct { - int last_key_frame; - int msb_timestamp_shift; - int rate_num; - int rate_den; - int64_t last_pts; - int64_t last_sync_pos; ///<pos of last 1/2 type frame - int decode_delay; -} StreamContext; - -typedef struct { - AVFormatContext *avf; - int written_packet_size; - int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes - FrameCode frame_code[256]; - unsigned int stream_count; - uint64_t next_startcode; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable - StreamContext *stream; - int max_distance; - int max_short_distance; - int rate_num; - int rate_den; - int short_startcode; -} NUTContext; - -static char *info_table[][2]={ - {NULL , NULL }, // end - {NULL , NULL }, - {NULL , "UTF8"}, - {NULL , "v"}, - {NULL , "s"}, - {"StreamId" , "v"}, - {"SegmentId" , "v"}, - {"StartTimestamp" , "v"}, - {"EndTimestamp" , "v"}, - {"Author" , "UTF8"}, - {"Title" , "UTF8"}, - {"Description" , "UTF8"}, - {"Copyright" , "UTF8"}, - {"Encoder" , "UTF8"}, - {"Keyword" , "UTF8"}, - {"Cover" , "JPEG"}, - {"Cover" , "PNG"}, -}; - -static void update(NUTContext *nut, int stream_index, int64_t frame_start, int frame_type, int frame_code, int key_frame, int size, int64_t pts){ - StreamContext *stream= &nut->stream[stream_index]; - - stream->last_key_frame= key_frame; - nut->packet_start[ frame_type ]= frame_start; - stream->last_pts= pts; -} +#include "nut.h" +#include "tree.h" -static void reset(AVFormatContext *s, int64_t global_ts){ - NUTContext *nut = s->priv_data; +void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val){ int i; - - for(i=0; i<s->nb_streams; i++){ - StreamContext *stream= &nut->stream[i]; - - stream->last_key_frame= 1; - - stream->last_pts= av_rescale(global_ts, stream->rate_num*(int64_t)nut->rate_den, stream->rate_den*(int64_t)nut->rate_num); - } -} - -static void build_frame_code(AVFormatContext *s){ - NUTContext *nut = s->priv_data; - int key_frame, index, pred, stream_id; - int start=0; - int end= 255; - int keyframe_0_esc= s->nb_streams > 2; - int pred_table[10]; - - if(keyframe_0_esc){ - /* keyframe = 0 escape */ - FrameCode *ft= &nut->frame_code[start]; - ft->flags= FLAG_DATA_SIZE; - ft->stream_id_plus1= 0; - ft->size_mul=1; - ft->timestamp_delta=0; - start++; - } - - for(stream_id= 0; stream_id<s->nb_streams; stream_id++){ - int start2= start + (end-start)*stream_id / s->nb_streams; - int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; - AVCodecContext *codec = s->streams[stream_id]->codec; - int is_audio= codec->codec_type == CODEC_TYPE_AUDIO; - int intra_only= /*codec->intra_only || */is_audio; - int pred_count; - - for(key_frame=0; key_frame<2; key_frame++){ - if(intra_only && keyframe_0_esc && key_frame==0) - continue; - - { - FrameCode *ft= &nut->frame_code[start2]; - ft->flags= FLAG_KEY_FRAME*key_frame; - ft->flags|= FLAG_DATA_SIZE; - ft->stream_id_plus1= stream_id + 1; - ft->size_mul=1; - ft->timestamp_delta=0; - start2++; - } - } - - 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; - for(pts=0; pts<2; pts++){ - for(pred=0; pred<2; pred++){ - FrameCode *ft= &nut->frame_code[start2]; - ft->flags= FLAG_KEY_FRAME*key_frame; - ft->stream_id_plus1= stream_id + 1; - ft->size_mul=frame_bytes + 2; - ft->size_lsb=frame_bytes + pred; - ft->timestamp_delta=pts; - start2++; - } - } - }else{ - FrameCode *ft= &nut->frame_code[start2]; - ft->flags= FLAG_KEY_FRAME | FLAG_DATA_SIZE; - ft->stream_id_plus1= stream_id + 1; - ft->size_mul=1; - ft->timestamp_delta=1; - start2++; - } -#endif - - if(codec->has_b_frames){ - pred_count=5; - pred_table[0]=-2; - pred_table[1]=-1; - pred_table[2]=1; - pred_table[3]=3; - pred_table[4]=4; - }else if(codec->codec_id == CODEC_ID_VORBIS){ - pred_count=3; - pred_table[0]=2; - pred_table[1]=9; - pred_table[2]=16; - }else{ - pred_count=1; - pred_table[0]=1; - } - - for(pred=0; pred<pred_count; pred++){ - int start3= start2 + (end2-start2)*pred / pred_count; - int end3 = start2 + (end2-start2)*(pred+1) / pred_count; - - for(index=start3; index<end3; index++){ - FrameCode *ft= &nut->frame_code[index]; - ft->flags= FLAG_KEY_FRAME*key_frame; - ft->flags|= FLAG_DATA_SIZE; - ft->stream_id_plus1= stream_id + 1; -//FIXME use single byte size and pred from last - ft->size_mul= end3-start3; - ft->size_lsb= index - start3; - ft->timestamp_delta= pred_table[pred]; - } - } - } - memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); - nut->frame_code['N'].flags= FLAG_INVALID; -} - -static uint64_t get_v(ByteIOContext *bc) -{ - uint64_t val = 0; - - for(;;) - { - int tmp = get_byte(bc); - - if (tmp&0x80) - val= (val<<7) + tmp - 0x80; - else{ -//av_log(NULL, AV_LOG_DEBUG, "get_v()= %"PRId64"\n", (val<<7) + tmp); - return (val<<7) + tmp; - } + for(i=0; i<nut->avf->nb_streams; i++){ + nut->stream[i].last_pts= av_rescale_rnd( + val, + time_base.num * (int64_t)nut->stream[i].time_base->den, + time_base.den * (int64_t)nut->stream[i].time_base->num, + AV_ROUND_DOWN); } - return -1; -} - -static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ - unsigned int len= get_v(bc); - - if(len && maxlen) - get_buffer(bc, string, FFMIN(len, maxlen)); - while(len > maxlen){ - get_byte(bc); - len--; - } - - if(maxlen) - string[FFMIN(len, maxlen-1)]= 0; - - if(maxlen == len) - return -1; - else - return 0; -} - -static int64_t get_s(ByteIOContext *bc){ - int64_t v = get_v(bc) + 1; - - if (v&1) return -(v>>1); - else return (v>>1); -} - -static uint64_t get_vb(ByteIOContext *bc){ - uint64_t val=0; - unsigned int i= get_v(bc); - - if(i>8) - return UINT64_MAX; - - while(i--) - val = (val<<8) + get_byte(bc); - -//av_log(NULL, AV_LOG_DEBUG, "get_vb()= %"PRId64"\n", val); - return val; -} - -#ifdef TRACE -static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){ - uint64_t v= get_v(bc); - - printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); - return v; -} - -static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){ - int64_t v= get_s(bc); - - printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); - return v; -} - -static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){ - uint64_t v= get_vb(bc); - - printf("get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); - return v; -} -#define get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#endif - - -static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum) -{ - int64_t start, size; - start= url_ftell(bc) - 8; - - size= get_v(bc); - - init_checksum(bc, calculate_checksum ? av_adler32_update : NULL, 1); - - nut->packet_start[2] = start; - nut->written_packet_size= size; - - return size; -} - -static int check_checksum(ByteIOContext *bc){ - unsigned long checksum= get_checksum(bc); - return checksum != get_be32(bc); -} - -/** - * - */ -static int get_length(uint64_t val){ - int i; - - for (i=7; val>>i; i+=7); - - return i; } -static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ - uint64_t state=0; - - if(pos >= 0) - url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently - - while(!url_feof(bc)){ - state= (state<<8) | get_byte(bc); - if((state>>56) != 'N') - continue; - switch(state){ - case MAIN_STARTCODE: - case STREAM_STARTCODE: - case KEYFRAME_STARTCODE: - case INFO_STARTCODE: - case INDEX_STARTCODE: - return state; - } - } - - return 0; -} - -/** - * find the given startcode. - * @param code the startcode - * @param pos the start position of the search, or -1 if the current position - * @returns the position of the startcode or -1 if not found - */ -static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ - for(;;){ - uint64_t startcode= find_any_startcode(bc, pos); - if(startcode == code) - return url_ftell(bc) - 8; - else if(startcode == 0) - return -1; - pos=-1; - } -} - -static int64_t lsb2full(StreamContext *stream, int64_t lsb){ - int64_t mask = (1<<stream->msb_timestamp_shift)-1; +int64_t ff_lsb2full(StreamContext *stream, int64_t lsb){ + int64_t mask = (1<<stream->msb_pts_shift)-1; int64_t delta= stream->last_pts - mask/2; return ((lsb - delta)&mask) + delta; } -#ifdef CONFIG_MUXERS - -static void put_v(ByteIOContext *bc, uint64_t val) -{ - int i; - -//av_log(NULL, AV_LOG_DEBUG, "put_v()= %"PRId64"\n", val); - val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently - i= get_length(val); - - for (i-=7; i>0; i-=7){ - put_byte(bc, 0x80 | (val>>i)); - } - - put_byte(bc, val&0x7f); -} - -/** - * stores a string as vb. - */ -static void put_str(ByteIOContext *bc, const char *string){ - int len= strlen(string); - - put_v(bc, len); - put_buffer(bc, string, len); -} - -static void put_s(ByteIOContext *bc, int64_t val){ - if (val<=0) put_v(bc, -2*val ); - else put_v(bc, 2*val-1); -} - -static void put_vb(ByteIOContext *bc, uint64_t val){ - int i; - - for (i=8; val>>i; i+=8); - - put_v(bc, i>>3); - for(i-=8; i>=0; i-=8) - put_byte(bc, (val>>i)&0xFF); -} - -#ifdef TRACE -static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ - printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); - - put_v(bc, v); -} - -static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){ - printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); - - put_s(bc, v); -} - -static inline void put_vb_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ - printf("get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); - - put_vb(bc, v); -} -#define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#define put_vb(bc, v) put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) -#endif - -static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum) -{ - put_flush_packet(bc); - nut->packet_start[2]= url_ftell(bc) - 8; - nut->written_packet_size = max_size; - - /* packet header */ - put_v(bc, nut->written_packet_size); /* forward ptr */ - - if(calculate_checksum) - init_checksum(bc, av_adler32_update, 1); - - return 0; -} - -/** - * - * must not be called more then once per packet - */ -static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){ - int64_t start= nut->packet_start[2]; - int64_t cur= url_ftell(bc); - int size= cur - start - get_length(nut->written_packet_size)/7 - 8; - - if(calculate_checksum) - size += 4; - - if(size != nut->written_packet_size){ - int i; - - assert( size <= nut->written_packet_size ); - - url_fseek(bc, start + 8, SEEK_SET); - for(i=get_length(size); i < get_length(nut->written_packet_size); i+=7) - put_byte(bc, 0x80); - put_v(bc, size); - - url_fseek(bc, cur, SEEK_SET); - nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ - - if(calculate_checksum) - put_be32(bc, get_checksum(bc)); - } - - return 0; -} - -static int nut_write_header(AVFormatContext *s) -{ - NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; - AVCodecContext *codec; - int i, j, tmp_time, tmp_flags,tmp_stream, tmp_mul, tmp_size, tmp_fields; - - if (strcmp(s->filename, "./data/b-libav.nut")) { - av_log(s, AV_LOG_ERROR, " libavformat NUT is non-compliant and disabled\n"); - return -1; - } - - nut->avf= s; - - nut->stream = - av_mallocz(sizeof(StreamContext)*s->nb_streams); - - - put_buffer(bc, ID_STRING, strlen(ID_STRING)); - put_byte(bc, 0); - nut->packet_start[2]= url_ftell(bc); - - /* main header */ - put_be64(bc, MAIN_STARTCODE); - put_packetheader(nut, bc, 120+5*256, 1); - put_v(bc, 2); /* version */ - put_v(bc, s->nb_streams); - put_v(bc, MAX_DISTANCE); - put_v(bc, MAX_SHORT_DISTANCE); - - put_v(bc, nut->rate_num=1); - put_v(bc, nut->rate_den=2); - put_v(bc, nut->short_startcode=0x4EFE79); - - build_frame_code(s); - assert(nut->frame_code['N'].flags == FLAG_INVALID); - - tmp_time= tmp_flags= tmp_stream= tmp_mul= tmp_size= /*tmp_res=*/ INT_MAX; - for(i=0; i<256;){ - tmp_fields=0; - tmp_size= 0; - if(tmp_time != nut->frame_code[i].timestamp_delta) tmp_fields=1; - if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2; - if(tmp_stream != nut->frame_code[i].stream_id_plus1) tmp_fields=3; - if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4; -// if(tmp_res != nut->frame_code[i].res ) tmp_fields=5; - - tmp_time = nut->frame_code[i].timestamp_delta; - tmp_flags = nut->frame_code[i].flags; - tmp_stream= nut->frame_code[i].stream_id_plus1; - tmp_mul = nut->frame_code[i].size_mul; - tmp_size = nut->frame_code[i].size_lsb; -// tmp_res = nut->frame_code[i].res; - - for(j=0; i<256; j++,i++){ - if(nut->frame_code[i].timestamp_delta != tmp_time ) break; - if(nut->frame_code[i].flags != tmp_flags ) break; - if(nut->frame_code[i].stream_id_plus1 != tmp_stream) break; - if(nut->frame_code[i].size_mul != tmp_mul ) break; - if(nut->frame_code[i].size_lsb != tmp_size+j) break; -// if(nut->frame_code[i].res != tmp_res ) break; - } - if(j != tmp_mul - tmp_size) tmp_fields=6; - - put_v(bc, tmp_flags); - put_v(bc, tmp_fields); - if(tmp_fields>0) put_s(bc, tmp_time); - if(tmp_fields>1) put_v(bc, tmp_mul); - if(tmp_fields>2) put_v(bc, tmp_stream); - if(tmp_fields>3) put_v(bc, tmp_size); - if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/); - if(tmp_fields>5) put_v(bc, j); - } - - update_packetheader(nut, bc, 0, 1); - - /* stream headers */ - for (i = 0; i < s->nb_streams; i++) - { - int nom, denom, ssize; - - codec = s->streams[i]->codec; - - put_be64(bc, STREAM_STARTCODE); - put_packetheader(nut, bc, 120 + codec->extradata_size, 1); - put_v(bc, i /*s->streams[i]->index*/); - switch(codec->codec_type){ - case CODEC_TYPE_VIDEO: put_v(bc, 0); break; - case CODEC_TYPE_AUDIO: put_v(bc, 1); break; -// case CODEC_TYPE_TEXT : put_v(bc, 2); break; - case CODEC_TYPE_DATA : put_v(bc, 3); break; - default: return -1; - } - if (codec->codec_tag) - put_vb(bc, codec->codec_tag); - else if (codec->codec_type == CODEC_TYPE_VIDEO) - { - put_vb(bc, codec_get_bmp_tag(codec->codec_id)); - } - else if (codec->codec_type == CODEC_TYPE_AUDIO) - { - put_vb(bc, codec_get_wav_tag(codec->codec_id)); - } - else - put_vb(bc, 0); - - ff_parse_specific_params(codec, &nom, &ssize, &denom); - - nut->stream[i].rate_num= nom; - nut->stream[i].rate_den= denom; - av_set_pts_info(s->streams[i], 60, denom, nom); - - put_v(bc, codec->bit_rate); - put_vb(bc, 0); /* no language code */ - put_v(bc, nom); - put_v(bc, denom); - if(nom / denom < 1000) - nut->stream[i].msb_timestamp_shift = 7; - else - nut->stream[i].msb_timestamp_shift = 14; - put_v(bc, nut->stream[i].msb_timestamp_shift); - put_v(bc, codec->has_b_frames); - put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ - - if(codec->extradata_size){ - put_v(bc, 1); - put_v(bc, codec->extradata_size); - put_buffer(bc, codec->extradata, codec->extradata_size); - } - put_v(bc, 0); /* end of codec specific headers */ - - switch(codec->codec_type) - { - case CODEC_TYPE_AUDIO: - put_v(bc, codec->sample_rate); - put_v(bc, 1); - put_v(bc, codec->channels); - break; - case CODEC_TYPE_VIDEO: - put_v(bc, codec->width); - put_v(bc, codec->height); - put_v(bc, codec->sample_aspect_ratio.num); - put_v(bc, codec->sample_aspect_ratio.den); - put_v(bc, 0); /* csp type -- unknown */ - break; - default: - break; - } - update_packetheader(nut, bc, 0, 1); - } - - /* info header */ - put_be64(bc, INFO_STARTCODE); - put_packetheader(nut, bc, 30+strlen(s->author)+strlen(s->title)+ - strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT), 1); - if (s->author[0]) - { - put_v(bc, 9); /* type */ - put_str(bc, s->author); - } - if (s->title[0]) - { - put_v(bc, 10); /* type */ - put_str(bc, s->title); - } - if (s->comment[0]) - { - put_v(bc, 11); /* type */ - put_str(bc, s->comment); - } - if (s->copyright[0]) - { - put_v(bc, 12); /* type */ - put_str(bc, s->copyright); - } - /* encoder */ - if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)){ - put_v(bc, 13); /* type */ - put_str(bc, LIBAVFORMAT_IDENT); - } - - put_v(bc, 0); /* eof info */ - update_packetheader(nut, bc, 0, 1); - - put_flush_packet(bc); - - return 0; -} - -static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - NUTContext *nut = s->priv_data; - StreamContext *stream= &nut->stream[pkt->stream_index]; - ByteIOContext *bc = &s->pb; - int key_frame = 0, full_pts=0; - AVCodecContext *enc; - int64_t coded_pts; - int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb, time_delta; - const int64_t frame_start= url_ftell(bc); - int64_t pts= pkt->pts; - int size= pkt->size; - int stream_index= pkt->stream_index; - - enc = s->streams[stream_index]->codec; - key_frame = !!(pkt->flags & PKT_FLAG_KEY); - - frame_type=0; - if(frame_start + size + 20 - FFMAX(nut->packet_start[1], nut->packet_start[2]) > MAX_DISTANCE) - frame_type=2; - if(key_frame && !stream->last_key_frame) - frame_type=2; - - if(frame_type>1){ - int64_t global_ts= av_rescale(pts, stream->rate_den*(int64_t)nut->rate_num, stream->rate_num*(int64_t)nut->rate_den); - reset(s, global_ts); - put_be64(bc, KEYFRAME_STARTCODE); - put_v(bc, global_ts); - } - assert(stream->last_pts != AV_NOPTS_VALUE); - coded_pts = pts & ((1<<stream->msb_timestamp_shift)-1); - if(lsb2full(stream, coded_pts) != pts) - full_pts=1; - - if(full_pts) - coded_pts= pts + (1<<stream->msb_timestamp_shift); - - best_length=INT_MAX; - frame_code= -1; - for(i=0; i<256; i++){ - int stream_id_plus1= nut->frame_code[i].stream_id_plus1; - int fc_key_frame; - int length=0; - size_mul= nut->frame_code[i].size_mul; - size_lsb= nut->frame_code[i].size_lsb; - time_delta= nut->frame_code[i].timestamp_delta; - flags= nut->frame_code[i].flags; - - assert(size_mul > size_lsb); - - if(stream_id_plus1 == 0) length+= get_length(stream_index); - else if(stream_id_plus1 - 1 != stream_index) - continue; - fc_key_frame= !!(flags & FLAG_KEY_FRAME); - - assert(key_frame==0 || key_frame==1); - if(fc_key_frame != key_frame) - continue; - - if(flags & FLAG_DATA_SIZE){ - if(size % size_mul != size_lsb) - continue; - length += get_length(size / size_mul); - }else if(size != size_lsb) - continue; - - if(full_pts && time_delta) - continue; - - if(!time_delta){ - length += get_length(coded_pts); - }else{ - if(time_delta != pts - stream->last_pts) - continue; - } - - if(length < best_length){ - best_length= length; - frame_code=i; - } -// av_log(s, AV_LOG_DEBUG, "%d %d %d %d %d %d %d %d %d %d\n", key_frame, frame_type, full_pts, size, stream_index, flags, size_mul, size_lsb, stream_id_plus1, length); - } - - assert(frame_code != -1); - flags= nut->frame_code[frame_code].flags; - size_mul= nut->frame_code[frame_code].size_mul; - size_lsb= nut->frame_code[frame_code].size_lsb; - time_delta= nut->frame_code[frame_code].timestamp_delta; -#ifdef TRACE - best_length /= 7; - best_length ++; //frame_code - if(frame_type==2){ - best_length += 8; // startcode - } - av_log(s, AV_LOG_DEBUG, "kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d pts:%"PRId64" fs:%"PRId64"\n", key_frame, frame_type, full_pts ? 1 : 0, frame_code, best_length, size, stream_index, flags, size_mul, size_lsb, nut->frame_code[frame_code].stream_id_plus1,(int)(pts - stream->last_pts), pts, frame_start); -// av_log(s, AV_LOG_DEBUG, "%d %d %d\n", stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]); -#endif - - assert(frame_type != 1); //short startcode not implemented yet - put_byte(bc, frame_code); - - if(nut->frame_code[frame_code].stream_id_plus1 == 0) - put_v(bc, stream_index); - if (!time_delta){ - put_v(bc, coded_pts); - } - if(flags & FLAG_DATA_SIZE) - put_v(bc, size / size_mul); - else - assert(size == size_lsb); - if(size > MAX_DISTANCE){ - assert(frame_type > 1); - } - - put_buffer(bc, pkt->data, size); - - update(nut, stream_index, frame_start, frame_type, frame_code, key_frame, size, pts); - - return 0; +int ff_nut_sp_pos_cmp(syncpoint_t *a, syncpoint_t *b){ + return ((a->pos - b->pos) >> 32) - ((b->pos - a->pos) >> 32); } -static int nut_write_trailer(AVFormatContext *s) -{ - NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; - -#if 0 - int i; - - /* WRITE INDEX */ - - for (i = 0; s->nb_streams; i++) - { - put_be64(bc, INDEX_STARTCODE); - put_packetheader(nut, bc, 64, 1); - put_v(bc, s->streams[i]->id); - put_v(bc, ...); - update_packetheader(nut, bc, 0, 1); - } -#endif - - put_flush_packet(bc); - - av_freep(&nut->stream); - - return 0; +int ff_nut_sp_pts_cmp(syncpoint_t *a, syncpoint_t *b){ + return ((a->ts - b->ts) >> 32) - ((b->ts - a->ts) >> 32); } -#endif //CONFIG_MUXERS -static int nut_probe(AVProbeData *p) -{ - int i; - uint64_t code= 0xff; +void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts){ + syncpoint_t *sp= av_mallocz(sizeof(syncpoint_t)); + struct AVTreeNode *node= av_mallocz(av_tree_node_size); - for (i = 0; i < p->buf_size; i++) { - code = (code << 8) | p->buf[i]; - if (code == MAIN_STARTCODE) - return AVPROBE_SCORE_MAX; + sp->pos= pos; + sp->back_ptr= back_ptr; + sp->ts= ts; + av_tree_insert(&nut->syncpoints, sp, ff_nut_sp_pos_cmp, &node); + if(node){ + av_free(sp); + av_free(node); } - return 0; } - -static int decode_main_header(NUTContext *nut){ - AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; - uint64_t tmp; - int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res; - - get_packetheader(nut, bc, 1); - - tmp = get_v(bc); - if (tmp != 2){ - av_log(s, AV_LOG_ERROR, "bad version (%"PRId64")\n", tmp); - return -1; - } - - nut->stream_count = get_v(bc); - if(nut->stream_count > MAX_STREAMS){ - av_log(s, AV_LOG_ERROR, "too many streams\n"); - return -1; - } - nut->max_distance = get_v(bc); - nut->max_short_distance = get_v(bc); - nut->rate_num= get_v(bc); - nut->rate_den= get_v(bc); - nut->short_startcode= get_v(bc); - if(nut->short_startcode>>16 != 'N'){ - av_log(s, AV_LOG_ERROR, "invalid short startcode %X\n", nut->short_startcode); - return -1; - } - - for(i=0; i<256;){ - int tmp_flags = get_v(bc); - int tmp_fields= get_v(bc); - if(tmp_fields>0) tmp_time = get_s(bc); - if(tmp_fields>1) tmp_mul = get_v(bc); - if(tmp_fields>2) tmp_stream= get_v(bc); - if(tmp_fields>3) tmp_size = get_v(bc); - else tmp_size = 0; - if(tmp_fields>4) tmp_res = get_v(bc); - else tmp_res = 0; - if(tmp_fields>5) count = get_v(bc); - else count = tmp_mul - tmp_size; - - while(tmp_fields-- > 6) - get_v(bc); - - if(count == 0 || i+count > 256){ - av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i); - return -1; - } - if(tmp_stream > nut->stream_count + 1){ - av_log(s, AV_LOG_ERROR, "illegal stream number\n"); - return -1; - } - - for(j=0; j<count; j++,i++){ - nut->frame_code[i].flags = tmp_flags ; - nut->frame_code[i].timestamp_delta = tmp_time ; - nut->frame_code[i].stream_id_plus1 = tmp_stream; - nut->frame_code[i].size_mul = tmp_mul ; - nut->frame_code[i].size_lsb = tmp_size+j; - nut->frame_code[i].reserved_count = tmp_res ; - } - } - if(nut->frame_code['N'].flags != FLAG_INVALID){ - av_log(s, AV_LOG_ERROR, "illegal frame_code table\n"); - return -1; - } - - if(check_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n"); - return -1; - } - - return 0; -} - -static int decode_stream_header(NUTContext *nut){ - AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; - int class, nom, denom, stream_id; - uint64_t tmp; - AVStream *st; - - get_packetheader(nut, bc, 1); - stream_id= get_v(bc); - if(stream_id >= nut->stream_count || s->streams[stream_id]) - return -1; - - st = av_new_stream(s, stream_id); - if (!st) - return AVERROR_NOMEM; - - class = get_v(bc); - tmp = get_vb(bc); - st->codec->codec_tag= tmp; - switch(class) - { - case 0: - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = codec_get_bmp_id(tmp); - if (st->codec->codec_id == CODEC_ID_NONE) - av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); - break; - case 1: - case 32: //compatibility - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = codec_get_wav_id(tmp); - if (st->codec->codec_id == CODEC_ID_NONE) - av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); - break; - case 2: -// st->codec->codec_type = CODEC_TYPE_TEXT; -// break; - case 3: - st->codec->codec_type = CODEC_TYPE_DATA; - break; - default: - av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class); - return -1; - } - s->bit_rate += get_v(bc); - get_vb(bc); /* language code */ - nom = get_v(bc); - denom = get_v(bc); - nut->stream[stream_id].msb_timestamp_shift = get_v(bc); - st->codec->has_b_frames= - nut->stream[stream_id].decode_delay= get_v(bc); - get_byte(bc); /* flags */ - - /* codec specific data headers */ - while(get_v(bc) != 0){ - st->codec->extradata_size= get_v(bc); - if((unsigned)st->codec->extradata_size > (1<<30)) - return -1; - st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(bc, st->codec->extradata, st->codec->extradata_size); -// url_fskip(bc, get_v(bc)); - } - - if (st->codec->codec_type == CODEC_TYPE_VIDEO) /* VIDEO */ - { - st->codec->width = get_v(bc); - st->codec->height = get_v(bc); - st->codec->sample_aspect_ratio.num= get_v(bc); - st->codec->sample_aspect_ratio.den= get_v(bc); - get_v(bc); /* csp type */ - } - if (st->codec->codec_type == CODEC_TYPE_AUDIO) /* AUDIO */ - { - st->codec->sample_rate = get_v(bc); - get_v(bc); // samplerate_den - st->codec->channels = get_v(bc); - } - if(check_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Stream header %d checksum mismatch\n", stream_id); - return -1; - } - av_set_pts_info(s->streams[stream_id], 60, denom, nom); - nut->stream[stream_id].rate_num= nom; - nut->stream[stream_id].rate_den= denom; - return 0; -} - -static int decode_info_header(NUTContext *nut){ - AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; - - get_packetheader(nut, bc, 1); - - for(;;){ - int id= get_v(bc); - char *name, *type, custom_name[256], custom_type[256]; - - if(!id) - break; - else if(id >= sizeof(info_table)/sizeof(info_table[0])){ - av_log(s, AV_LOG_ERROR, "info id is too large %d %zd\n", id, sizeof(info_table)/sizeof(info_table[0])); - return -1; - } - - type= info_table[id][1]; - name= info_table[id][0]; -//av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name); - - if(!type){ - get_str(bc, custom_type, sizeof(custom_type)); - type= custom_type; - } - if(!name){ - get_str(bc, custom_name, sizeof(custom_name)); - name= custom_name; - } - - if(!strcmp(type, "v")){ - get_v(bc); - }else{ - if(!strcmp(name, "Author")) - get_str(bc, s->author, sizeof(s->author)); - else if(!strcmp(name, "Title")) - get_str(bc, s->title, sizeof(s->title)); - else if(!strcmp(name, "Copyright")) - get_str(bc, s->copyright, sizeof(s->copyright)); - else if(!strcmp(name, "Description")) - get_str(bc, s->comment, sizeof(s->comment)); - else - get_str(bc, NULL, 0); - } - } - if(check_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n"); - return -1; - } - return 0; -} - -static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) -{ - NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; - int64_t pos; - int inited_stream_count; - - nut->avf= s; - - /* main header */ - pos=0; - for(;;){ - pos= find_startcode(bc, MAIN_STARTCODE, pos)+1; - if (pos<0){ - av_log(s, AV_LOG_ERROR, "no main startcode found\n"); - return -1; - } - if(decode_main_header(nut) >= 0) - break; - } - - - s->bit_rate = 0; - - nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count); - - /* stream headers */ - pos=0; - for(inited_stream_count=0; inited_stream_count < nut->stream_count;){ - pos= find_startcode(bc, STREAM_STARTCODE, pos)+1; - if (pos<0+1){ - av_log(s, AV_LOG_ERROR, "not all stream headers found\n"); - return -1; - } - if(decode_stream_header(nut) >= 0) - inited_stream_count++; - } - - /* info headers */ - pos=0; - for(;;){ - uint64_t startcode= find_any_startcode(bc, pos); - pos= url_ftell(bc); - - if(startcode==0){ - av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); - return -1; - }else if(startcode == KEYFRAME_STARTCODE){ - nut->next_startcode= startcode; - break; - }else if(startcode != INFO_STARTCODE){ - continue; - } - - decode_info_header(nut); - } - - return 0; -} - -static int decode_frame_header(NUTContext *nut, int *key_frame_ret, int64_t *pts_ret, int *stream_id_ret, int frame_code, int frame_type, int64_t frame_start){ - AVFormatContext *s= nut->avf; - StreamContext *stream; - ByteIOContext *bc = &s->pb; - int size, flags, size_mul, size_lsb, stream_id, time_delta; - int64_t pts = 0; - - if(frame_type < 2 && frame_start - nut->packet_start[2] > nut->max_distance){ - av_log(s, AV_LOG_ERROR, "last frame must have been damaged\n"); - return -1; - } - - if(frame_type) - nut->packet_start[ frame_type ]= frame_start; //otherwise 1 goto 1 may happen - - flags= nut->frame_code[frame_code].flags; - size_mul= nut->frame_code[frame_code].size_mul; - size_lsb= nut->frame_code[frame_code].size_lsb; - stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1; - time_delta= nut->frame_code[frame_code].timestamp_delta; - - if(stream_id==-1) - stream_id= get_v(bc); - if(stream_id >= s->nb_streams){ - av_log(s, AV_LOG_ERROR, "illegal stream_id\n"); - return -1; - } - stream= &nut->stream[stream_id]; - -// av_log(s, AV_LOG_DEBUG, "ft:%d ppts:%d %d %d\n", frame_type, stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]); - - *key_frame_ret= !!(flags & FLAG_KEY_FRAME); - - if(!time_delta){ - int64_t mask = (1<<stream->msb_timestamp_shift)-1; - pts= get_v(bc); - if(pts > mask){ - pts -= mask+1; - }else{ - if(stream->last_pts == AV_NOPTS_VALUE){ - av_log(s, AV_LOG_ERROR, "no reference pts available\n"); - return -1; - } - pts= lsb2full(stream, pts); - } - }else{ - if(stream->last_pts == AV_NOPTS_VALUE){ - av_log(s, AV_LOG_ERROR, "no reference pts available\n"); - return -1; - } - pts= stream->last_pts + time_delta; - } - - if(*key_frame_ret){ -// av_log(s, AV_LOG_DEBUG, "stream:%d start:%"PRId64" pts:%"PRId64" length:%"PRId64"\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos); - av_add_index_entry( - s->streams[stream_id], - frame_start, - pts, - 0, - frame_start - nut->stream[stream_id].last_sync_pos, - AVINDEX_KEYFRAME); - nut->stream[stream_id].last_sync_pos= frame_start; -// assert(nut->packet_start == frame_start); - } - - assert(size_mul > size_lsb); - size= size_lsb; - if(flags & FLAG_DATA_SIZE) - size+= size_mul*get_v(bc); - -#ifdef TRACE -av_log(s, AV_LOG_DEBUG, "fs:%"PRId64" fc:%d ft:%d kf:%d pts:%"PRId64" size:%d mul:%d lsb:%d flags:%d delta:%d\n", frame_start, frame_code, frame_type, *key_frame_ret, pts, size, size_mul, size_lsb, flags, time_delta); -#endif - - if(frame_type==0 && url_ftell(bc) - nut->packet_start[2] + size > nut->max_distance){ - av_log(s, AV_LOG_ERROR, "frame size too large\n"); - return -1; - } - - *stream_id_ret = stream_id; - *pts_ret = pts; - - update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts); - - return size; -} - -static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type, int64_t frame_start){ - AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; - int size, stream_id, key_frame, discard; - int64_t pts, last_IP_pts; - - size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, frame_start); - if(size < 0) - return -1; - - discard= s->streams[ stream_id ]->discard; - last_IP_pts= s->streams[ stream_id ]->last_IP_pts; - if( (discard >= AVDISCARD_NONKEY && !key_frame) - ||(discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts) - || discard >= AVDISCARD_ALL){ - url_fskip(bc, size); - return 1; - } - - av_get_packet(bc, pkt, size); - pkt->stream_index = stream_id; - if (key_frame) - pkt->flags |= PKT_FLAG_KEY; - pkt->pts = pts; - - return 0; -} - -static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; - int i, frame_code=0, ret; - - for(;;){ - int64_t pos= url_ftell(bc); - int frame_type= 0; - uint64_t tmp= nut->next_startcode; - nut->next_startcode=0; - - if (url_feof(bc)) - return -1; - - if(tmp){ - pos-=8; - }else{ - frame_code = get_byte(bc); - if(frame_code == 'N'){ - tmp= frame_code; - for(i=1; i<8; i++) - tmp = (tmp<<8) + get_byte(bc); - } - } - switch(tmp){ - case MAIN_STARTCODE: - case STREAM_STARTCODE: - case INDEX_STARTCODE: - get_packetheader(nut, bc, 0); - assert(nut->packet_start[2] == pos); - url_fseek(bc, nut->written_packet_size, SEEK_CUR); - break; - case INFO_STARTCODE: - if(decode_info_header(nut)<0) - goto resync; - break; - case KEYFRAME_STARTCODE: - frame_type = 2; - reset(s, get_v(bc)); - frame_code = get_byte(bc); - case 0: - ret= decode_frame(nut, pkt, frame_code, frame_type, pos); - if(ret==0) - return 0; - else if(ret==1) //ok but discard packet - break; - default: -resync: -av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1); - tmp= find_any_startcode(bc, nut->packet_start[2]+1); - if(tmp==0) - return -1; -av_log(s, AV_LOG_DEBUG, "sync\n"); - nut->next_startcode= tmp; - } - } -} - -static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ - NUTContext *nut = s->priv_data; - StreamContext *stream; - ByteIOContext *bc = &s->pb; - int64_t pos, pts; - uint64_t code; - int frame_code,step, stream_id, i,size, key_frame; -av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit); - - if(*pos_arg < 0) - return AV_NOPTS_VALUE; - - pos= *pos_arg; - step= FFMIN(16*1024, pos); - do{ - pos-= step; - code= find_any_startcode(bc, pos); - - if(code && url_ftell(bc) - 8 <= *pos_arg) - break; - step= FFMIN(2*step, pos); - }while(step); - - if(!code) //nothing found, not even after pos_arg - return AV_NOPTS_VALUE; - - url_fseek(bc, -8, SEEK_CUR); - for(i=0; i<s->nb_streams; i++) - nut->stream[i].last_sync_pos= url_ftell(bc); - - for(;;){ - int frame_type=0; - int64_t pos= url_ftell(bc); - uint64_t tmp=0; - - if(pos > pos_limit || url_feof(bc)) - return AV_NOPTS_VALUE; - - frame_code = get_byte(bc); - if(frame_code == 'N'){ - tmp= frame_code; - for(i=1; i<8; i++) - tmp = (tmp<<8) + get_byte(bc); - } -//av_log(s, AV_LOG_DEBUG, "before switch %"PRIX64" at=%"PRId64"\n", tmp, pos); - - switch(tmp){ - case MAIN_STARTCODE: - case STREAM_STARTCODE: - case INDEX_STARTCODE: - case INFO_STARTCODE: - get_packetheader(nut, bc, 0); - assert(nut->packet_start[2]==pos); - url_fseek(bc, nut->written_packet_size, SEEK_CUR); - break; - case KEYFRAME_STARTCODE: - frame_type=2; - reset(s, get_v(bc)); - frame_code = get_byte(bc); - case 0: - size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, pos); - if(size < 0) - goto resync; - - stream= &nut->stream[stream_id]; - if(stream_id != stream_index || !key_frame || pos < *pos_arg){ - url_fseek(bc, size, SEEK_CUR); - break; - } - - *pos_arg= pos; - return pts; - default: -resync: -av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", nut->packet_start[2]+1); - if(!find_any_startcode(bc, nut->packet_start[2]+1)) - return AV_NOPTS_VALUE; - - url_fseek(bc, -8, SEEK_CUR); - } - } - return AV_NOPTS_VALUE; -} - -static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){ -// NUTContext *nut = s->priv_data; - int64_t pos; - - if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0) - return -1; - - pos= url_ftell(&s->pb); - nut_read_timestamp(s, stream_index, &pos, pos-1); - - return 0; -} - -static int nut_read_close(AVFormatContext *s) -{ - NUTContext *nut = s->priv_data; - - av_freep(&nut->stream); - - return 0; -} - -#ifdef CONFIG_NUT_DEMUXER -AVInputFormat nut_demuxer = { - "nut", - "nut format", - sizeof(NUTContext), - nut_probe, - nut_read_header, - nut_read_packet, - nut_read_close, - nut_read_seek, - nut_read_timestamp, - .extensions = "nut", -}; -#endif -#ifdef CONFIG_NUT_MUXER -AVOutputFormat nut_muxer = { - "nut", - "nut format", - "video/x-nut", - "nut", - sizeof(NUTContext), -#ifdef CONFIG_LIBVORBIS - CODEC_ID_VORBIS, -#elif defined(CONFIG_LIBMP3LAME) - CODEC_ID_MP3, -#else - CODEC_ID_MP2, /* AC3 needs liba52 decoder */ -#endif - CODEC_ID_MPEG4, - nut_write_header, - nut_write_packet, - nut_write_trailer, - .flags = AVFMT_GLOBALHEADER, -}; -#endif diff --git a/contrib/ffmpeg/libavformat/nut.h b/contrib/ffmpeg/libavformat/nut.h index 82bbf6f17..943914603 100644 --- a/contrib/ffmpeg/libavformat/nut.h +++ b/contrib/ffmpeg/libavformat/nut.h @@ -17,12 +17,13 @@ * 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 FFMPEG_NUT_H +#define FFMPEG_NUT_H + //#include <limits.h> #include "avformat.h" -#include "crc.h" //#include "mpegaudio.h" #include "riff.h" //#include "adler32.h" @@ -43,10 +44,12 @@ typedef enum{ FLAG_CODED_PTS = 8, ///<if set, coded_pts is in the frame header FLAG_STREAM_ID = 16, ///<if set, stream_id is coded in the frame header FLAG_SIZE_MSB = 32, ///<if set, data_size_msb is at frame header, otherwise data_size_msb is 0 - FLAG_CHECKSUM = 64, ///<if set then the frame header contains a checksum + FLAG_CHECKSUM = 64, ///<if set, the frame header contains a checksum FLAG_RESERVED = 128, ///<if set, reserved_count is coded in the frame header - FLAG_CODED =4096, ///<if set, coded_flags are stored in the frame header. - FLAG_INVALID =8192, ///<if set, frame_code is invalid. + FLAG_HEADER_IDX =1024, ///<If set, header_idx is coded in the frame header. + FLAG_MATCH_TIME =2048, ///<If set, match_time_delta is coded in the frame header + FLAG_CODED =4096, ///<if set, coded_flags are stored in the frame header + FLAG_INVALID =8192, ///<if set, frame_code is invalid }flag_t; typedef struct { @@ -63,14 +66,15 @@ typedef struct { uint16_t size_lsb; int16_t pts_delta; uint8_t reserved_count; -} FrameCode; // maybe s/FrameCode/framecode_t/ or change all to java style but dont mix + uint8_t header_idx; +} FrameCode; // maybe s/FrameCode/framecode_t/ or change all to Java style but do not mix typedef struct { int last_flags; int skip_until_key_frame; int64_t last_pts; int time_base_id; - AVRational time_base; + AVRational *time_base; int msb_pts_shift; int max_pts_distance; int decode_delay; //FIXME duplicate of has_b_frames @@ -79,19 +83,24 @@ typedef struct { typedef struct { AVFormatContext *avf; // int written_packet_size; -// int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes +// int64_t packet_start; FrameCode frame_code[256]; - uint64_t next_startcode; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable + uint8_t header_len[128]; + const uint8_t *header[128]; + uint64_t next_startcode; ///< stores the next startcode if it has already been parsed but the stream is not seekable StreamContext *stream; unsigned int max_distance; unsigned int time_base_count; int64_t last_syncpoint_pos; + int header_count; AVRational *time_base; struct AVTreeNode *syncpoints; } NUTContext; +void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val); +int64_t ff_lsb2full(StreamContext *stream, int64_t lsb); +int ff_nut_sp_pos_cmp(syncpoint_t *a, syncpoint_t *b); +int ff_nut_sp_pts_cmp(syncpoint_t *a, syncpoint_t *b); +void ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts); -//FIXME move to a common spot, like crc.c/h -static unsigned long av_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf, unsigned int len){ - return av_crc(av_crc04C11DB7, checksum, buf, len); -} +#endif /* FFMPEG_NUT_H */ diff --git a/contrib/ffmpeg/libavformat/nutdec.c b/contrib/ffmpeg/libavformat/nutdec.c index c0f331c27..e072e7ed7 100644 --- a/contrib/ffmpeg/libavformat/nutdec.c +++ b/contrib/ffmpeg/libavformat/nutdec.c @@ -18,28 +18,17 @@ * 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 "tree.h" #include "nut.h" +#include "avstring.h" #undef NDEBUG #include <assert.h> -static uint64_t get_v(ByteIOContext *bc){ - uint64_t val = 0; - int tmp; - - do{ - tmp = get_byte(bc); - val= (val<<7) + (tmp&127); - }while(tmp&128); - return val; -} - static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ - unsigned int len= get_v(bc); + unsigned int len= ff_get_v(bc); if(len && maxlen) get_buffer(bc, string, FFMIN(len, maxlen)); @@ -58,14 +47,14 @@ static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ } static int64_t get_s(ByteIOContext *bc){ - int64_t v = get_v(bc) + 1; + int64_t v = ff_get_v(bc) + 1; if (v&1) return -(v>>1); else return (v>>1); } static uint64_t get_fourcc(ByteIOContext *bc){ - unsigned int len= get_v(bc); + unsigned int len= ff_get_v(bc); if (len==2) return get_le16(bc); else if(len==4) return get_le32(bc); @@ -74,43 +63,46 @@ static uint64_t get_fourcc(ByteIOContext *bc){ #ifdef TRACE static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){ - uint64_t v= get_v(bc); + uint64_t v= ff_get_v(bc); - printf("get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); + av_log(NULL, AV_LOG_DEBUG, "get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); return v; } static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){ int64_t v= get_s(bc); - printf("get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); + av_log(NULL, AV_LOG_DEBUG, "get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); return v; } static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){ uint64_t v= get_vb(bc); - printf("get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); + av_log(NULL, AV_LOG_DEBUG, "get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); return v; } -#define get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define ff_get_v(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) #define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) #define get_vb(bc) get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__) #endif -static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum) +static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum, uint64_t startcode) { - int64_t start, size; + int64_t size; // start= url_ftell(bc) - 8; - size= get_v(bc); - if(size > 4096) - get_be32(bc); //FIXME check this + startcode= be2me_64(startcode); + startcode= ff_crc04C11DB7_update(0, &startcode, 8); - init_checksum(bc, calculate_checksum ? av_crc04C11DB7_update : NULL, 0); + init_checksum(bc, ff_crc04C11DB7_update, startcode); + size= ff_get_v(bc); + if(size > 4096) + get_be32(bc); + if(get_checksum(bc) && size > 4096) + return -1; -// nut->packet_start[2] = start; -// nut->written_packet_size= size; + init_checksum(bc, calculate_checksum ? ff_crc04C11DB7_update : NULL, 0); return size; } @@ -119,7 +111,7 @@ static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ uint64_t state=0; if(pos >= 0) - url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently + url_fseek(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 are currently while(!url_feof(bc)){ state= (state<<8) | get_byte(bc); @@ -139,7 +131,7 @@ static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ } /** - * find the given startcode. + * Find the given startcode. * @param code the startcode * @param pos the start position of the search, or -1 if the current position * @returns the position of the startcode or -1 if not found @@ -155,12 +147,6 @@ static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ } } -static int64_t lsb2full(StreamContext *stream, int64_t lsb){ - int64_t mask = (1<<stream->msb_pts_shift)-1; - int64_t delta= stream->last_pts - mask/2; - return ((lsb - delta)&mask) + delta; -} - static int nut_probe(AVProbeData *p){ int i; uint64_t code= 0; @@ -174,7 +160,7 @@ static int nut_probe(AVProbeData *p){ } #define GET_V(dst, check) \ - tmp= get_v(bc);\ + tmp= ff_get_v(bc);\ if(!(check)){\ av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp);\ return -1;\ @@ -195,18 +181,19 @@ static int skip_reserved(ByteIOContext *bc, int64_t pos){ static int decode_main_header(NUTContext *nut){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; uint64_t tmp, end; unsigned int stream_count; - int i, j, tmp_stream, tmp_mul, tmp_pts, tmp_size, count, tmp_res; + int i, j, tmp_stream, tmp_mul, tmp_pts, tmp_size, count, tmp_res, tmp_head_idx; + int64_t tmp_match; - end= get_packetheader(nut, bc, 1); + end= get_packetheader(nut, bc, 1, MAIN_STARTCODE); end += url_ftell(bc); GET_V(tmp , tmp >=2 && tmp <= 3) GET_V(stream_count , tmp > 0 && tmp <=MAX_STREAMS) - nut->max_distance = get_v(bc); + nut->max_distance = ff_get_v(bc); if(nut->max_distance > 65536){ av_log(s, AV_LOG_DEBUG, "max_distance %d\n", nut->max_distance); nut->max_distance= 65536; @@ -226,21 +213,25 @@ static int decode_main_header(NUTContext *nut){ tmp_pts=0; tmp_mul=1; tmp_stream=0; + tmp_match= 1-(1LL<<62); + tmp_head_idx= 0; for(i=0; i<256;){ - int tmp_flags = get_v(bc); - int tmp_fields= get_v(bc); + int tmp_flags = ff_get_v(bc); + int tmp_fields= ff_get_v(bc); if(tmp_fields>0) tmp_pts = get_s(bc); - if(tmp_fields>1) tmp_mul = get_v(bc); - if(tmp_fields>2) tmp_stream= get_v(bc); - if(tmp_fields>3) tmp_size = get_v(bc); + if(tmp_fields>1) tmp_mul = ff_get_v(bc); + if(tmp_fields>2) tmp_stream= ff_get_v(bc); + if(tmp_fields>3) tmp_size = ff_get_v(bc); else tmp_size = 0; - if(tmp_fields>4) tmp_res = get_v(bc); + if(tmp_fields>4) tmp_res = ff_get_v(bc); else tmp_res = 0; - if(tmp_fields>5) count = get_v(bc); + if(tmp_fields>5) count = ff_get_v(bc); else count = tmp_mul - tmp_size; + if(tmp_fields>6) tmp_match = get_s(bc); + if(tmp_fields>7) tmp_head_idx= ff_get_v(bc); - while(tmp_fields-- > 6) - get_v(bc); + while(tmp_fields-- > 8) + ff_get_v(bc); if(count == 0 || i+count > 256){ av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i); @@ -263,12 +254,30 @@ static int decode_main_header(NUTContext *nut){ nut->frame_code[i].size_mul = tmp_mul ; nut->frame_code[i].size_lsb = tmp_size+j; nut->frame_code[i].reserved_count = tmp_res ; + nut->frame_code[i].header_idx = tmp_head_idx; } } assert(nut->frame_code['N'].flags == FLAG_INVALID); + if(end > url_ftell(bc) + 4){ + int rem= 1024; + GET_V(nut->header_count, tmp<128U) + nut->header_count++; + for(i=1; i<nut->header_count; i++){ + GET_V(nut->header_len[i], tmp>0 && tmp<256); + rem -= nut->header_len[i]; + if(rem < 0){ + av_log(s, AV_LOG_ERROR, "invalid elision header\n"); + return -1; + } + nut->header[i]= av_malloc(nut->header_len[i]); + get_buffer(bc, nut->header[i], nut->header_len[i]); + } + assert(nut->header_len[0]==0); + } + if(skip_reserved(bc, end) || get_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n"); + av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n"); return -1; } @@ -282,36 +291,36 @@ static int decode_main_header(NUTContext *nut){ static int decode_stream_header(NUTContext *nut){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; StreamContext *stc; int class, stream_id; uint64_t tmp, end; AVStream *st; - end= get_packetheader(nut, bc, 1); + end= get_packetheader(nut, bc, 1, STREAM_STARTCODE); end += url_ftell(bc); - GET_V(stream_id, tmp < s->nb_streams && !nut->stream[tmp].time_base.num); + GET_V(stream_id, tmp < s->nb_streams && !nut->stream[tmp].time_base); stc= &nut->stream[stream_id]; st = s->streams[stream_id]; if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); - class = get_v(bc); + class = ff_get_v(bc); tmp = get_fourcc(bc); st->codec->codec_tag= tmp; switch(class) { case 0: st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = codec_get_bmp_id(tmp); + st->codec->codec_id = codec_get_id(codec_bmp_tags, tmp); if (st->codec->codec_id == CODEC_ID_NONE) av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); break; case 1: st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = codec_get_wav_id(tmp); + st->codec->codec_id = codec_get_id(codec_wav_tags, tmp); if (st->codec->codec_id == CODEC_ID_NONE) av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); break; @@ -322,15 +331,15 @@ static int decode_stream_header(NUTContext *nut){ st->codec->codec_type = CODEC_TYPE_DATA; break; default: - av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class); + av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class); return -1; } GET_V(stc->time_base_id , tmp < nut->time_base_count); GET_V(stc->msb_pts_shift , tmp < 16); - stc->max_pts_distance= get_v(bc); - GET_V(stc->decode_delay , tmp < 1000); //sanity limit, raise this if moors law is true + stc->max_pts_distance= ff_get_v(bc); + GET_V(stc->decode_delay , tmp < 1000); //sanity limit, raise this if Moore's law is true st->codec->has_b_frames= stc->decode_delay; - get_v(bc); //stream flags + ff_get_v(bc); //stream flags GET_V(st->codec->extradata_size, tmp < (1<<30)); if(st->codec->extradata_size){ @@ -341,48 +350,45 @@ static int decode_stream_header(NUTContext *nut){ if (st->codec->codec_type == CODEC_TYPE_VIDEO){ GET_V(st->codec->width , tmp > 0) GET_V(st->codec->height, tmp > 0) - st->codec->sample_aspect_ratio.num= get_v(bc); - st->codec->sample_aspect_ratio.den= get_v(bc); + st->codec->sample_aspect_ratio.num= ff_get_v(bc); + st->codec->sample_aspect_ratio.den= ff_get_v(bc); if((!st->codec->sample_aspect_ratio.num) != (!st->codec->sample_aspect_ratio.den)){ - av_log(s, AV_LOG_ERROR, "invalid aspect ratio\n"); + av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n", st->codec->sample_aspect_ratio.num, st->codec->sample_aspect_ratio.den); return -1; } - get_v(bc); /* csp type */ + ff_get_v(bc); /* csp type */ }else if (st->codec->codec_type == CODEC_TYPE_AUDIO){ GET_V(st->codec->sample_rate , tmp > 0) - tmp= get_v(bc); // samplerate_den - if(tmp > st->codec->sample_rate){ - av_log(s, AV_LOG_ERROR, "bleh, libnut muxed this ;)\n"); - st->codec->sample_rate= tmp; - } + ff_get_v(bc); // samplerate_den GET_V(st->codec->channels, tmp > 0) } if(skip_reserved(bc, end) || get_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Stream header %d checksum mismatch\n", stream_id); + av_log(s, AV_LOG_ERROR, "stream header %d checksum mismatch\n", stream_id); return -1; } - stc->time_base= nut->time_base[stc->time_base_id]; - av_set_pts_info(s->streams[stream_id], 63, stc->time_base.num, stc->time_base.den); + stc->time_base= &nut->time_base[stc->time_base_id]; + av_set_pts_info(s->streams[stream_id], 63, stc->time_base->num, stc->time_base->den); return 0; } static int decode_info_header(NUTContext *nut){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; uint64_t tmp; unsigned int stream_id_plus1, chapter_start, chapter_len, count; int chapter_id, i; int64_t value, end; - char name[256], str_value[1024], type_str[256], *type= type_str; + char name[256], str_value[1024], type_str[256]; + const char *type; - end= get_packetheader(nut, bc, 1); + end= get_packetheader(nut, bc, 1, INFO_STARTCODE); end += url_ftell(bc); GET_V(stream_id_plus1, tmp <= s->nb_streams) chapter_id = get_s(bc); - chapter_start= get_v(bc); - chapter_len = get_v(bc); - count = get_v(bc); + chapter_start= ff_get_v(bc); + chapter_len = ff_get_v(bc); + count = ff_get_v(bc); for(i=0; i<count; i++){ get_str(bc, name, sizeof(name)); value= get_s(bc); @@ -390,14 +396,15 @@ static int decode_info_header(NUTContext *nut){ type= "UTF-8"; get_str(bc, str_value, sizeof(str_value)); }else if(value == -2){ - get_str(bc, type, sizeof(type)); + get_str(bc, type_str, sizeof(type_str)); + type= type_str; get_str(bc, str_value, sizeof(str_value)); }else if(value == -3){ type= "s"; value= get_s(bc); }else if(value == -4){ type= "t"; - value= get_v(bc); + value= ff_get_v(bc); }else if(value < -4){ type= "r"; get_s(bc); @@ -407,69 +414,39 @@ static int decode_info_header(NUTContext *nut){ if(chapter_id==0 && !strcmp(type, "UTF-8")){ if (!strcmp(name, "Author")) - pstrcpy(s->author , sizeof(s->author) , str_value); + av_strlcpy(s->author , str_value, sizeof(s->author)); else if(!strcmp(name, "Title")) - pstrcpy(s->title , sizeof(s->title) , str_value); + av_strlcpy(s->title , str_value, sizeof(s->title)); else if(!strcmp(name, "Copyright")) - pstrcpy(s->copyright, sizeof(s->copyright), str_value); + av_strlcpy(s->copyright, str_value, sizeof(s->copyright)); else if(!strcmp(name, "Description")) - pstrcpy(s->comment , sizeof(s->comment) , str_value); + av_strlcpy(s->comment , str_value, sizeof(s->comment)); } } if(skip_reserved(bc, end) || get_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n"); + av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n"); return -1; } return 0; } -int sp_pos_cmp(syncpoint_t *a, syncpoint_t *b){ - return (a->pos - b->pos>>32) - (b->pos - a->pos>>32); -} - -int sp_pts_cmp(syncpoint_t *a, syncpoint_t *b){ - return (a->ts - b->ts>>32) - (b->ts - a->ts>>32); -} - -static void add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts){ - syncpoint_t *sp2, *sp= av_mallocz(sizeof(syncpoint_t)); - - sp->pos= pos; - sp->back_ptr= back_ptr; - sp->ts= ts; - sp2= av_tree_insert(&nut->syncpoints, sp, sp_pos_cmp); - if(sp2 && sp2 != sp) - av_free(sp); -} - static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; int64_t end, tmp; - int i; - AVRational time_base; nut->last_syncpoint_pos= url_ftell(bc)-8; - end= get_packetheader(nut, bc, 1); + end= get_packetheader(nut, bc, 1, SYNCPOINT_STARTCODE); end += url_ftell(bc); - tmp= get_v(bc); - *back_ptr= nut->last_syncpoint_pos - 16*get_v(bc); + tmp= ff_get_v(bc); + *back_ptr= nut->last_syncpoint_pos - 16*ff_get_v(bc); if(*back_ptr < 0) return -1; - time_base= nut->time_base[tmp % nut->time_base_count]; - for(i=0; i<s->nb_streams; i++){ - nut->stream[i].last_pts= av_rescale_rnd( - tmp / nut->time_base_count, - time_base.num * (int64_t)nut->stream[i].time_base.den, - time_base.den * (int64_t)nut->stream[i].time_base.num, - AV_ROUND_DOWN); - //last_key_frame ? - } - //FIXME put this in a reset func maybe + ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count], tmp / nut->time_base_count); if(skip_reserved(bc, end) || get_checksum(bc)){ av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n"); @@ -477,14 +454,14 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr){ } *ts= tmp / s->nb_streams * av_q2d(nut->time_base[tmp % s->nb_streams])*AV_TIME_BASE; - add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts); + ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts); return 0; } static int find_and_decode_index(NUTContext *nut){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; uint64_t tmp, end; int i, j, syncpoint_count; int64_t filesize= url_fsize(bc); @@ -498,10 +475,10 @@ static int find_and_decode_index(NUTContext *nut){ return -1; } - end= get_packetheader(nut, bc, 1); + end= get_packetheader(nut, bc, 1, INDEX_STARTCODE); end += url_ftell(bc); - get_v(bc); //max_pts + ff_get_v(bc); //max_pts GET_V(syncpoint_count, tmp < INT_MAX/8 && tmp > 0) syncpoints= av_malloc(sizeof(int64_t)*syncpoint_count); has_keyframe= av_malloc(sizeof(int8_t)*(syncpoint_count+1)); @@ -514,7 +491,7 @@ static int find_and_decode_index(NUTContext *nut){ for(i=0; i<s->nb_streams; i++){ int64_t last_pts= -1; for(j=0; j<syncpoint_count;){ - uint64_t x= get_v(bc); + uint64_t x= ff_get_v(bc); int type= x&1; int n= j; x>>=1; @@ -543,12 +520,12 @@ static int find_and_decode_index(NUTContext *nut){ return -1; } assert(n<=syncpoint_count+1); - for(; j<n; j++){ + for(; j<n && j<syncpoint_count; j++){ if(has_keyframe[j]){ - uint64_t B, A= get_v(bc); + uint64_t B, A= ff_get_v(bc); if(!A){ - A= get_v(bc); - B= get_v(bc); + A= ff_get_v(bc); + B= ff_get_v(bc); //eor_pts[j][i] = last_pts + A + B }else B= 0; @@ -566,7 +543,7 @@ static int find_and_decode_index(NUTContext *nut){ } if(skip_reserved(bc, end) || get_checksum(bc)){ - av_log(s, AV_LOG_ERROR, "Index checksum mismatch\n"); + av_log(s, AV_LOG_ERROR, "index checksum mismatch\n"); return -1; } return 0; @@ -575,9 +552,9 @@ static int find_and_decode_index(NUTContext *nut){ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) { NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; int64_t pos; - int inited_stream_count; + int initialized_stream_count; nut->avf= s; @@ -586,21 +563,21 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) do{ pos= find_startcode(bc, MAIN_STARTCODE, pos)+1; if (pos<0+1){ - av_log(s, AV_LOG_ERROR, "no main startcode found\n"); + av_log(s, AV_LOG_ERROR, "No main startcode found.\n"); return -1; } }while(decode_main_header(nut) < 0); /* stream headers */ pos=0; - for(inited_stream_count=0; inited_stream_count < s->nb_streams;){ + for(initialized_stream_count=0; initialized_stream_count < s->nb_streams;){ pos= find_startcode(bc, STREAM_STARTCODE, pos)+1; if (pos<0+1){ - av_log(s, AV_LOG_ERROR, "not all stream headers found\n"); + av_log(s, AV_LOG_ERROR, "Not all stream headers found.\n"); return -1; } if(decode_stream_header(nut) >= 0) - inited_stream_count++; + initialized_stream_count++; } /* info headers */ @@ -634,15 +611,15 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) return 0; } -static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, int frame_code){ +static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, uint8_t *header_idx, int frame_code){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; StreamContext *stc; int size, flags, size_mul, pts_delta, i, reserved_count; uint64_t tmp; if(url_ftell(bc) > nut->last_syncpoint_pos + nut->max_distance){ - av_log(s, AV_LOG_ERROR, "last frame must have been damaged %Ld > %Ld + %d\n", url_ftell(bc), nut->last_syncpoint_pos, nut->max_distance); + av_log(s, AV_LOG_ERROR, "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n", url_ftell(bc), nut->last_syncpoint_pos, nut->max_distance); return -1; } @@ -652,31 +629,45 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, in *stream_id = nut->frame_code[frame_code].stream_id; pts_delta = nut->frame_code[frame_code].pts_delta; reserved_count = nut->frame_code[frame_code].reserved_count; + *header_idx = nut->frame_code[frame_code].header_idx; if(flags & FLAG_INVALID) return -1; if(flags & FLAG_CODED) - flags ^= get_v(bc); + flags ^= ff_get_v(bc); if(flags & FLAG_STREAM_ID){ GET_V(*stream_id, tmp < s->nb_streams) } stc= &nut->stream[*stream_id]; if(flags&FLAG_CODED_PTS){ - int coded_pts= get_v(bc); + int coded_pts= ff_get_v(bc); //FIXME check last_pts validity? if(coded_pts < (1<<stc->msb_pts_shift)){ - *pts=lsb2full(stc, coded_pts); + *pts=ff_lsb2full(stc, coded_pts); }else *pts=coded_pts - (1<<stc->msb_pts_shift); }else *pts= stc->last_pts + pts_delta; if(flags&FLAG_SIZE_MSB){ - size += size_mul*get_v(bc); + size += size_mul*ff_get_v(bc); } + if(flags&FLAG_MATCH_TIME) + get_s(bc); + if(flags&FLAG_HEADER_IDX) + *header_idx= ff_get_v(bc); if(flags&FLAG_RESERVED) - reserved_count= get_v(bc); + reserved_count= ff_get_v(bc); for(i=0; i<reserved_count; i++) - get_v(bc); + ff_get_v(bc); + + if(*header_idx >= (unsigned)nut->header_count){ + av_log(s, AV_LOG_ERROR, "header_idx invalid\n"); + return -1; + } + if(size > 4096) + *header_idx=0; + size -= nut->header_len[*header_idx]; + if(flags&FLAG_CHECKSUM){ get_be32(bc); //FIXME check this }else if(size > 2*nut->max_distance || FFABS(stc->last_pts - *pts) > stc->max_pts_distance){ @@ -692,12 +683,13 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, in static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ AVFormatContext *s= nut->avf; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; int size, stream_id, discard; int64_t pts, last_IP_pts; StreamContext *stc; + uint8_t header_idx; - size= decode_frame_header(nut, &pts, &stream_id, frame_code); + size= decode_frame_header(nut, &pts, &stream_id, &header_idx, frame_code); if(size < 0) return -1; @@ -716,7 +708,11 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ return 1; } - av_get_packet(bc, pkt, size); + av_new_packet(pkt, size + nut->header_len[header_idx]); + memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]); + pkt->pos= url_ftell(bc); //FIXME + get_buffer(bc, pkt->data + nut->header_len[header_idx], size); + pkt->stream_index = stream_id; if (stc->last_flags & FLAG_KEY) pkt->flags |= PKT_FLAG_KEY; @@ -728,7 +724,7 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) { NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; int i, frame_code=0, ret, skip; int64_t ts, back_ptr; @@ -753,7 +749,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) case MAIN_STARTCODE: case STREAM_STARTCODE: case INDEX_STARTCODE: - skip= get_packetheader(nut, bc, 0); + skip= get_packetheader(nut, bc, 0, tmp); url_fseek(bc, skip, SEEK_CUR); break; case INFO_STARTCODE: @@ -784,24 +780,23 @@ av_log(s, AV_LOG_DEBUG, "sync\n"); static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){ NUTContext *nut = s->priv_data; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; int64_t pos, pts, back_ptr; av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit); pos= *pos_arg; -resync: do{ pos= find_startcode(bc, SYNCPOINT_STARTCODE, pos)+1; if(pos < 1){ assert(nut->next_startcode == 0); - av_log(s, AV_LOG_ERROR, "read_timestamp failed\n"); + av_log(s, AV_LOG_ERROR, "read_timestamp failed.\n"); return AV_NOPTS_VALUE; } }while(decode_syncpoint(nut, &pts, &back_ptr) < 0); *pos_arg = pos-1; assert(nut->last_syncpoint_pos == *pos_arg); - av_log(s, AV_LOG_DEBUG, "return %Ld %Ld\n", pts,back_ptr ); + av_log(s, AV_LOG_DEBUG, "return %"PRId64" %"PRId64"\n", pts,back_ptr ); if (stream_index == -1) return pts; else if(stream_index == -2) return back_ptr; @@ -825,8 +820,8 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flag pos2= st->index_entries[index].pos; ts = st->index_entries[index].timestamp; }else{ - av_tree_find(nut->syncpoints, &dummy, sp_pts_cmp, next_node); - av_log(s, AV_LOG_DEBUG, "%Ld-%Ld %Ld-%Ld\n", next_node[0]->pos, next_node[1]->pos, + av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pts_cmp, next_node); + av_log(s, AV_LOG_DEBUG, "%"PRIu64"-%"PRIu64" %"PRId64"-%"PRId64"\n", next_node[0]->pos, next_node[1]->pos, next_node[0]->ts , next_node[1]->ts); pos= av_gen_search(s, -1, dummy.ts, next_node[0]->pos, next_node[1]->pos, next_node[1]->pos, next_node[0]->ts , next_node[1]->ts, AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp); @@ -834,22 +829,22 @@ static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flag if(!(flags & AVSEEK_FLAG_BACKWARD)){ dummy.pos= pos+16; next_node[1]= &nopts_sp; - av_tree_find(nut->syncpoints, &dummy, sp_pos_cmp, next_node); + av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, next_node); pos2= av_gen_search(s, -2, dummy.pos, next_node[0]->pos , next_node[1]->pos, next_node[1]->pos, next_node[0]->back_ptr, next_node[1]->back_ptr, flags, &ts, nut_read_timestamp); if(pos2>=0) pos= pos2; - //FIXME dir but i think it doesnt matter + //FIXME dir but i think it does not matter } dummy.pos= pos; - sp= av_tree_find(nut->syncpoints, &dummy, sp_pos_cmp, NULL); + sp= av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, NULL); assert(sp); pos2= sp->back_ptr - 15; } av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos2); - pos= find_startcode(&s->pb, SYNCPOINT_STARTCODE, pos2); - url_fseek(&s->pb, pos, SEEK_SET); + pos= find_startcode(s->pb, SYNCPOINT_STARTCODE, pos2); + url_fseek(s->pb, pos, SEEK_SET); av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos); if(pos2 > pos || pos2 + 15 < pos){ av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n"); diff --git a/contrib/ffmpeg/libavformat/nutenc.c b/contrib/ffmpeg/libavformat/nutenc.c new file mode 100644 index 000000000..5c0975c28 --- /dev/null +++ b/contrib/ffmpeg/libavformat/nutenc.c @@ -0,0 +1,775 @@ +/* + * nut muxer + * Copyright (c) 2004-2007 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 + */ + +#include "nut.h" +#include "tree.h" +#include "mpegaudiodata.h" + +static int find_expected_header(AVCodecContext *c, int size, int key_frame, uint8_t out[64]){ + int sample_rate= c->sample_rate; + + if(size>4096) + return 0; + + AV_WB24(out, 1); + + if(c->codec_id == CODEC_ID_MPEG4){ + if(key_frame){ + return 3; + }else{ + out[3]= 0xB6; + return 4; + } + }else if(c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MPEG2VIDEO){ + return 3; + }else if(c->codec_id == CODEC_ID_H264){ + return 3; + }else if(c->codec_id == CODEC_ID_MP3 || c->codec_id == CODEC_ID_MP2){ + int lsf, mpeg25, sample_rate_index, bitrate_index, frame_size; + int layer= c->codec_id == CODEC_ID_MP3 ? 3 : 2; + unsigned int header= 0xFFF00000; + + lsf = sample_rate < (24000+32000)/2; + mpeg25 = sample_rate < (12000+16000)/2; + sample_rate <<= lsf + mpeg25; + if (sample_rate < (32000 + 44100)/2) sample_rate_index=2; + else if(sample_rate < (44100 + 48000)/2) sample_rate_index=0; + else sample_rate_index=1; + + sample_rate= ff_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25); + + for(bitrate_index=2; bitrate_index<30; bitrate_index++){ + frame_size = ff_mpa_bitrate_tab[lsf][layer-1][bitrate_index>>1]; + frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index&1); + + if(frame_size == size) + break; + } + + header |= (!lsf)<<19; + header |= (4-layer)<<17; + header |= 1<<16; //no crc + AV_WB32(out, header); + if(size <= 0) + return 2; //we guess theres no crc, if there is one the user clearly doesnt care about overhead + if(bitrate_index == 30) + return -1; //something is wrong ... + + header |= (bitrate_index>>1)<<12; + header |= sample_rate_index<<10; + header |= (bitrate_index&1)<<9; + + return 2; //FIXME actually put the needed ones in build_elision_headers() + return 3; //we guess that the private bit isnt set +//FIXME the above asumtations should be checked, if these turn out false too often something should be done + } + return 0; +} + +static int find_header_idx(AVFormatContext *s, AVCodecContext *c, int size, int frame_type){ + NUTContext *nut = s->priv_data; + uint8_t out[64]; + int i; + int len= find_expected_header(c, size, frame_type, out); + +//av_log(NULL, AV_LOG_ERROR, "expected_h len=%d size=%d codec_id=%d\n", len, size, c->codec_id); + + for(i=1; i<nut->header_count; i++){ + if( len == nut->header_len[i] + && !memcmp(out, nut->header[i], len)){ +// av_log(NULL, AV_LOG_ERROR, "found %d\n", i); + return i; + } + } +// av_log(NULL, AV_LOG_ERROR, "nothing found\n"); + return 0; +} + +static void build_elision_headers(AVFormatContext *s){ + NUTContext *nut = s->priv_data; + int i; + //FIXME this is lame + //FIXME write a 2pass mode to find the maximal headers + const static uint8_t headers[][5]={ + {3, 0x00, 0x00, 0x01}, + {4, 0x00, 0x00, 0x01, 0xB6}, + {2, 0xFF, 0xFA}, //mp3+crc + {2, 0xFF, 0xFB}, //mp3 + {2, 0xFF, 0xFC}, //mp2+crc + {2, 0xFF, 0xFD}, //mp2 + }; + + nut->header_count= 7; + for(i=1; i<nut->header_count; i++){ + nut->header_len[i]= headers[i-1][0]; + nut->header [i]= &headers[i-1][1]; + } +} + +static void build_frame_code(AVFormatContext *s){ + NUTContext *nut = s->priv_data; + int key_frame, index, pred, stream_id; + int start=1; + int end= 254; + int keyframe_0_esc= s->nb_streams > 2; + int pred_table[10]; + FrameCode *ft; + + ft= &nut->frame_code[start]; + ft->flags= FLAG_CODED; + ft->size_mul=1; + ft->pts_delta=1; + start++; + + if(keyframe_0_esc){ + /* keyframe = 0 escape */ + FrameCode *ft= &nut->frame_code[start]; + ft->flags= FLAG_STREAM_ID | FLAG_SIZE_MSB | FLAG_CODED_PTS; + ft->size_mul=1; + start++; + } + + for(stream_id= 0; stream_id<s->nb_streams; stream_id++){ + int start2= start + (end-start)*stream_id / s->nb_streams; + int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; + AVCodecContext *codec = s->streams[stream_id]->codec; + int is_audio= codec->codec_type == CODEC_TYPE_AUDIO; + int intra_only= /*codec->intra_only || */is_audio; + int pred_count; + + for(key_frame=0; key_frame<2; key_frame++){ + if(intra_only && keyframe_0_esc && key_frame==0) + continue; + + { + FrameCode *ft= &nut->frame_code[start2]; + ft->flags= FLAG_KEY*key_frame; + ft->flags|= FLAG_SIZE_MSB | FLAG_CODED_PTS; + ft->stream_id= stream_id; + ft->size_mul=1; + if(is_audio) + ft->header_idx= find_header_idx(s, codec, -1, key_frame); + start2++; + } + } + + 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; + for(pts=0; pts<2; pts++){ + for(pred=0; pred<2; pred++){ + FrameCode *ft= &nut->frame_code[start2]; + ft->flags= FLAG_KEY*key_frame; + ft->stream_id= stream_id; + ft->size_mul=frame_bytes + 2; + ft->size_lsb=frame_bytes + pred; + ft->pts_delta=pts; + ft->header_idx= find_header_idx(s, codec, frame_bytes + pred, key_frame); + start2++; + } + } + }else{ + FrameCode *ft= &nut->frame_code[start2]; + ft->flags= FLAG_KEY | FLAG_SIZE_MSB; + ft->stream_id= stream_id; + ft->size_mul=1; + ft->pts_delta=1; + start2++; + } +#endif + + if(codec->has_b_frames){ + pred_count=5; + pred_table[0]=-2; + pred_table[1]=-1; + pred_table[2]=1; + pred_table[3]=3; + pred_table[4]=4; + }else if(codec->codec_id == CODEC_ID_VORBIS){ + pred_count=3; + pred_table[0]=2; + pred_table[1]=9; + pred_table[2]=16; + }else{ + pred_count=1; + pred_table[0]=1; + } + + for(pred=0; pred<pred_count; pred++){ + int start3= start2 + (end2-start2)*pred / pred_count; + int end3 = start2 + (end2-start2)*(pred+1) / pred_count; + + for(index=start3; index<end3; index++){ + FrameCode *ft= &nut->frame_code[index]; + ft->flags= FLAG_KEY*key_frame; + ft->flags|= FLAG_SIZE_MSB; + ft->stream_id= stream_id; +//FIXME use single byte size and pred from last + ft->size_mul= end3-start3; + ft->size_lsb= index - start3; + ft->pts_delta= pred_table[pred]; + if(is_audio) + ft->header_idx= find_header_idx(s, codec, -1, key_frame); + } + } + } + memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); + nut->frame_code[ 0].flags= + nut->frame_code[255].flags= + nut->frame_code['N'].flags= FLAG_INVALID; +} + +/** + * Gets the length in bytes which is needed to store val as v. + */ +static int get_length(uint64_t val){ + int i=1; + + while(val>>=7) + i++; + + return i; +} + +static void put_v(ByteIOContext *bc, uint64_t val){ + int i= get_length(val); + + while(--i>0) + put_byte(bc, 128 | (val>>(7*i))); + + put_byte(bc, val&127); +} + +static void put_t(NUTContext *nut, StreamContext *nus, ByteIOContext *bc, uint64_t val){ + val *= nut->time_base_count; + val += nus->time_base - nut->time_base; + put_v(bc, val); +} + +/** + * Stores a string as vb. + */ +static void put_str(ByteIOContext *bc, const char *string){ + int len= strlen(string); + + put_v(bc, len); + put_buffer(bc, string, len); +} + +static void put_s(ByteIOContext *bc, int64_t val){ + put_v(bc, 2*FFABS(val) - (val>0)); +} + +#ifdef TRACE +static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){ + av_log(NULL, AV_LOG_DEBUG, "put_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); + + put_v(bc, v); +} + +static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){ + av_log(NULL, AV_LOG_DEBUG, "put_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line); + + put_s(bc, v); +} +#define put_v(bc, v) put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#define put_s(bc, v) put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__) +#endif + +//FIXME remove calculate_checksum +static void put_packet(NUTContext *nut, ByteIOContext *bc, ByteIOContext *dyn_bc, int calculate_checksum, uint64_t startcode){ + uint8_t *dyn_buf=NULL; + int dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf); + int forw_ptr= dyn_size + 4*calculate_checksum; + + if(forw_ptr > 4096) + init_checksum(bc, ff_crc04C11DB7_update, 0); + put_be64(bc, startcode); + put_v(bc, forw_ptr); + if(forw_ptr > 4096) + put_le32(bc, get_checksum(bc)); + + if(calculate_checksum) + init_checksum(bc, ff_crc04C11DB7_update, 0); + put_buffer(bc, dyn_buf, dyn_size); + if(calculate_checksum) + put_le32(bc, get_checksum(bc)); + + av_free(dyn_buf); +} + +static void write_mainheader(NUTContext *nut, ByteIOContext *bc){ + int i, j, tmp_pts, tmp_flags, tmp_stream, tmp_mul, tmp_size, tmp_fields, tmp_head_idx; + int64_t tmp_match; + + put_v(bc, 3); /* version */ + put_v(bc, nut->avf->nb_streams); + put_v(bc, nut->max_distance); + put_v(bc, nut->time_base_count); + + for(i=0; i<nut->time_base_count; i++){ + put_v(bc, nut->time_base[i].num); + put_v(bc, nut->time_base[i].den); + } + + tmp_pts=0; + tmp_mul=1; + tmp_stream=0; + tmp_match= 1-(1LL<<62); + tmp_head_idx= 0; + for(i=0; i<256;){ + tmp_fields=0; + tmp_size=0; +// tmp_res=0; + if(tmp_pts != nut->frame_code[i].pts_delta) tmp_fields=1; + if(tmp_mul != nut->frame_code[i].size_mul ) tmp_fields=2; + if(tmp_stream != nut->frame_code[i].stream_id) tmp_fields=3; + if(tmp_size != nut->frame_code[i].size_lsb ) tmp_fields=4; +// if(tmp_res != nut->frame_code[i].res ) tmp_fields=5; + if(tmp_head_idx!=nut->frame_code[i].header_idx)tmp_fields=8; + + tmp_pts = nut->frame_code[i].pts_delta; + tmp_flags = nut->frame_code[i].flags; + tmp_stream= nut->frame_code[i].stream_id; + tmp_mul = nut->frame_code[i].size_mul; + tmp_size = nut->frame_code[i].size_lsb; +// tmp_res = nut->frame_code[i].res; + tmp_head_idx= nut->frame_code[i].header_idx; + + for(j=0; i<256; j++,i++){ + if(i == 'N'){ + j--; + continue; + } + if(nut->frame_code[i].pts_delta != tmp_pts ) break; + if(nut->frame_code[i].flags != tmp_flags ) break; + if(nut->frame_code[i].stream_id != tmp_stream) break; + if(nut->frame_code[i].size_mul != tmp_mul ) break; + if(nut->frame_code[i].size_lsb != tmp_size+j) break; +// if(nut->frame_code[i].res != tmp_res ) break; + if(nut->frame_code[i].header_idx!= tmp_head_idx) break; + } + if(j != tmp_mul - tmp_size) tmp_fields=6; + + put_v(bc, tmp_flags); + put_v(bc, tmp_fields); + if(tmp_fields>0) put_s(bc, tmp_pts); + if(tmp_fields>1) put_v(bc, tmp_mul); + if(tmp_fields>2) put_v(bc, tmp_stream); + if(tmp_fields>3) put_v(bc, tmp_size); + if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/); + if(tmp_fields>5) put_v(bc, j); + if(tmp_fields>6) put_v(bc, tmp_match); + if(tmp_fields>7) put_v(bc, tmp_head_idx); + } + put_v(bc, nut->header_count-1); + for(i=1; i<nut->header_count; i++){ + put_v(bc, nut->header_len[i]); + put_buffer(bc, nut->header[i], nut->header_len[i]); + } +} + +static int write_streamheader(NUTContext *nut, ByteIOContext *bc, AVCodecContext *codec, int i){ + put_v(bc, i); + switch(codec->codec_type){ + case CODEC_TYPE_VIDEO: put_v(bc, 0); break; + case CODEC_TYPE_AUDIO: put_v(bc, 1); break; +// case CODEC_TYPE_TEXT : put_v(bc, 2); break; + default : put_v(bc, 3); break; + } + put_v(bc, 4); + if (codec->codec_tag){ + put_le32(bc, codec->codec_tag); + }else + return -1; + + put_v(bc, nut->stream[i].time_base - nut->time_base); + put_v(bc, nut->stream[i].msb_pts_shift); + put_v(bc, nut->stream[i].max_pts_distance); + put_v(bc, codec->has_b_frames); + put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */ + + put_v(bc, codec->extradata_size); + put_buffer(bc, codec->extradata, codec->extradata_size); + + switch(codec->codec_type){ + case CODEC_TYPE_AUDIO: + put_v(bc, codec->sample_rate); + put_v(bc, 1); + put_v(bc, codec->channels); + break; + case CODEC_TYPE_VIDEO: + put_v(bc, codec->width); + put_v(bc, codec->height); + + if(codec->sample_aspect_ratio.num<=0 || codec->sample_aspect_ratio.den<=0){ + put_v(bc, 0); + put_v(bc, 0); + }else{ + put_v(bc, codec->sample_aspect_ratio.num); + put_v(bc, codec->sample_aspect_ratio.den); + } + put_v(bc, 0); /* csp type -- unknown */ + break; + default: + break; + } + return 0; +} + +static int add_info(ByteIOContext *bc, const char *type, const char *value){ + put_str(bc, type); + put_s(bc, -1); + put_str(bc, value); + return 1; +} + +static int write_globalinfo(NUTContext *nut, ByteIOContext *bc){ + AVFormatContext *s= nut->avf; + ByteIOContext *dyn_bc; + uint8_t *dyn_buf=NULL; + int count=0, dyn_size; + int ret = url_open_dyn_buf(&dyn_bc); + if(ret < 0) + return ret; + + if(s->title [0]) count+= add_info(dyn_bc, "Title" , s->title); + if(s->author [0]) count+= add_info(dyn_bc, "Author" , s->author); + if(s->copyright[0]) count+= add_info(dyn_bc, "Copyright", s->copyright); + if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) + count+= add_info(dyn_bc, "Encoder" , LIBAVFORMAT_IDENT); + + put_v(bc, 0); //stream_if_plus1 + put_v(bc, 0); //chapter_id + put_v(bc, 0); //timestamp_start + put_v(bc, 0); //length + + put_v(bc, count); + + dyn_size= url_close_dyn_buf(dyn_bc, &dyn_buf); + put_buffer(bc, dyn_buf, dyn_size); + av_free(dyn_buf); + return 0; +} + +static int write_headers(NUTContext *nut, ByteIOContext *bc){ + ByteIOContext *dyn_bc; + int i, ret; + + ret = url_open_dyn_buf(&dyn_bc); + if(ret < 0) + return ret; + write_mainheader(nut, dyn_bc); + put_packet(nut, bc, dyn_bc, 1, MAIN_STARTCODE); + + for (i=0; i < nut->avf->nb_streams; i++){ + AVCodecContext *codec = nut->avf->streams[i]->codec; + + ret = url_open_dyn_buf(&dyn_bc); + if(ret < 0) + return ret; + write_streamheader(nut, dyn_bc, codec, i); + put_packet(nut, bc, dyn_bc, 1, STREAM_STARTCODE); + } + + ret = url_open_dyn_buf(&dyn_bc); + if(ret < 0) + return ret; + write_globalinfo(nut, dyn_bc); + put_packet(nut, bc, dyn_bc, 1, INFO_STARTCODE); + + nut->last_syncpoint_pos= INT_MIN; + nut->header_count++; + return 0; +} + +static int write_header(AVFormatContext *s){ + NUTContext *nut = s->priv_data; + ByteIOContext *bc = s->pb; + int i, j; + + nut->avf= s; + + nut->stream = av_mallocz(sizeof(StreamContext)*s->nb_streams); + nut->time_base= av_mallocz(sizeof(AVRational )*s->nb_streams); + + for(i=0; i<s->nb_streams; i++){ + AVStream *st= s->streams[i]; + int ssize; + AVRational time_base; + ff_parse_specific_params(st->codec, &time_base.den, &ssize, &time_base.num); + + av_set_pts_info(st, 64, time_base.num, time_base.den); + + for(j=0; j<nut->time_base_count; j++){ + if(!memcmp(&time_base, &nut->time_base[j], sizeof(AVRational))){ + break; + } + } + nut->time_base[j]= time_base; + nut->stream[i].time_base= &nut->time_base[j]; + if(j==nut->time_base_count) + nut->time_base_count++; + + if(av_q2d(time_base) >= 0.001) + nut->stream[i].msb_pts_shift = 7; + else + nut->stream[i].msb_pts_shift = 14; + nut->stream[i].max_pts_distance= FFMAX(1/av_q2d(time_base), 1); + } + + nut->max_distance = MAX_DISTANCE; + build_elision_headers(s); + build_frame_code(s); + assert(nut->frame_code['N'].flags == FLAG_INVALID); + + put_buffer(bc, ID_STRING, strlen(ID_STRING)); + put_byte(bc, 0); + + write_headers(nut, bc); + + put_flush_packet(bc); + + //FIXME index + + return 0; +} + +static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc, AVPacket *pkt){ + int flags= 0; + + if(pkt->flags & PKT_FLAG_KEY ) flags |= FLAG_KEY; + if(pkt->stream_index != fc->stream_id ) flags |= FLAG_STREAM_ID; + if(pkt->size / fc->size_mul ) flags |= FLAG_SIZE_MSB; + if(pkt->pts - nus->last_pts != fc->pts_delta) flags |= FLAG_CODED_PTS; + if(pkt->size > 2*nut->max_distance ) flags |= FLAG_CHECKSUM; + if(FFABS(pkt->pts - nus->last_pts) + > nus->max_pts_distance) flags |= FLAG_CHECKSUM; + if( pkt->size < nut->header_len[fc->header_idx] + || (pkt->size > 4096 && fc->header_idx) + || memcmp(pkt->data, nut->header[fc->header_idx], nut->header_len[fc->header_idx])) + flags |= FLAG_HEADER_IDX; + + return flags | (fc->flags & FLAG_CODED); +} + +static int find_best_header_idx(NUTContext *nut, AVPacket *pkt){ + int i; + int best_i = 0; + int best_len= 0; + + if(pkt->size > 4096) + return 0; + + for(i=1; i<nut->header_count; i++){ + if( pkt->size >= nut->header_len[i] + && nut->header_len[i] > best_len + && !memcmp(pkt->data, nut->header[i], nut->header_len[i])){ + best_i= i; + best_len= nut->header_len[i]; + } + } + return best_i; +} + +static int write_packet(AVFormatContext *s, AVPacket *pkt){ + NUTContext *nut = s->priv_data; + StreamContext *nus= &nut->stream[pkt->stream_index]; + ByteIOContext *bc = s->pb, *dyn_bc; + FrameCode *fc; + int64_t coded_pts; + int best_length, frame_code, flags, needed_flags, i, header_idx, best_header_idx; + int key_frame = !!(pkt->flags & PKT_FLAG_KEY); + int store_sp=0; + int ret; + + if(1LL<<(20+3*nut->header_count) <= url_ftell(bc)) + write_headers(nut, bc); + + if(key_frame && !(nus->last_flags & FLAG_KEY)) + store_sp= 1; + + if(pkt->size + 30/*FIXME check*/ + url_ftell(bc) >= nut->last_syncpoint_pos + nut->max_distance) + store_sp= 1; + +//FIXME: Ensure store_sp is 1 in the first place. + + if(store_sp){ + syncpoint_t *sp, dummy= {.pos= INT64_MAX}; + + ff_nut_reset_ts(nut, *nus->time_base, pkt->dts); + for(i=0; i<s->nb_streams; i++){ + AVStream *st= s->streams[i]; + int64_t dts_tb = av_rescale_rnd(pkt->dts, + nus->time_base->num * (int64_t)nut->stream[i].time_base->den, + nus->time_base->den * (int64_t)nut->stream[i].time_base->num, + AV_ROUND_DOWN); + int index= av_index_search_timestamp(st, dts_tb, AVSEEK_FLAG_BACKWARD); + if(index>=0) dummy.pos= FFMIN(dummy.pos, st->index_entries[index].pos); + } + if(dummy.pos == INT64_MAX) + dummy.pos= 0; + sp= av_tree_find(nut->syncpoints, &dummy, ff_nut_sp_pos_cmp, NULL); + + nut->last_syncpoint_pos= url_ftell(bc); + ret = url_open_dyn_buf(&dyn_bc); + if(ret < 0) + return ret; + put_t(nut, nus, dyn_bc, pkt->dts); + put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos)>>4 : 0); + put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE); + + ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0/*unused*/, pkt->dts); + } + assert(nus->last_pts != AV_NOPTS_VALUE); + + coded_pts = pkt->pts & ((1<<nus->msb_pts_shift)-1); + if(ff_lsb2full(nus, coded_pts) != pkt->pts) + coded_pts= pkt->pts + (1<<nus->msb_pts_shift); + + best_header_idx= find_best_header_idx(nut, pkt); + + best_length=INT_MAX; + frame_code= -1; + for(i=0; i<256; i++){ + int length= 0; + FrameCode *fc= &nut->frame_code[i]; + int flags= fc->flags; + + if(flags & FLAG_INVALID) + continue; + needed_flags= get_needed_flags(nut, nus, fc, pkt); + + if(flags & FLAG_CODED){ + length++; + flags = needed_flags; + } + + if((flags & needed_flags) != needed_flags) + continue; + + if((flags ^ needed_flags) & FLAG_KEY) + continue; + + if(flags & FLAG_STREAM_ID) + length+= get_length(pkt->stream_index); + + if(pkt->size % fc->size_mul != fc->size_lsb) + continue; + if(flags & FLAG_SIZE_MSB) + length += get_length(pkt->size / fc->size_mul); + + if(flags & FLAG_CHECKSUM) + length+=4; + + if(flags & FLAG_CODED_PTS) + length += get_length(coded_pts); + + if( (flags & FLAG_CODED) + && nut->header_len[best_header_idx] > nut->header_len[fc->header_idx]+1){ + flags |= FLAG_HEADER_IDX; + } + + if(flags & FLAG_HEADER_IDX){ + length += 1 - nut->header_len[best_header_idx]; + }else{ + length -= nut->header_len[fc->header_idx]; + } + + length*=4; + length+= !(flags & FLAG_CODED_PTS); + length+= !(flags & FLAG_CHECKSUM); + + if(length < best_length){ + best_length= length; + frame_code=i; + } + } + assert(frame_code != -1); + fc= &nut->frame_code[frame_code]; + flags= fc->flags; + needed_flags= get_needed_flags(nut, nus, fc, pkt); + header_idx= fc->header_idx; + + init_checksum(bc, ff_crc04C11DB7_update, 0); + put_byte(bc, frame_code); + if(flags & FLAG_CODED){ + put_v(bc, (flags^needed_flags) & ~(FLAG_CODED)); + flags = needed_flags; + } + if(flags & FLAG_STREAM_ID) put_v(bc, pkt->stream_index); + if(flags & FLAG_CODED_PTS) put_v(bc, coded_pts); + if(flags & FLAG_SIZE_MSB) put_v(bc, pkt->size / fc->size_mul); + if(flags & FLAG_HEADER_IDX) put_v(bc, header_idx= best_header_idx); + + if(flags & FLAG_CHECKSUM) put_le32(bc, get_checksum(bc)); + else get_checksum(bc); + + put_buffer(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]); + nus->last_flags= flags; + nus->last_pts= pkt->pts; + + //FIXME just store one per syncpoint + if(flags & FLAG_KEY) + av_add_index_entry( + s->streams[pkt->stream_index], + nut->last_syncpoint_pos, + pkt->pts, + 0, + 0, + AVINDEX_KEYFRAME); + + return 0; +} + +static int write_trailer(AVFormatContext *s){ + NUTContext *nut= s->priv_data; + ByteIOContext *bc= s->pb; + + while(nut->header_count<3) + write_headers(nut, bc); + put_flush_packet(bc); + + return 0; +} + +AVOutputFormat nut_muxer = { + "nut", + "nut format", + "video/x-nut", + "nut", + sizeof(NUTContext), +#ifdef CONFIG_LIBVORBIS + CODEC_ID_VORBIS, +#elif defined(CONFIG_LIBMP3LAME) + CODEC_ID_MP3, +#else + CODEC_ID_MP2, /* AC3 needs liba52 decoder */ +#endif + CODEC_ID_MPEG4, + write_header, + write_packet, + write_trailer, + .flags = AVFMT_GLOBALHEADER, + .codec_tag= (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0}, +}; diff --git a/contrib/ffmpeg/libavformat/nuv.c b/contrib/ffmpeg/libavformat/nuv.c index 7e04222ee..f56d116ff 100644 --- a/contrib/ffmpeg/libavformat/nuv.c +++ b/contrib/ffmpeg/libavformat/nuv.c @@ -24,6 +24,7 @@ typedef struct { int v_id; int a_id; + int rtjpg_video; } NUVContext; typedef enum { @@ -35,8 +36,6 @@ typedef enum { } frametype_t; static int nuv_probe(AVProbeData *p) { - if (p->buf_size < 12) - return 0; if (!memcmp(p->buf, "NuppelVideo", 12)) return AVPROBE_SCORE_MAX; if (!memcmp(p->buf, "MythTVVideo", 12)) @@ -86,6 +85,8 @@ static int get_codec_data(ByteIOContext *pb, AVStream *vst, vst->codec->codec_tag = get_le32(pb); vst->codec->codec_id = codec_get_id(codec_bmp_tags, vst->codec->codec_tag); + if (vst->codec->codec_tag == MKTAG('R', 'J', 'P', 'G')) + vst->codec->codec_id = CODEC_ID_NUV; } else url_fskip(pb, 4); @@ -97,6 +98,7 @@ static int get_codec_data(ByteIOContext *pb, AVStream *vst, ast->codec->codec_id = wav_codec_get_id(ast->codec->codec_tag, ast->codec->bits_per_sample); + ast->need_parsing = AVSTREAM_PARSE_FULL; } else url_fskip(pb, 4 * 4); @@ -117,8 +119,8 @@ static int get_codec_data(ByteIOContext *pb, AVStream *vst, } static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) { - NUVContext *ctx = (NUVContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + NUVContext *ctx = s->priv_data; + ByteIOContext *pb = s->pb; char id_string[12], version_string[5]; double aspect, fps; int is_mythtv, width, height, v_packs, a_packs; @@ -149,7 +151,6 @@ static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) { vst = av_new_stream(s, ctx->v_id); vst->codec->codec_type = CODEC_TYPE_VIDEO; vst->codec->codec_id = CODEC_ID_NUV; - vst->codec->codec_tag = MKTAG('R', 'J', 'P', 'G'); vst->codec->width = width; vst->codec->height = height; vst->codec->bits_per_sample = 10; @@ -174,39 +175,45 @@ static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) { ctx->a_id = -1; get_codec_data(pb, vst, ast, is_mythtv); + ctx->rtjpg_video = vst->codec->codec_id == CODEC_ID_NUV; return 0; } #define HDRSIZE 12 static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { - NUVContext *ctx = (NUVContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + NUVContext *ctx = s->priv_data; + ByteIOContext *pb = s->pb; uint8_t hdr[HDRSIZE]; frametype_t frametype; int ret, size; while (!url_feof(pb)) { + int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0; ret = get_buffer(pb, hdr, HDRSIZE); if (ret <= 0) return ret ? ret : -1; frametype = hdr[0]; size = PKTSIZE(AV_RL32(&hdr[8])); switch (frametype) { - case NUV_VIDEO: case NUV_EXTRADATA: + if (!ctx->rtjpg_video) { + url_fskip(pb, size); + break; + } + case NUV_VIDEO: if (ctx->v_id < 0) { av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n"); url_fskip(pb, size); break; } - ret = av_new_packet(pkt, HDRSIZE + size); + ret = av_new_packet(pkt, copyhdrsize + size); if (ret < 0) return ret; - pkt->pos = url_ftell(pb); + pkt->pos = url_ftell(pb) - copyhdrsize; pkt->pts = AV_RL32(&hdr[4]); pkt->stream_index = ctx->v_id; - memcpy(pkt->data, hdr, HDRSIZE); - ret = get_buffer(pb, pkt->data + HDRSIZE, size); + memcpy(pkt->data, hdr, copyhdrsize); + ret = get_buffer(pb, pkt->data + copyhdrsize, size); return ret; case NUV_AUDIO: if (ctx->a_id < 0) { @@ -226,7 +233,7 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { break; } } - return AVERROR_IO; + return AVERROR(EIO); } AVInputFormat nuv_demuxer = { diff --git a/contrib/ffmpeg/libavformat/ogg.c b/contrib/ffmpeg/libavformat/ogg.c deleted file mode 100644 index c98bb2273..000000000 --- a/contrib/ffmpeg/libavformat/ogg.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Ogg bitstream support - * Mark Hills <mark@pogo.org.uk> - * - * Uses libogg, but requires libvorbisenc to construct correct headers - * when containing Vorbis stream -- currently the only format supported - * - * 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 <ogg/ogg.h> - -#include "avformat.h" - -#undef NDEBUG -#include <assert.h> - -#define DECODER_BUFFER_SIZE 4096 - - -typedef struct OggContext { - /* output */ - ogg_stream_state os ; - int header_handled ; - ogg_packet op; - - /* input */ - ogg_sync_state oy ; -} OggContext ; - - -#ifdef CONFIG_MUXERS -static int ogg_write_header(AVFormatContext *avfcontext) -{ - OggContext *context = avfcontext->priv_data; - ogg_packet *op= &context->op; - int n; - - ogg_stream_init(&context->os, 31415); - - for(n = 0 ; n < avfcontext->nb_streams ; n++) { - AVCodecContext *codec = avfcontext->streams[n]->codec; - uint8_t *headers = codec->extradata; - int headers_len = codec->extradata_size; - uint8_t *header_start[3]; - int header_len[3]; - int i, j; - - av_set_pts_info(avfcontext->streams[n], 60, 1, AV_TIME_BASE); - - for(j=1,i=0;i<2;++i, ++j) { - header_len[i]=0; - while(j<headers_len && headers[j]==0xff) { - header_len[i]+=0xff; - ++j; - } - header_len[i]+=headers[j]; - } - header_len[2]=headers_len-header_len[0]-header_len[1]-j; - headers+=j; - header_start[0] = headers; - header_start[1] = header_start[0] + header_len[0]; - header_start[2] = header_start[1] + header_len[1]; - - for(i=0; i < 3; ++i){ - op->bytes = header_len[i]; - - op->packet= header_start[i]; - op->b_o_s= op->packetno==0; - - ogg_stream_packetin(&context->os, op); - - op->packetno++; //FIXME multiple streams - } - - context->header_handled = 0 ; - } - - return 0 ; -} - -static int ogg_write_packet(AVFormatContext *avfcontext, AVPacket *pkt) -{ - OggContext *context = avfcontext->priv_data ; - AVCodecContext *avctx= avfcontext->streams[pkt->stream_index]->codec; - ogg_packet *op= &context->op; - ogg_page og ; - int64_t pts; - - pts= av_rescale(pkt->pts, avctx->sample_rate, AV_TIME_BASE); - -// av_log(avfcontext, AV_LOG_DEBUG, "M%d\n", size); - - /* flush header packets so audio starts on a new page */ - - if(!context->header_handled) { - while(ogg_stream_flush(&context->os, &og)) { - put_buffer(&avfcontext->pb, og.header, og.header_len) ; - put_buffer(&avfcontext->pb, og.body, og.body_len) ; - put_flush_packet(&avfcontext->pb); - } - context->header_handled = 1 ; - } - - op->packet = (uint8_t*) pkt->data; - op->bytes = pkt->size; - op->b_o_s = op->packetno == 0; - op->granulepos= pts; - - /* correct the fields in the packet -- essential for streaming */ - - ogg_stream_packetin(&context->os, op); - - while(ogg_stream_pageout(&context->os, &og)) { - put_buffer(&avfcontext->pb, og.header, og.header_len); - put_buffer(&avfcontext->pb, og.body, og.body_len); - put_flush_packet(&avfcontext->pb); - } - op->packetno++; - - return 0; -} - - -static int ogg_write_trailer(AVFormatContext *avfcontext) { - OggContext *context = avfcontext->priv_data ; - ogg_page og ; - - while(ogg_stream_flush(&context->os, &og)) { - put_buffer(&avfcontext->pb, og.header, og.header_len) ; - put_buffer(&avfcontext->pb, og.body, og.body_len) ; - put_flush_packet(&avfcontext->pb); - } - - ogg_stream_clear(&context->os) ; - return 0 ; -} - - -AVOutputFormat ogg_muxer = { - "ogg", - "Ogg format", - "application/ogg", - "ogg", - sizeof(OggContext), - CODEC_ID_VORBIS, - 0, - ogg_write_header, - ogg_write_packet, - ogg_write_trailer, -} ; -#endif //CONFIG_MUXERS - -#if 0 -static int next_packet(AVFormatContext *avfcontext, ogg_packet *op) { - OggContext *context = avfcontext->priv_data ; - ogg_page og ; - char *buf ; - - while(ogg_stream_packetout(&context->os, op) != 1) { - - /* while no pages are available, read in more data to the sync */ - while(ogg_sync_pageout(&context->oy, &og) != 1) { - buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ; - if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0) - return 1 ; - ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ; - } - - /* got a page. Feed it into the stream and get the packet */ - if(ogg_stream_pagein(&context->os, &og) != 0) - return 1 ; - } - - return 0 ; -} - - -static int ogg_read_header(AVFormatContext *avfcontext, AVFormatParameters *ap) -{ - OggContext *context = avfcontext->priv_data; - ogg_packet op ; - char *buf ; - ogg_page og ; - AVStream *ast ; - AVCodecContext *codec; - uint8_t *p; - int i; - - ogg_sync_init(&context->oy) ; - buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ; - - if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0) - return AVERROR_IO ; - - ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ; - ogg_sync_pageout(&context->oy, &og) ; - ogg_stream_init(&context->os, ogg_page_serialno(&og)) ; - ogg_stream_pagein(&context->os, &og) ; - - /* currently only one vorbis stream supported */ - - ast = av_new_stream(avfcontext, 0) ; - if(!ast) - return AVERROR_NOMEM ; - av_set_pts_info(ast, 60, 1, AV_TIME_BASE); - - codec= &ast->codec; - codec->codec_type = CODEC_TYPE_AUDIO; - codec->codec_id = CODEC_ID_VORBIS; - for(i=0; i<3; i++){ - if(next_packet(avfcontext, &op)){ - return -1; - } - if(op.bytes >= (1<<16) || op.bytes < 0) - return -1; - codec->extradata_size+= 2 + op.bytes; - codec->extradata= av_realloc(codec->extradata, codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - memset(codec->extradata + codec->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); - p= codec->extradata + codec->extradata_size - 2 - op.bytes; - *(p++)= op.bytes>>8; - *(p++)= op.bytes&0xFF; - memcpy(p, op.packet, op.bytes); - } - - return 0 ; -} - - -static int ogg_read_packet(AVFormatContext *avfcontext, AVPacket *pkt) { - ogg_packet op ; - - if(next_packet(avfcontext, &op)) - return AVERROR_IO ; - if(av_new_packet(pkt, op.bytes) < 0) - return AVERROR_IO ; - pkt->stream_index = 0 ; - memcpy(pkt->data, op.packet, op.bytes); - if(avfcontext->streams[0]->codec.sample_rate && op.granulepos!=-1) - pkt->pts= av_rescale(op.granulepos, AV_TIME_BASE, avfcontext->streams[0]->codec.sample_rate); -// printf("%"PRId64" %d %d\n", pkt->pts, (int)op.granulepos, avfcontext->streams[0]->codec.sample_rate); - - return op.bytes; -} - - -static int ogg_read_close(AVFormatContext *avfcontext) { - OggContext *context = avfcontext->priv_data ; - - ogg_stream_clear(&context->os) ; - ogg_sync_clear(&context->oy) ; - - return 0 ; -} - - -static AVInputFormat ogg_iformat = { - "ogg", - "Ogg Vorbis", - sizeof(OggContext), - NULL, - ogg_read_header, - ogg_read_packet, - ogg_read_close, - .extensions = "ogg", -} ; -#endif diff --git a/contrib/ffmpeg/libavformat/ogg2.c b/contrib/ffmpeg/libavformat/oggdec.c index 8ca7b2d13..96d16a873 100644 --- a/contrib/ffmpeg/libavformat/ogg2.c +++ b/contrib/ffmpeg/libavformat/oggdec.c @@ -31,54 +31,25 @@ #include <stdio.h> -#include "ogg2.h" +#include "oggdec.h" #include "avformat.h" #define MAX_PAGE_SIZE 65307 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE static ogg_codec_t *ogg_codecs[] = { + &speex_codec, &vorbis_codec, &theora_codec, &flac_codec, + &old_flac_codec, &ogm_video_codec, &ogm_audio_codec, + &ogm_text_codec, &ogm_old_codec, NULL }; -#if 0 // CONFIG_MUXERS -static int -ogg_write_header (AVFormatContext * avfcontext) -{ -} - -static int -ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt) -{ -} - - -static int -ogg_write_trailer (AVFormatContext * avfcontext) -{ -} - - -AVOutputFormat ogg_muxer = { - "ogg", - "Ogg format", - "application/ogg", - "ogg", - sizeof (OggContext), - CODEC_ID_VORBIS, - 0, - ogg_write_header, - ogg_write_packet, - ogg_write_trailer, -}; -#endif //CONFIG_MUXERS - //FIXME We could avoid some structure duplication static int ogg_save (AVFormatContext * s) @@ -87,7 +58,7 @@ ogg_save (AVFormatContext * s) ogg_state_t *ost = av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams)); int i; - ost->pos = url_ftell (&s->pb);; + ost->pos = url_ftell (s->pb); ost->curidx = ogg->curidx; ost->next = ogg->state; ost->nstreams = ogg->nstreams; @@ -109,7 +80,7 @@ static int ogg_restore (AVFormatContext * s, int discard) { ogg_t *ogg = s->priv_data; - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; ogg_state_t *ost = ogg->state; int i; @@ -200,7 +171,7 @@ ogg_new_stream (AVFormatContext * s, uint32_t serial) st = av_new_stream (s, idx); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 64, 1, 1000000); @@ -227,7 +198,7 @@ ogg_new_buf(ogg_t *ogg, int idx) static int ogg_read_page (AVFormatContext * s, int *str) { - ByteIOContext *bc = &s->pb; + ByteIOContext *bc = s->pb; ogg_t *ogg = s->priv_data; ogg_stream_t *os; int i = 0; @@ -408,6 +379,7 @@ ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize) } if (os->header > -1 && os->seq > os->header){ + os->pflags = 0; if (os->codec && os->codec->packet) os->codec->packet (s, idx); if (str) @@ -468,20 +440,20 @@ ogg_get_length (AVFormatContext * s) int idx = -1, i; offset_t size, end; - if(s->pb.is_streamed) + if(url_is_streamed(s->pb)) return 0; // already set if (s->duration != AV_NOPTS_VALUE) return 0; - size = url_fsize(&s->pb); + size = url_fsize(s->pb); if(size < 0) return 0; end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size; ogg_save (s); - url_fseek (&s->pb, end, SEEK_SET); + url_fseek (s->pb, end, SEEK_SET); while (!ogg_read_page (s, &i)){ if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && @@ -540,7 +512,7 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt) //Get an ogg packet do{ if (ogg_packet (s, &idx, &pstart, &psize) < 0) - return AVERROR_IO; + return AVERROR(EIO); }while (idx < 0 || !s->streams[idx]); ogg = s->priv_data; @@ -548,7 +520,7 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt) //Alloc a pkt if (av_new_packet (pkt, psize) < 0) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = idx; memcpy (pkt->data, os->buf + pstart, psize); if (os->lastgp != -1LL){ @@ -556,6 +528,8 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt) os->lastgp = -1; } + pkt->flags = os->pflags; + return psize; } @@ -575,109 +549,31 @@ ogg_read_close (AVFormatContext * s) } -static int -ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts, - int flags) +static int64_t +ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, + int64_t pos_limit) { - AVStream *st = s->streams[stream_index]; ogg_t *ogg = s->priv_data; - ByteIOContext *bc = &s->pb; - uint64_t min = 0, max = ogg->size; - uint64_t tmin = st->start_time, tmax = st->start_time + st->duration; + ByteIOContext *bc = s->pb; int64_t pts = AV_NOPTS_VALUE; - - ogg_save (s); - - if ((uint64_t)target_ts < tmin || target_ts < 0) - target_ts = tmin; - while (min <= max && tmin < tmax){ - uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin); - int i = -1; - - url_fseek (bc, p, SEEK_SET); - - while (!ogg_read_page (s, &i)){ - if (i == stream_index && ogg->streams[i].granule != 0 && - ogg->streams[i].granule != -1) - break; - } - - if (i == -1) - break; - - pts = ogg_gptopts (s, i, ogg->streams[i].granule); - p = url_ftell (bc); - - if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den) + int i; + url_fseek(bc, *pos_arg, SEEK_SET); + while (url_ftell(bc) < pos_limit && !ogg_read_page (s, &i)) { + if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && + ogg->streams[i].codec && i == stream_index) { + pts = ogg_gptopts(s, i, ogg->streams[i].granule); + // FIXME: this is the position of the packet after the one with above + // pts. + *pos_arg = url_ftell(bc); break; - - if (pts > target_ts){ - if (max == p && tmax == pts) { - // probably our tmin is wrong, causing us to always end up too late in the file - tmin = (target_ts + tmin + 1) / 2; - if (tmin == target_ts) { - url_fseek(bc, min, SEEK_SET); - break; - } - } - max = p; - tmax = pts; - }else{ - if (min == p && tmin == pts) { - // probably our tmax is wrong, causing us to always end up too early in the file - tmax = (target_ts + tmax) / 2; - if (tmax == target_ts) { - url_fseek(bc, max, SEEK_SET); - break; - } - } - min = p; - tmin = pts; } } - - if (FFABS (pts - target_ts) * st->time_base.num < st->time_base.den){ - ogg_restore (s, 1); - ogg_reset (ogg); - }else{ - ogg_restore (s, 0); - pts = AV_NOPTS_VALUE; - } - - av_update_cur_dts(s, st, pts); - return 0; - -#if 0 - //later... - int64_t pos; - if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0) - return -1; - pos = url_ftell (&s->pb); - ogg_read_timestamp (s, stream_index, &pos, pos - 1); -#endif - -} - -#if 0 -static int64_t -ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg, - int64_t pos_limit) -{ - ogg_t *ogg = s->priv_data; - ByteIOContext *bc = &s->pb; - int64_t pos, pts; - - if (*pos_arg < 0) - return AV_NOPTS_VALUE; - - pos = *pos_arg; + ogg_reset(ogg); + return pts; } -#endif static int ogg_probe(AVProbeData *p) { - if (p->buf_size < 6) - return 0; if (p->buf[0] == 'O' && p->buf[1] == 'g' && p->buf[2] == 'g' && p->buf[3] == 'S' && p->buf[4] == 0x0 && p->buf[5] <= 0x7 ) @@ -694,7 +590,7 @@ AVInputFormat ogg_demuxer = { ogg_read_header, ogg_read_packet, ogg_read_close, - ogg_read_seek, -// ogg_read_timestamp, + NULL, + ogg_read_timestamp, .extensions = "ogg", }; diff --git a/contrib/ffmpeg/libavformat/ogg2.h b/contrib/ffmpeg/libavformat/oggdec.h index 6b7c6b22e..4e88d0e39 100644 --- a/contrib/ffmpeg/libavformat/ogg2.h +++ b/contrib/ffmpeg/libavformat/oggdec.h @@ -22,15 +22,15 @@ DEALINGS IN THE SOFTWARE. **/ -#ifndef OGG_H -#define OGG_H +#ifndef FFMPEG_OGGDEC_H +#define FFMPEG_OGGDEC_H #include "avformat.h" typedef struct ogg_codec { - int8_t *magic; + const int8_t *magic; uint8_t magicsize; - int8_t *name; + const int8_t *name; int (*header)(AVFormatContext *, int); int (*packet)(AVFormatContext *, int); uint64_t (*gptopts)(AVFormatContext *, int, uint64_t); @@ -42,6 +42,7 @@ typedef struct ogg_stream { unsigned int bufpos; unsigned int pstart; unsigned int psize; + unsigned int pflags; uint32_t serial; uint32_t seq; uint64_t granule, lastgp; @@ -74,13 +75,16 @@ typedef struct ogg { #define OGG_FLAG_BOS 2 #define OGG_FLAG_EOS 4 -extern ogg_codec_t vorbis_codec; -extern ogg_codec_t theora_codec; extern ogg_codec_t flac_codec; -extern ogg_codec_t ogm_video_codec; extern ogg_codec_t ogm_audio_codec; extern ogg_codec_t ogm_old_codec; +extern ogg_codec_t ogm_text_codec; +extern ogg_codec_t ogm_video_codec; +extern ogg_codec_t old_flac_codec; +extern ogg_codec_t speex_codec; +extern ogg_codec_t theora_codec; +extern ogg_codec_t vorbis_codec; extern int vorbis_comment(AVFormatContext *ms, uint8_t *buf, int size); -#endif +#endif /* FFMPEG_OGGDEC_H */ diff --git a/contrib/ffmpeg/libavformat/oggenc.c b/contrib/ffmpeg/libavformat/oggenc.c new file mode 100644 index 000000000..af2c5de12 --- /dev/null +++ b/contrib/ffmpeg/libavformat/oggenc.c @@ -0,0 +1,292 @@ +/* + * Ogg muxer + * Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr> + * + * 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 "crc.h" +#include "xiph.h" +#include "bytestream.h" + +typedef struct { + int64_t duration; + unsigned page_counter; + uint8_t *header[3]; + int header_len[3]; + /** for theora granule */ + int kfgshift; + int64_t last_kf_pts; + int vrev; + int eos; +} OGGStreamContext; + +static void ogg_update_checksum(AVFormatContext *s, offset_t crc_offset) +{ + offset_t pos = url_ftell(s->pb); + uint32_t checksum = get_checksum(s->pb); + url_fseek(s->pb, crc_offset, SEEK_SET); + put_be32(s->pb, checksum); + url_fseek(s->pb, pos, SEEK_SET); +} + +static int ogg_write_page(AVFormatContext *s, const uint8_t *data, int size, + int64_t granule, int stream_index, int flags) +{ + OGGStreamContext *oggstream = s->streams[stream_index]->priv_data; + offset_t crc_offset; + int page_segments, i; + + if (size >= 255*255) { + granule = -1; + size = 255*255; + } else if (oggstream->eos) + flags |= 4; + + page_segments = FFMIN((size/255)+!!size, 255); + + init_checksum(s->pb, ff_crc04C11DB7_update, 0); + put_tag(s->pb, "OggS"); + put_byte(s->pb, 0); + put_byte(s->pb, flags); + put_le64(s->pb, granule); + put_le32(s->pb, stream_index); + put_le32(s->pb, oggstream->page_counter++); + crc_offset = url_ftell(s->pb); + put_le32(s->pb, 0); // crc + put_byte(s->pb, page_segments); + for (i = 0; i < page_segments-1; i++) + put_byte(s->pb, 255); + if (size) { + put_byte(s->pb, size - (page_segments-1)*255); + put_buffer(s->pb, data, size); + } + ogg_update_checksum(s, crc_offset); + put_flush_packet(s->pb); + return size; +} + +static int ogg_build_flac_headers(const uint8_t *extradata, int extradata_size, + OGGStreamContext *oggstream, int bitexact) +{ + const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; + uint8_t *p; + if (extradata_size != 34) + return -1; + oggstream->header_len[0] = 79; + oggstream->header[0] = av_mallocz(79); // per ogg flac specs + p = oggstream->header[0]; + bytestream_put_byte(&p, 0x7F); + bytestream_put_buffer(&p, "FLAC", 4); + bytestream_put_byte(&p, 1); // major version + bytestream_put_byte(&p, 0); // minor version + bytestream_put_be16(&p, 1); // headers packets without this one + bytestream_put_buffer(&p, "fLaC", 4); + bytestream_put_byte(&p, 0x00); // streaminfo + bytestream_put_be24(&p, 34); + bytestream_put_buffer(&p, extradata, 34); + oggstream->header_len[1] = 1+3+4+strlen(vendor)+4; + oggstream->header[1] = av_mallocz(oggstream->header_len[1]); + p = oggstream->header[1]; + bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment + bytestream_put_be24(&p, oggstream->header_len[1] - 4); + bytestream_put_le32(&p, strlen(vendor)); + bytestream_put_buffer(&p, vendor, strlen(vendor)); + bytestream_put_le32(&p, 0); // user comment list length + return 0; +} + +static int ogg_write_header(AVFormatContext *s) +{ + OGGStreamContext *oggstream; + int i, j; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if (st->codec->codec_type == CODEC_TYPE_AUDIO) + av_set_pts_info(st, 64, 1, st->codec->sample_rate); + else if (st->codec->codec_type == CODEC_TYPE_VIDEO) + av_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); + if (st->codec->codec_id != CODEC_ID_VORBIS && + st->codec->codec_id != CODEC_ID_THEORA && + st->codec->codec_id != CODEC_ID_FLAC) { + av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i); + return -1; + } + + if (!st->codec->extradata || !st->codec->extradata_size) { + av_log(s, AV_LOG_ERROR, "No extradata present\n"); + return -1; + } + oggstream = av_mallocz(sizeof(*oggstream)); + st->priv_data = oggstream; + if (st->codec->codec_id == CODEC_ID_FLAC) { + if (ogg_build_flac_headers(st->codec->extradata, st->codec->extradata_size, + oggstream, st->codec->flags & CODEC_FLAG_BITEXACT) < 0) { + av_log(s, AV_LOG_ERROR, "Extradata corrupted\n"); + av_freep(&st->priv_data); + } + } else { + if (ff_split_xiph_headers(st->codec->extradata, st->codec->extradata_size, + st->codec->codec_id == CODEC_ID_VORBIS ? 30 : 42, + oggstream->header, oggstream->header_len) < 0) { + av_log(s, AV_LOG_ERROR, "Extradata corrupted\n"); + av_freep(&st->priv_data); + return -1; + } + if (st->codec->codec_id == CODEC_ID_THEORA) { + /** KFGSHIFT is the width of the less significant section of the granule position + The less significant section is the frame count since the last keyframe */ + oggstream->kfgshift = ((oggstream->header[0][40]&3)<<3)|(oggstream->header[0][41]>>5); + oggstream->vrev = oggstream->header[0][9]; + av_log(s, AV_LOG_DEBUG, "theora kfgshift %d, vrev %d\n", + oggstream->kfgshift, oggstream->vrev); + } + } + } + for (i = 0; i < 3; i++) { + for (j = 0; j < s->nb_streams; j++) { + AVStream *st = s->streams[j]; + OGGStreamContext *oggstream = st->priv_data; + if (oggstream && oggstream->header_len[i]) { + ogg_write_page(s, oggstream->header[i], oggstream->header_len[i], + 0, st->index, i ? 0 : 2); // bos + } + } + } + return 0; +} + +static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + AVStream *st = s->streams[pkt->stream_index]; + OGGStreamContext *oggstream = st->priv_data; + uint8_t *ptr = pkt->data; + int ret, size = pkt->size; + int64_t granule; + + if (st->codec->codec_id == CODEC_ID_THEORA) { + int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + pkt->duration; + int pframe_count; + if (pkt->flags & PKT_FLAG_KEY) + oggstream->last_kf_pts = pts; + pframe_count = pts - oggstream->last_kf_pts; + // prevent frame count from overflow if key frame flag is not set + if (pframe_count >= (1<<oggstream->kfgshift)) { + oggstream->last_kf_pts += pframe_count; + pframe_count = 0; + } + granule = (oggstream->last_kf_pts<<oggstream->kfgshift) | pframe_count; + } else + granule = pkt->pts + pkt->duration; + oggstream->duration = granule; + do { + ret = ogg_write_page(s, ptr, size, granule, pkt->stream_index, ptr != pkt->data); + ptr += ret; size -= ret; + } while (size > 0 || ret == 255*255); // need to output a last nil page + + return 0; +} + +int ogg_interleave_per_granule(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush) +{ + AVPacketList *pktl, **next_point, *this_pktl; + int stream_count = 0; + int streams[MAX_STREAMS] = {0}; + int interleaved = 0; + + if (pkt) { + AVStream *st = s->streams[pkt->stream_index]; + this_pktl = av_mallocz(sizeof(AVPacketList)); + this_pktl->pkt = *pkt; + if (pkt->destruct == av_destruct_packet) + pkt->destruct = NULL; // not shared -> must keep original from being freed + else + av_dup_packet(&this_pktl->pkt); // shared -> must dup + next_point = &s->packet_buffer; + while (*next_point) { + AVStream *st2 = s->streams[(*next_point)->pkt.stream_index]; + AVPacket *next_pkt = &(*next_point)->pkt; + int64_t cur_granule, next_granule; + next_granule = av_rescale_q(next_pkt->pts + next_pkt->duration, + st2->time_base, AV_TIME_BASE_Q); + cur_granule = av_rescale_q(pkt->pts + pkt->duration, + st->time_base, AV_TIME_BASE_Q); + if (next_granule > cur_granule) + break; + next_point= &(*next_point)->next; + } + this_pktl->next= *next_point; + *next_point= this_pktl; + } + + pktl = s->packet_buffer; + while (pktl) { + if (streams[pktl->pkt.stream_index] == 0) + stream_count++; + streams[pktl->pkt.stream_index]++; + // need to buffer at least one packet to set eos flag + if (streams[pktl->pkt.stream_index] == 2) + interleaved++; + pktl = pktl->next; + } + + if ((s->nb_streams == stream_count && interleaved == stream_count) || + (flush && stream_count)) { + pktl= s->packet_buffer; + *out= pktl->pkt; + s->packet_buffer = pktl->next; + if (flush && streams[out->stream_index] == 1) { + OGGStreamContext *ogg = s->streams[out->stream_index]->priv_data; + ogg->eos = 1; + } + av_freep(&pktl); + return 1; + } else { + av_init_packet(out); + return 0; + } +} + +static int ogg_write_trailer(AVFormatContext *s) +{ + int i; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + OGGStreamContext *oggstream = st->priv_data; + if (st->codec->codec_id == CODEC_ID_FLAC) { + av_free(oggstream->header[0]); + av_free(oggstream->header[1]); + } + av_freep(&st->priv_data); + } + return 0; +} + +AVOutputFormat ogg_muxer = { + "ogg", + "Ogg format", + "application/ogg", + "ogg", + 0, + CODEC_ID_FLAC, + CODEC_ID_THEORA, + ogg_write_header, + ogg_write_packet, + ogg_write_trailer, + .interleave_packet = ogg_interleave_per_granule, +}; diff --git a/contrib/ffmpeg/libavformat/oggparseflac.c b/contrib/ffmpeg/libavformat/oggparseflac.c index 8960088d8..611a8c5a1 100644 --- a/contrib/ffmpeg/libavformat/oggparseflac.c +++ b/contrib/ffmpeg/libavformat/oggparseflac.c @@ -21,7 +21,7 @@ #include <stdlib.h> #include "avformat.h" #include "bitstream.h" -#include "ogg2.h" +#include "oggdec.h" #define FLAC_STREAMINFO_SIZE 0x22 @@ -49,7 +49,7 @@ flac_header (AVFormatContext * s, int idx) skip_bits(&gb, 4*8); /* "fLaC" */ /* METADATA_BLOCK_HEADER */ - if (get_bits(&gb, 32) != FLAC_STREAMINFO_SIZE) + if (get_bits_long(&gb, 32) != FLAC_STREAMINFO_SIZE) return -1; skip_bits(&gb, 16*2+24*2); @@ -75,8 +75,24 @@ flac_header (AVFormatContext * s, int idx) return 1; } +static int +old_flac_header (AVFormatContext * s, int idx) +{ + AVStream *st = s->streams[idx]; + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_FLAC; + + return 0; +} + ogg_codec_t flac_codec = { .magic = "\177FLAC", .magicsize = 5, .header = flac_header }; + +ogg_codec_t old_flac_codec = { + .magic = "fLaC", + .magicsize = 4, + .header = old_flac_header +}; diff --git a/contrib/ffmpeg/libavformat/oggparseogm.c b/contrib/ffmpeg/libavformat/oggparseogm.c index 8788e5d41..70e53948f 100644 --- a/contrib/ffmpeg/libavformat/oggparseogm.c +++ b/contrib/ffmpeg/libavformat/oggparseogm.c @@ -25,8 +25,9 @@ #include <stdlib.h> #include "avformat.h" #include "bitstream.h" -#include "bswap.h" -#include "ogg2.h" +#include "bytestream.h" +#include "intreadwrite.h" +#include "oggdec.h" #include "riff.h" static int @@ -35,7 +36,7 @@ ogm_header(AVFormatContext *s, int idx) ogg_t *ogg = s->priv_data; ogg_stream_t *os = ogg->streams + idx; AVStream *st = s->streams[idx]; - uint8_t *p = os->buf + os->pstart; + const uint8_t *p = os->buf + os->pstart; uint64_t time_unit; uint64_t spu; uint32_t default_len; @@ -51,42 +52,42 @@ ogm_header(AVFormatContext *s, int idx) int tag; st->codec->codec_type = CODEC_TYPE_VIDEO; p += 8; - tag = le2me_32(unaligned32(p)); - st->codec->codec_id = codec_get_bmp_id(tag); + tag = bytestream_get_le32(&p); + st->codec->codec_id = codec_get_id(codec_bmp_tags, tag); st->codec->codec_tag = tag; + } else if (*p == 't') { + st->codec->codec_type = CODEC_TYPE_SUBTITLE; + st->codec->codec_id = CODEC_ID_TEXT; + p += 12; } else { + uint8_t acid[5]; int cid; st->codec->codec_type = CODEC_TYPE_AUDIO; p += 8; - p[4] = 0; - cid = strtol(p, NULL, 16); - st->codec->codec_id = codec_get_wav_id(cid); + bytestream_get_buffer(&p, acid, 4); + acid[4] = 0; + cid = strtol(acid, NULL, 16); + st->codec->codec_id = codec_get_id(codec_wav_tags, cid); } - p += 4; p += 4; /* useless size field */ - time_unit = le2me_64(unaligned64(p)); - p += 8; - spu = le2me_64(unaligned64(p)); - p += 8; - default_len = le2me_32(unaligned32(p)); - p += 4; + time_unit = bytestream_get_le64(&p); + spu = bytestream_get_le64(&p); + default_len = bytestream_get_le32(&p); p += 8; /* buffersize + bits_per_sample */ if(st->codec->codec_type == CODEC_TYPE_VIDEO){ - st->codec->width = le2me_32(unaligned32(p)); - p += 4; - st->codec->height = le2me_32(unaligned32(p)); + st->codec->width = bytestream_get_le32(&p); + st->codec->height = bytestream_get_le32(&p); st->codec->time_base.den = spu * 10000000; st->codec->time_base.num = time_unit; st->time_base = st->codec->time_base; } else { - st->codec->channels = le2me_16(unaligned16(p)); - p += 2; + st->codec->channels = bytestream_get_le16(&p); p += 2; /* block_align */ - st->codec->bit_rate = le2me_32(unaligned32(p)) * 8; + st->codec->bit_rate = bytestream_get_le32(&p) * 8; st->codec->sample_rate = spu * 10000000 / time_unit; st->time_base.num = 1; st->time_base.den = st->codec->sample_rate; @@ -109,21 +110,21 @@ ogm_dshow_header(AVFormatContext *s, int idx) if(*p != 1) return 1; - t = le2me_32(unaligned32(p + 96)); + t = AV_RL32(p + 96); if(t == 0x05589f80){ st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = codec_get_bmp_id(le2me_32(unaligned32(p + 68))); + st->codec->codec_id = codec_get_id(codec_bmp_tags, AV_RL32(p + 68)); st->codec->time_base.den = 10000000; - st->codec->time_base.num = le2me_64(unaligned64(p + 164)); - st->codec->width = le2me_32(unaligned32(p + 176)); - st->codec->height = le2me_32(unaligned32(p + 180)); + st->codec->time_base.num = AV_RL64(p + 164); + st->codec->width = AV_RL32(p + 176); + st->codec->height = AV_RL32(p + 180); } else if(t == 0x05589f81){ st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = codec_get_wav_id(le2me_16(unaligned16(p+124))); - st->codec->channels = le2me_16(unaligned16(p + 126)); - st->codec->sample_rate = le2me_32(unaligned32(p + 128)); - st->codec->bit_rate = le2me_32(unaligned32(p + 132)) * 8; + st->codec->codec_id = codec_get_id(codec_wav_tags, AV_RL16(p + 124)); + st->codec->channels = AV_RL16(p + 126); + st->codec->sample_rate = AV_RL32(p + 128); + st->codec->bit_rate = AV_RL32(p + 132) * 8; } return 1; @@ -137,6 +138,9 @@ ogm_packet(AVFormatContext *s, int idx) uint8_t *p = os->buf + os->pstart; int lb; + if(*p & 8) + os->pflags |= PKT_FLAG_KEY; + lb = ((*p & 2) << 1) | ((*p >> 6) & 3); os->pstart += lb + 1; os->psize -= lb + 1; @@ -158,6 +162,13 @@ ogg_codec_t ogm_audio_codec = { .packet = ogm_packet }; +ogg_codec_t ogm_text_codec = { + .magic = "\001text", + .magicsize = 5, + .header = ogm_header, + .packet = ogm_packet +}; + ogg_codec_t ogm_old_codec = { .magic = "\001Direct Show Samples embedded in Ogg", .magicsize = 35, diff --git a/contrib/ffmpeg/libavformat/oggparsespeex.c b/contrib/ffmpeg/libavformat/oggparsespeex.c new file mode 100644 index 000000000..a6c44271e --- /dev/null +++ b/contrib/ffmpeg/libavformat/oggparsespeex.c @@ -0,0 +1,61 @@ +/* + Copyright (C) 2008 Reimar Döffinger + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +**/ + +#include <stdlib.h> +#include "avformat.h" +#include "bitstream.h" +#include "bytestream.h" +#include "bswap.h" +#include "oggdec.h" +#include "avstring.h" + +static int speex_header(AVFormatContext *s, int idx) { + ogg_t *ogg = s->priv_data; + ogg_stream_t *os = ogg->streams + idx; + AVStream *st = s->streams[idx]; + uint8_t *p = os->buf + os->pstart; + + if (os->psize < 80) + return 1; + + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_SPEEX; + + st->codec->sample_rate = AV_RL32(p + 36); + st->codec->channels = AV_RL32(p + 48); + st->codec->extradata_size = os->psize; + st->codec->extradata = av_malloc(st->codec->extradata_size); + memcpy(st->codec->extradata, p, st->codec->extradata_size); + + st->time_base.num = 1; + st->time_base.den = st->codec->sample_rate; + + return 0; +} + +ogg_codec_t speex_codec = { + .magic = "Speex ", + .magicsize = 8, + .header = speex_header +}; diff --git a/contrib/ffmpeg/libavformat/oggparsetheora.c b/contrib/ffmpeg/libavformat/oggparsetheora.c index 9052bbbea..b976dcb70 100644 --- a/contrib/ffmpeg/libavformat/oggparsetheora.c +++ b/contrib/ffmpeg/libavformat/oggparsetheora.c @@ -26,7 +26,7 @@ #include "avformat.h" #include "bitstream.h" #include "bswap.h" -#include "ogg2.h" +#include "oggdec.h" typedef struct theora_params { int gpshift; @@ -53,16 +53,14 @@ theora_header (AVFormatContext * s, int idx) if (os->buf[os->pstart] == 0x80) { GetBitContext gb; + int width, height; int version; init_get_bits(&gb, os->buf + os->pstart, os->psize*8); skip_bits(&gb, 7*8); /* 0x80"theora" */ - version = get_bits(&gb, 8) << 16; - version |= get_bits(&gb, 8) << 8; - version |= get_bits(&gb, 8); - + version = get_bits_long(&gb, 24); if (version < 0x030100) { av_log(s, AV_LOG_ERROR, @@ -70,19 +68,27 @@ theora_header (AVFormatContext * s, int idx) return -1; } - st->codec->width = get_bits(&gb, 16) << 4; - st->codec->height = get_bits(&gb, 16) << 4; + width = get_bits(&gb, 16) << 4; + height = get_bits(&gb, 16) << 4; + avcodec_set_dimensions(st->codec, width, height); if (version >= 0x030400) - skip_bits(&gb, 164); - else if (version >= 0x030200) - skip_bits(&gb, 64); - st->codec->time_base.den = get_bits(&gb, 32); - st->codec->time_base.num = get_bits(&gb, 32); + skip_bits(&gb, 100); + + width = get_bits_long(&gb, 24); + height = get_bits_long(&gb, 24); + if ( width <= st->codec->width && width > st->codec->width-16 + && height <= st->codec->height && height > st->codec->height-16) + avcodec_set_dimensions(st->codec, width, height); + + if (version >= 0x030200) + skip_bits(&gb, 16); + st->codec->time_base.den = get_bits_long(&gb, 32); + st->codec->time_base.num = get_bits_long(&gb, 32); st->time_base = st->codec->time_base; - st->codec->sample_aspect_ratio.num = get_bits(&gb, 24); - st->codec->sample_aspect_ratio.den = get_bits(&gb, 24); + st->codec->sample_aspect_ratio.num = get_bits_long(&gb, 24); + st->codec->sample_aspect_ratio.den = get_bits_long(&gb, 24); if (version >= 0x030200) skip_bits(&gb, 38); @@ -118,6 +124,9 @@ theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp) uint64_t iframe = gp >> thp->gpshift; uint64_t pframe = gp & thp->gpmask; + if(!pframe) + os->pflags |= PKT_FLAG_KEY; + return iframe + pframe; } diff --git a/contrib/ffmpeg/libavformat/oggparsevorbis.c b/contrib/ffmpeg/libavformat/oggparsevorbis.c index 5de221cb4..cc914ce39 100644 --- a/contrib/ffmpeg/libavformat/oggparsevorbis.c +++ b/contrib/ffmpeg/libavformat/oggparsevorbis.c @@ -25,49 +25,44 @@ #include <stdlib.h> #include "avformat.h" #include "bitstream.h" +#include "bytestream.h" #include "bswap.h" -#include "ogg2.h" +#include "oggdec.h" +#include "avstring.h" extern int -vorbis_comment (AVFormatContext * as, uint8_t *buf, int size) +vorbis_comment(AVFormatContext * as, uint8_t *buf, int size) { - char *p = buf; - int s, n, j; + const uint8_t *p = buf; + const uint8_t *end = buf + size; + unsigned s, n, j; - if (size < 4) + if (size < 8) /* must have vendor_length and user_comment_list_length */ return -1; - s = le2me_32 (unaligned32 (p)); - p += 4; - size -= 4; + s = bytestream_get_le32(&p); - if (size < s + 4) + if (end - p < s) return -1; p += s; - size -= s; - n = le2me_32 (unaligned32 (p)); - p += 4; - size -= 4; + n = bytestream_get_le32(&p); - while (size >= 4){ - char *t, *v; + while (p < end && n > 0) { + const char *t, *v; int tl, vl; - s = le2me_32 (unaligned32 (p)); - p += 4; - size -= 4; + s = bytestream_get_le32(&p); - if (size < s) + if (end - p < s) break; t = p; p += s; - size -= s; n--; - v = memchr (t, '=', s); + v = memchr(t, '=', s); if (!v) continue; @@ -75,39 +70,40 @@ vorbis_comment (AVFormatContext * as, uint8_t *buf, int size) vl = s - tl - 1; v++; - if (tl && vl){ + if (tl && vl) { char tt[tl + 1]; char ct[vl + 1]; for (j = 0; j < tl; j++) - tt[j] = toupper (t[j]); + tt[j] = toupper(t[j]); tt[tl] = 0; - memcpy (ct, v, vl); + memcpy(ct, v, vl); ct[vl] = 0; // took from Vorbis_I_spec - if (!strcmp (tt, "AUTHOR")) - strncpy (as->author, ct, FFMIN(sizeof (as->author), vl)); - else if (!strcmp (tt, "TITLE")) - strncpy (as->title, ct, FFMIN(sizeof (as->title), vl)); - else if (!strcmp (tt, "COPYRIGHT")) - strncpy (as->copyright, ct, FFMIN(sizeof (as->copyright), vl)); - else if (!strcmp (tt, "DESCRIPTION")) - strncpy (as->comment, ct, FFMIN(sizeof (as->comment), vl)); - else if (!strcmp (tt, "GENRE")) - strncpy (as->genre, ct, FFMIN(sizeof (as->genre), vl)); - else if (!strcmp (tt, "TRACKNUMBER")) - as->track = atoi (ct); - //Too bored to add others for today + if (!strcmp(tt, "AUTHOR") || !strcmp(tt, "ARTIST")) + av_strlcpy(as->author, ct, sizeof(as->author)); + else if (!strcmp(tt, "TITLE")) + av_strlcpy(as->title, ct, sizeof(as->title)); + else if (!strcmp(tt, "COPYRIGHT")) + av_strlcpy(as->copyright, ct, sizeof(as->copyright)); + else if (!strcmp(tt, "DESCRIPTION")) + av_strlcpy(as->comment, ct, sizeof(as->comment)); + else if (!strcmp(tt, "GENRE")) + av_strlcpy(as->genre, ct, sizeof(as->genre)); + else if (!strcmp(tt, "TRACKNUMBER")) + as->track = atoi(ct); + else if (!strcmp(tt, "ALBUM")) + av_strlcpy(as->album, ct, sizeof(as->album)); } } - if (size > 0) - av_log (as, AV_LOG_INFO, "%i bytes of comment header remain\n", size); + if (p != end) + av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", p-end); if (n > 0) - av_log (as, AV_LOG_INFO, - "truncated comment header, %i comments not found\n", n); + av_log(as, AV_LOG_INFO, + "truncated comment header, %i comments not found\n", n); return 0; } @@ -134,7 +130,7 @@ typedef struct { static unsigned int fixup_vorbis_headers(AVFormatContext * as, oggvorbis_private_t *priv, - void **buf) + uint8_t **buf) { int i,offset, len; unsigned char *ptr; @@ -146,7 +142,7 @@ fixup_vorbis_headers(AVFormatContext * as, oggvorbis_private_t *priv, offset = 1; offset += av_xiphlacing(&ptr[offset], priv->len[0]); offset += av_xiphlacing(&ptr[offset], priv->len[1]); - for(i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) { memcpy(&ptr[offset], priv->packet[i], priv->len[i]); offset += priv->len[i]; } @@ -166,22 +162,46 @@ vorbis_header (AVFormatContext * s, int idx) if (os->seq > 2) return 0; - if(os->seq == 0) { + if (os->seq == 0) { os->private = av_mallocz(sizeof(oggvorbis_private_t)); - if(!os->private) + if (!os->private) return 0; } + if (os->psize < 1) + return -1; + priv = os->private; priv->len[os->seq] = os->psize; priv->packet[os->seq] = av_mallocz(os->psize); memcpy(priv->packet[os->seq], os->buf + os->pstart, os->psize); if (os->buf[os->pstart] == 1) { - uint8_t *p = os->buf + os->pstart + 11; //skip up to the audio channels - st->codec->channels = *p++; - st->codec->sample_rate = le2me_32 (unaligned32 (p)); - p += 8; //skip maximum and and nominal bitrate - st->codec->bit_rate = le2me_32 (unaligned32 (p)); //Minimum bitrate + const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */ + unsigned blocksize, bs0, bs1; + + if (os->psize != 30) + return -1; + + if (bytestream_get_le32(&p) != 0) /* vorbis_version */ + return -1; + + st->codec->channels = bytestream_get_byte(&p); + st->codec->sample_rate = bytestream_get_le32(&p); + p += 4; // skip maximum bitrate + st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate + p += 4; // skip minimum bitrate + + blocksize = bytestream_get_byte(&p); + bs0 = blocksize & 15; + bs1 = blocksize >> 4; + + if (bs0 > bs1) + return -1; + if (bs0 < 6 || bs1 > 13) + return -1; + + if (bytestream_get_byte(&p) != 1) /* framing_flag */ + return -1; st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_VORBIS; @@ -189,7 +209,8 @@ vorbis_header (AVFormatContext * s, int idx) st->time_base.num = 1; st->time_base.den = st->codec->sample_rate; } else if (os->buf[os->pstart] == 3) { - vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8); + if (os->psize > 8) + vorbis_comment (s, os->buf + os->pstart + 7, os->psize - 8); } else { st->codec->extradata_size = fixup_vorbis_headers(s, priv, &st->codec->extradata); diff --git a/contrib/ffmpeg/libavformat/os_support.c b/contrib/ffmpeg/libavformat/os_support.c index 7a4be8fa7..cc109d596 100644 --- a/contrib/ffmpeg/libavformat/os_support.c +++ b/contrib/ffmpeg/libavformat/os_support.c @@ -21,90 +21,69 @@ */ #include "config.h" #include "avformat.h" -#if defined(CONFIG_WINCE) -/* Skip includes on WinCE. */ -#elif defined(__MINGW32__) -#include <sys/types.h> -#include <sys/timeb.h> -#elif defined(CONFIG_OS2) -#include <string.h> -#include <sys/time.h> -#else #include <unistd.h> #include <fcntl.h> -#include <sys/time.h> -#endif -#include <time.h> +#include "os_support.h" -#ifndef HAVE_SYS_POLL_H -#if defined(__MINGW32__) +#ifdef CONFIG_NETWORK +#ifndef HAVE_POLL_H +#ifdef HAVE_WINSOCK2_H #include <winsock2.h> -#else +#elif defined (HAVE_SYS_SELECT_H) #include <sys/select.h> #endif #endif -/** - * gets the current time in micro seconds. - */ -int64_t av_gettime(void) -{ -#if defined(CONFIG_WINCE) - return timeGetTime() * INT64_C(1000); -#elif defined(__MINGW32__) - struct timeb tb; - _ftime(&tb); - return ((int64_t)tb.time * INT64_C(1000) + (int64_t)tb.millitm) * INT64_C(1000); -#else - struct timeval tv; - gettimeofday(&tv,NULL); - return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; -#endif -} - -#if !defined(CONFIG_WINCE) && !defined(HAVE_LOCALTIME_R) -struct tm *localtime_r(const time_t *t, struct tm *tp) -{ - struct tm *l; - - l = localtime(t); - if (!l) - return 0; - *tp = *l; - return tp; -} -#endif /* !defined(CONFIG_WINCE) && !defined(HAVE_LOCALTIME_R) */ +#include "network.h" -#if !defined(HAVE_INET_ATON) && defined(CONFIG_NETWORK) +#if !defined(HAVE_INET_ATON) #include <stdlib.h> #include <strings.h> -#include "network.h" int inet_aton (const char * str, struct in_addr * add) { - const char * pch = str; unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0; - add1 = atoi(pch); - pch = strpbrk(pch,"."); - if (pch == 0 || ++pch == 0) goto done; - add2 = atoi(pch); - pch = strpbrk(pch,"."); - if (pch == 0 || ++pch == 0) goto done; - add3 = atoi(pch); - pch = strpbrk(pch,"."); - if (pch == 0 || ++pch == 0) goto done; - add4 = atoi(pch); - -done: + if (sscanf(str, "%d.%d.%d.%d", &add1, &add2, &add3, &add4) != 4) + return 0; + + if (!add1 || (add1|add2|add3|add4) > 255) return 0; + add->s_addr=(add4<<24)+(add3<<16)+(add2<<8)+add1; return 1; } -#endif /* !defined(HAVE_INET_ATON) && defined(CONFIG_NETWORK) */ +#endif /* !defined(HAVE_INET_ATON) */ + +/* resolve host with also IP address parsing */ +int resolve_host(struct in_addr *sin_addr, const char *hostname) +{ + struct hostent *hp; + + if (!inet_aton(hostname, sin_addr)) { + hp = gethostbyname(hostname); + if (!hp) + return -1; + memcpy(sin_addr, hp->h_addr, sizeof(struct in_addr)); + } + return 0; +} + +int ff_socket_nonblock(int socket, int enable) +{ +#ifdef HAVE_WINSOCK2_H + return ioctlsocket(socket, FIONBIO, &enable); +#else + if (enable) + return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); + else + return fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); +#endif +} +#endif /* CONFIG_NETWORK */ #ifdef CONFIG_FFSERVER -#ifndef HAVE_SYS_POLL_H +#ifndef HAVE_POLL_H int poll(struct pollfd *fds, nfds_t numfds, int timeout) { fd_set read_set; @@ -114,6 +93,13 @@ int poll(struct pollfd *fds, nfds_t numfds, int timeout) int n; int rc; +#ifdef HAVE_WINSOCK2_H + if (numfds >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } +#endif + FD_ZERO(&read_set); FD_ZERO(&write_set); FD_ZERO(&exception_set); @@ -122,10 +108,12 @@ int poll(struct pollfd *fds, nfds_t numfds, int timeout) for(i = 0; i < numfds; i++) { if (fds[i].fd < 0) continue; +#ifndef HAVE_WINSOCK2_H if (fds[i].fd >= FD_SETSIZE) { errno = EINVAL; return -1; } +#endif if (fds[i].events & POLLIN) FD_SET(fds[i].fd, &read_set); if (fds[i].events & POLLOUT) FD_SET(fds[i].fd, &write_set); @@ -162,6 +150,6 @@ int poll(struct pollfd *fds, nfds_t numfds, int timeout) return rc; } -#endif /* HAVE_SYS_POLL_H */ +#endif /* HAVE_POLL_H */ #endif /* CONFIG_FFSERVER */ diff --git a/contrib/ffmpeg/libavformat/os_support.h b/contrib/ffmpeg/libavformat/os_support.h index 424d6dabd..67d586ab6 100644 --- a/contrib/ffmpeg/libavformat/os_support.h +++ b/contrib/ffmpeg/libavformat/os_support.h @@ -19,23 +19,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _OS_SUPPORT_H -#define _OS_SUPPORT_H +#ifndef FFMPEG_OS_SUPPORT_H +#define FFMPEG_OS_SUPPORT_H /** * @file os_support.h * miscellaneous OS support macros and functions. - * - * - socklen_t typedef (BeOS, Innotek libc) - * - usleep() (Win32, BeOS, OS/2) - * - lseek() (Win32) - * - floatf() (OS/2) - * - strcasecmp() (OS/2) - * - closesocket() - * - poll() (BeOS, MinGW) */ -#if defined(__BEOS__) || defined(__INNOTEK_LIBC__) +#ifndef HAVE_SOCKLEN_T typedef int socklen_t; #endif @@ -45,16 +37,12 @@ __declspec(dllimport) void __stdcall Sleep(unsigned long dwMilliseconds); # define usleep(t) Sleep((t) / 1000) # include <fcntl.h> # define lseek(f,p,w) _lseeki64((f), (p), (w)) -# define HAVE_CLOSESOCKET 1 #endif #ifdef __BEOS__ # include <sys/socket.h> # include <netinet/in.h> /* not net_server ? */ -# if IPPROTO_TCP != 6 -# define HAVE_CLOSESOCKET 1 -# endif # include <BeBuild.h> /* R5 didn't have usleep, fake it. Haiku and Zeta has it now. */ # if B_BEOS_VERSION <= B_BEOS_VERSION_5 @@ -68,19 +56,13 @@ __declspec(dllimport) void __stdcall Sleep(unsigned long dwMilliseconds); # endif #endif -#if defined(CONFIG_OS2) -#include <stdlib.h> -static inline int usleep(unsigned int t) { return _sleep2(t / 1000); } -static inline int strcasecmp(const char* s1, const char* s2) { return stricmp(s1,s2); } -#endif - /* most of the time closing a socket is just closing an fd */ -#if HAVE_CLOSESOCKET != 1 +#ifndef HAVE_CLOSESOCKET #define closesocket close #endif #ifdef CONFIG_FFSERVER -#ifndef HAVE_SYS_POLL_H +#ifndef HAVE_POLL_H typedef unsigned long nfds_t; struct pollfd { @@ -105,7 +87,7 @@ struct pollfd { extern int poll(struct pollfd *fds, nfds_t numfds, int timeout); -#endif /* HAVE_SYS_POLL_H */ +#endif /* HAVE_POLL_H */ #endif /* CONFIG_FFSERVER */ -#endif /* _OS_SUPPORT_H */ +#endif /* FFMPEG_OS_SUPPORT_H */ diff --git a/contrib/ffmpeg/libavformat/psxstr.c b/contrib/ffmpeg/libavformat/psxstr.c index 2f1a3dc73..3d4cac7f8 100644 --- a/contrib/ffmpeg/libavformat/psxstr.c +++ b/contrib/ffmpeg/libavformat/psxstr.c @@ -125,8 +125,8 @@ static void dump(unsigned char *buf,size_t len) static int str_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; - StrDemuxContext *str = (StrDemuxContext *)s->priv_data; + ByteIOContext *pb = s->pb; + StrDemuxContext *str = s->priv_data; AVStream *st; unsigned char sector[RAW_CD_SECTOR_SIZE]; int start; @@ -142,7 +142,7 @@ static int str_read_header(AVFormatContext *s, /* skip over any RIFF header */ if (get_buffer(pb, sector, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE) - return AVERROR_IO; + return AVERROR(EIO); if (AV_RL32(§or[0]) == RIFF_TAG) start = RIFF_HEADER_SIZE; else @@ -153,7 +153,7 @@ static int str_read_header(AVFormatContext *s, /* check through the first 32 sectors for individual channels */ for (i = 0; i < 32; i++) { if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE) - return AVERROR_IO; + return AVERROR(EIO); //printf("%02x %02x %02x %02x\n",sector[0x10],sector[0x11],sector[0x12],sector[0x13]); @@ -178,7 +178,7 @@ static int str_read_header(AVFormatContext *s, /* allocate a new AVStream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 64, 1, 15); str->channels[channel].video_stream_index = st->index; @@ -207,7 +207,7 @@ static int str_read_header(AVFormatContext *s, /* allocate a new AVStream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 64, 128, str->channels[channel].sample_rate); str->channels[channel].audio_stream_index = st->index; @@ -249,8 +249,8 @@ if (str->audio_channel != -1) static int str_read_packet(AVFormatContext *s, AVPacket *ret_pkt) { - ByteIOContext *pb = &s->pb; - StrDemuxContext *str = (StrDemuxContext *)s->priv_data; + ByteIOContext *pb = s->pb; + StrDemuxContext *str = s->priv_data; unsigned char sector[RAW_CD_SECTOR_SIZE]; int channel; int packet_read = 0; @@ -260,7 +260,7 @@ static int str_read_packet(AVFormatContext *s, while (!packet_read) { if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE) - return AVERROR_IO; + return AVERROR(EIO); channel = sector[0x11]; if (channel >= 32) @@ -282,7 +282,7 @@ static int str_read_packet(AVFormatContext *s, pkt = &str->tmp_pkt; if (current_sector == 0) { if (av_new_packet(pkt, frame_size)) - return AVERROR_IO; + return AVERROR(EIO); pkt->pos= url_ftell(pb) - RAW_CD_SECTOR_SIZE; pkt->stream_index = @@ -319,7 +319,7 @@ printf (" dropping audio sector\n"); if (channel == str->audio_channel) { pkt = ret_pkt; if (av_new_packet(pkt, 2304)) - return AVERROR_IO; + return AVERROR(EIO); memcpy(pkt->data,sector+24,2304); pkt->stream_index = @@ -338,7 +338,7 @@ printf (" dropping other sector\n"); } if (url_feof(pb)) - return AVERROR_IO; + return AVERROR(EIO); } return ret; @@ -346,7 +346,7 @@ printf (" dropping other sector\n"); static int str_read_close(AVFormatContext *s) { - StrDemuxContext *str = (StrDemuxContext *)s->priv_data; + StrDemuxContext *str = s->priv_data; av_free(str->video_chunk); diff --git a/contrib/ffmpeg/libavformat/pva.c b/contrib/ffmpeg/libavformat/pva.c new file mode 100644 index 000000000..03b92bf3d --- /dev/null +++ b/contrib/ffmpeg/libavformat/pva.c @@ -0,0 +1,211 @@ +/* + * TechnoTrend PVA (.pva) demuxer + * Copyright (c) 2007, 2008 Ivo van Poorten + * + * 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 "mpeg.h" + +#define PVA_MAX_PAYLOAD_LENGTH 0x17f8 +#define PVA_VIDEO_PAYLOAD 0x01 +#define PVA_AUDIO_PAYLOAD 0x02 +#define PVA_MAGIC (('A' << 8) + 'V') + +typedef struct { + int continue_pes; +} PVAContext; + +static int pva_probe(AVProbeData * pd) { + unsigned char *buf = pd->buf; + + if (AV_RB16(buf) == PVA_MAGIC && buf[2] && buf[2] < 3 && buf[4] == 0x55) + return AVPROBE_SCORE_MAX / 2; + + return 0; +} + +static int pva_read_header(AVFormatContext *s, AVFormatParameters *ap) { + AVStream *st; + + if (!(st = av_new_stream(s, 0))) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_MPEG2VIDEO; + st->need_parsing = AVSTREAM_PARSE_FULL; + av_set_pts_info(st, 32, 1, 90000); + av_add_index_entry(st, 0, 0, 0, 0, AVINDEX_KEYFRAME); + + if (!(st = av_new_stream(s, 1))) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_MP2; + st->need_parsing = AVSTREAM_PARSE_HEADERS; + av_set_pts_info(st, 33, 1, 90000); + av_add_index_entry(st, 0, 0, 0, 0, AVINDEX_KEYFRAME); + + /* the parameters will be extracted from the compressed bitstream */ + return 0; +} + +#define pva_log if (read_packet) av_log + +static int read_part_of_packet(AVFormatContext *s, int64_t *pts, + int *len, int *strid, int read_packet) { + ByteIOContext *pb = s->pb; + PVAContext *pvactx = s->priv_data; + int syncword, streamid, reserved, flags, length, pts_flag; + int64_t pva_pts = AV_NOPTS_VALUE, startpos; + +recover: + startpos = url_ftell(pb); + + syncword = get_be16(pb); + streamid = get_byte(pb); + get_byte(pb); /* counter not used */ + reserved = get_byte(pb); + flags = get_byte(pb); + length = get_be16(pb); + + pts_flag = flags & 0x10; + + if (syncword != PVA_MAGIC) { + pva_log(s, AV_LOG_ERROR, "invalid syncword\n"); + return AVERROR(EIO); + } + if (streamid != PVA_VIDEO_PAYLOAD && streamid != PVA_AUDIO_PAYLOAD) { + pva_log(s, AV_LOG_ERROR, "invalid streamid\n"); + return AVERROR(EIO); + } + if (reserved != 0x55) { + pva_log(s, AV_LOG_WARNING, "expected reserved byte to be 0x55\n"); + } + if (length > PVA_MAX_PAYLOAD_LENGTH) { + pva_log(s, AV_LOG_ERROR, "invalid payload length %u\n", length); + return AVERROR(EIO); + } + + if (streamid == PVA_VIDEO_PAYLOAD && pts_flag) { + pva_pts = get_be32(pb); + length -= 4; + } else if (streamid == PVA_AUDIO_PAYLOAD) { + /* PVA Audio Packets either start with a signaled PES packet or + * are a continuation of the previous PES packet. New PES packets + * always start at the beginning of a PVA Packet, never somewhere in + * the middle. */ + if (!pvactx->continue_pes) { + int pes_signal, pes_header_data_length, pes_packet_length, + pes_flags; + unsigned char pes_header_data[256]; + + pes_signal = get_be24(pb); + get_byte(pb); + pes_packet_length = get_be16(pb); + pes_flags = get_be16(pb); + pes_header_data_length = get_byte(pb); + + if (pes_signal != 1) { + pva_log(s, AV_LOG_WARNING, "expected signaled PES packet, " + "trying to recover\n"); + url_fskip(pb, length - 9); + if (!read_packet) + return AVERROR(EIO); + goto recover; + } + + get_buffer(pb, pes_header_data, pes_header_data_length); + length -= 9 + pes_header_data_length; + + pes_packet_length -= 3 + pes_header_data_length; + + pvactx->continue_pes = pes_packet_length; + + if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20) + pva_pts = ff_parse_pes_pts(pes_header_data); + } + + pvactx->continue_pes -= length; + + if (pvactx->continue_pes < 0) { + pva_log(s, AV_LOG_WARNING, "audio data corruption\n"); + pvactx->continue_pes = 0; + } + } + + if (pva_pts != AV_NOPTS_VALUE) + av_add_index_entry(s->streams[streamid-1], startpos, pva_pts, 0, 0, AVINDEX_KEYFRAME); + + *pts = pva_pts; + *len = length; + *strid = streamid; + return 0; +} + +static int pva_read_packet(AVFormatContext *s, AVPacket *pkt) { + ByteIOContext *pb = s->pb; + int64_t pva_pts; + int ret, length, streamid; + + if (read_part_of_packet(s, &pva_pts, &length, &streamid, 1) < 0 || + (ret = av_get_packet(pb, pkt, length)) <= 0) + return AVERROR(EIO); + + pkt->stream_index = streamid - 1; + pkt->pts = pva_pts; + + return ret; +} + +static int64_t pva_read_timestamp(struct AVFormatContext *s, int stream_index, + int64_t *pos, int64_t pos_limit) { + ByteIOContext *pb = s->pb; + PVAContext *pvactx = s->priv_data; + int length, streamid; + int64_t res; + + pos_limit = FFMIN(*pos+PVA_MAX_PAYLOAD_LENGTH*8, (uint64_t)*pos+pos_limit); + + while (*pos < pos_limit) { + res = AV_NOPTS_VALUE; + url_fseek(pb, *pos, SEEK_SET); + + pvactx->continue_pes = 0; + if (read_part_of_packet(s, &res, &length, &streamid, 0)) { + (*pos)++; + continue; + } + if (streamid - 1 != stream_index || res == AV_NOPTS_VALUE) { + *pos = url_ftell(pb) + length; + continue; + } + break; + } + + pvactx->continue_pes = 0; + return res; +} + +AVInputFormat pva_demuxer = { + "pva", + "pva file and stream format", + sizeof(PVAContext), + pva_probe, + pva_read_header, + pva_read_packet, + .read_timestamp = pva_read_timestamp +}; diff --git a/contrib/ffmpeg/libavformat/qtpalette.h b/contrib/ffmpeg/libavformat/qtpalette.h index 183600fde..0c6c44f47 100644 --- a/contrib/ffmpeg/libavformat/qtpalette.h +++ b/contrib/ffmpeg/libavformat/qtpalette.h @@ -20,17 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef QTPALETTE_H -#define QTPALETTE_H +#ifndef FFMPEG_QTPALETTE_H +#define FFMPEG_QTPALETTE_H -unsigned char ff_qt_default_palette_4[4 * 4] = { +#include <inttypes.h> + +static const uint8_t ff_qt_default_palette_4[4 * 4] = { 0x93, 0x65, 0x5E, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xDF, 0xD0, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00 }; -unsigned char ff_qt_default_palette_16[16 * 4] = { +static const uint8_t ff_qt_default_palette_16[16 * 4] = { 0xFF, 0xFB, 0xFF, 0x00, 0xEF, 0xD9, 0xBB, 0x00, 0xE8, 0xC9, 0xB1, 0x00, @@ -49,7 +51,7 @@ unsigned char ff_qt_default_palette_16[16 * 4] = { 0x00, 0x00, 0x00, 0x00 }; -unsigned char ff_qt_default_palette_256[256 * 4] = { +static const uint8_t ff_qt_default_palette_256[256 * 4] = { /* 0, 0x00 */ 0xFF, 0xFF, 0xFF, 0x00, /* 1, 0x01 */ 0xFF, 0xFF, 0xCC, 0x00, /* 2, 0x02 */ 0xFF, 0xFF, 0x99, 0x00, @@ -308,4 +310,4 @@ unsigned char ff_qt_default_palette_256[256 * 4] = { /* 255, 0xFF */ 0x00, 0x00, 0x00, 0x00 }; -#endif +#endif /* FFMPEG_QTPALETTE_H */ diff --git a/contrib/ffmpeg/libavformat/raw.c b/contrib/ffmpeg/libavformat/raw.c index 73a20379a..d4b138953 100644 --- a/contrib/ffmpeg/libavformat/raw.c +++ b/contrib/ffmpeg/libavformat/raw.c @@ -20,15 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "ac3.h" +#include "ac3_parser.h" +#include "raw.h" #ifdef CONFIG_MUXERS /* simple formats */ -static int raw_write_header(struct AVFormatContext *s) -{ - return 0; -} - static int flac_write_header(struct AVFormatContext *s) { static const uint8_t header[8] = { @@ -37,21 +33,29 @@ static int flac_write_header(struct AVFormatContext *s) uint8_t *streaminfo = s->streams[0]->codec->extradata; int len = s->streams[0]->codec->extradata_size; if(streaminfo != NULL && len > 0) { - put_buffer(&s->pb, header, 8); - put_buffer(&s->pb, streaminfo, len); + put_buffer(s->pb, header, 8); + put_buffer(s->pb, streaminfo, len); } return 0; } -static int raw_write_packet(struct AVFormatContext *s, AVPacket *pkt) + +static int roq_write_header(struct AVFormatContext *s) { - put_buffer(&s->pb, pkt->data, pkt->size); - put_flush_packet(&s->pb); + static const uint8_t header[] = { + 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x00 + }; + + put_buffer(s->pb, header, 8); + put_flush_packet(s->pb); + return 0; } -static int raw_write_trailer(struct AVFormatContext *s) +static int raw_write_packet(struct AVFormatContext *s, AVPacket *pkt) { + put_buffer(s->pb, pkt->data, pkt->size); + put_flush_packet(s->pb); return 0; } #endif //CONFIG_MUXERS @@ -64,7 +68,7 @@ static int raw_read_header(AVFormatContext *s, AVFormatParameters *ap) st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); id = s->iformat->value; if (id == CODEC_ID_RAWVIDEO) { @@ -81,7 +85,10 @@ static int raw_read_header(AVFormatContext *s, AVFormatParameters *ap) av_set_pts_info(st, 64, 1, st->codec->sample_rate); break; case CODEC_TYPE_VIDEO: - av_set_pts_info(st, 64, ap->time_base.num, ap->time_base.den); + if(ap->time_base.num) + av_set_pts_info(st, 64, ap->time_base.num, ap->time_base.den); + else + av_set_pts_info(st, 64, 1, 25); st->codec->width = ap->width; st->codec->height = ap->height; st->codec->pix_fmt = ap->pix_fmt; @@ -98,20 +105,26 @@ static int raw_read_header(AVFormatContext *s, AVFormatParameters *ap) static int raw_read_packet(AVFormatContext *s, AVPacket *pkt) { - int ret, size; + int ret, size, bps; // AVStream *st = s->streams[0]; size= RAW_PACKET_SIZE; - ret= av_get_packet(&s->pb, pkt, size); + ret= av_get_packet(s->pb, pkt, size); pkt->stream_index = 0; if (ret <= 0) { - return AVERROR_IO; + return AVERROR(EIO); } /* note: we need to modify the packet size here to handle the last packet */ pkt->size = ret; + + bps= av_get_bits_per_sample(s->streams[0]->codec->codec_id); + assert(bps); // if false there IS a bug elsewhere (NOT in this function) + pkt->dts= + pkt->pts= pkt->pos*8 / (bps * s->streams[0]->codec->channels); + return ret; } @@ -122,14 +135,14 @@ static int raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt) size = RAW_PACKET_SIZE; if (av_new_packet(pkt, size) < 0) - return AVERROR_IO; + return AVERROR(EIO); - pkt->pos= url_ftell(&s->pb); + pkt->pos= url_ftell(s->pb); pkt->stream_index = 0; - ret = get_partial_buffer(&s->pb, pkt->data, size); + ret = get_partial_buffer(s->pb, pkt->data, size); if (ret <= 0) { av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } pkt->size = ret; return ret; @@ -140,32 +153,32 @@ static int ingenient_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, size, w, h, unk1, unk2; - if (get_le32(&s->pb) != MKTAG('M', 'J', 'P', 'G')) - return AVERROR_IO; // FIXME + if (get_le32(s->pb) != MKTAG('M', 'J', 'P', 'G')) + return AVERROR(EIO); // FIXME - size = get_le32(&s->pb); + size = get_le32(s->pb); - w = get_le16(&s->pb); - h = get_le16(&s->pb); + w = get_le16(s->pb); + h = get_le16(s->pb); - url_fskip(&s->pb, 8); // zero + size (padded?) - url_fskip(&s->pb, 2); - unk1 = get_le16(&s->pb); - unk2 = get_le16(&s->pb); - url_fskip(&s->pb, 22); // ascii timestamp + url_fskip(s->pb, 8); // zero + size (padded?) + url_fskip(s->pb, 2); + unk1 = get_le16(s->pb); + unk2 = get_le16(s->pb); + url_fskip(s->pb, 22); // ascii timestamp av_log(NULL, AV_LOG_DEBUG, "Ingenient packet: size=%d, width=%d, height=%d, unk1=%d unk2=%d\n", size, w, h, unk1, unk2); if (av_new_packet(pkt, size) < 0) - return AVERROR_IO; + return AVERROR(EIO); - pkt->pos = url_ftell(&s->pb); + pkt->pos = url_ftell(s->pb); pkt->stream_index = 0; - ret = get_buffer(&s->pb, pkt->data, size); + ret = get_buffer(s->pb, pkt->data, size); if (ret <= 0) { av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } pkt->size = ret; return ret; @@ -202,7 +215,7 @@ int pcm_read_seek(AVFormatContext *s, /* recompute exact position */ st->cur_dts = av_rescale(pos, st->time_base.den, byte_rate * (int64_t)st->time_base.num); - url_fseek(&s->pb, pos + s->data_offset, SEEK_SET); + url_fseek(s->pb, pos + s->data_offset, SEEK_SET); return 0; } @@ -214,11 +227,11 @@ static int ac3_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_AC3; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -230,10 +243,10 @@ static int shorten_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_SHORTEN; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -246,10 +259,10 @@ static int flac_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_FLAC; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -262,11 +275,11 @@ static int dts_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_DTS; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -279,11 +292,11 @@ static int aac_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_AAC; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* the parameters will be extracted from the compressed bitstream */ return 0; } @@ -296,14 +309,14 @@ static int video_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = s->iformat->value; - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; /* for mjpeg, specify frame rate */ - /* for mpeg4 specify it too (most mpeg4 streams dont have the fixed_vop_rate set ...)*/ + /* for mpeg4 specify it too (most mpeg4 streams do not have the fixed_vop_rate set ...)*/ if (ap->time_base.num) { av_set_pts_info(st, 64, ap->time_base.num, ap->time_base.den); } else if ( st->codec->codec_id == CODEC_ID_MJPEG || @@ -347,32 +360,29 @@ static int mpegvideo_probe(AVProbeData *p) return 0; } -#define VIDEO_OBJECT_START_CODE 0x00000100 -#define VIDEO_OBJECT_LAYER_START_CODE 0x00000120 #define VISUAL_OBJECT_START_CODE 0x000001b5 #define VOP_START_CODE 0x000001b6 static int mpeg4video_probe(AVProbeData *probe_packet) { uint32_t temp_buffer= -1; - int VO=0, VOL=0, VOP = 0, VISO = 0; + int VO=0, VOL=0, VOP = 0, VISO = 0, res=0; int i; for(i=0; i<probe_packet->buf_size; i++){ temp_buffer = (temp_buffer<<8) + probe_packet->buf[i]; - if ((temp_buffer & 0xffffff00) == 0x100) { - switch(temp_buffer){ - case VOP_START_CODE: VOP++; break; - case VISUAL_OBJECT_START_CODE: VISO++; break; - } - switch(temp_buffer & 0xfffffff0){ - case VIDEO_OBJECT_START_CODE: VO++; break; - case VIDEO_OBJECT_LAYER_START_CODE: VOL++; break; - } - } + if ((temp_buffer & 0xffffff00) != 0x100) + continue; + + if (temp_buffer == VOP_START_CODE) VOP++; + else if (temp_buffer == VISUAL_OBJECT_START_CODE) VISO++; + else if (temp_buffer < 0x120) VO++; + else if (temp_buffer < 0x130) VOL++; + else if ( !(0x1AF < temp_buffer && temp_buffer < 0x1B7) + && !(0x1B9 < temp_buffer && temp_buffer < 0x1C4)) res++; } - if ( VOP >= VISO && VOP >= VOL && VO >= VOL && VOL > 0) + if ( VOP >= VISO && VOP >= VOL && VO >= VOL && VOL > 0 && res==0) return AVPROBE_SCORE_MAX/2; return 0; } @@ -382,8 +392,6 @@ static int h263_probe(AVProbeData *p) int code; const uint8_t *d; - if (p->buf_size < 6) - return 0; d = p->buf; code = (d[0] << 14) | (d[1] << 6) | (d[2] >> 2); if (code == 0x20) { @@ -397,8 +405,6 @@ static int h261_probe(AVProbeData *p) int code; const uint8_t *d; - if (p->buf_size < 6) - return 0; d = p->buf; code = (d[0] << 12) | (d[1] << 4) | (d[2] >> 4); if (code == 0x10) { @@ -409,16 +415,13 @@ static int h261_probe(AVProbeData *p) static int ac3_probe(AVProbeData *p) { - int max_frames, first_frames, frames; + int max_frames, first_frames = 0, frames; uint8_t *buf, *buf2, *end; AC3HeaderInfo hdr; - if(p->buf_size < 7) - return 0; - max_frames = 0; buf = p->buf; - end = buf + FFMIN(4096, p->buf_size - 7); + end = buf + p->buf_size; for(; buf < end; buf++) { buf2 = buf; @@ -438,6 +441,12 @@ static int ac3_probe(AVProbeData *p) else return 0; } +static int flac_probe(AVProbeData *p) +{ + if(memcmp(p->buf, "fLaC", 4)) return 0; + else return AVPROBE_SCORE_MAX / 2; +} + AVInputFormat shorten_demuxer = { "shn", "raw shorten", @@ -454,7 +463,7 @@ AVInputFormat flac_demuxer = { "flac", "raw flac", 0, - NULL, + flac_probe, flac_read_header, raw_read_partial_packet, raw_read_close, @@ -473,11 +482,11 @@ AVOutputFormat flac_muxer = { 0, flac_write_header, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS +#ifdef CONFIG_AC3_DEMUXER AVInputFormat ac3_demuxer = { "ac3", "raw ac3", @@ -489,6 +498,7 @@ AVInputFormat ac3_demuxer = { .flags= AVFMT_GENERIC_INDEX, .extensions = "ac3", }; +#endif #ifdef CONFIG_MUXERS AVOutputFormat ac3_muxer = { @@ -499,9 +509,8 @@ AVOutputFormat ac3_muxer = { 0, CODEC_ID_AC3, 0, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -530,6 +539,21 @@ AVInputFormat aac_demuxer = { .extensions = "aac", }; +#ifdef CONFIG_ROQ_MUXER +AVOutputFormat roq_muxer = +{ + "RoQ", + "Id RoQ format", + NULL, + "roq", + 0, + CODEC_ID_ROQ_DPCM, + CODEC_ID_ROQ, + roq_write_header, + raw_write_packet, +}; +#endif //CONFIG_ROQ_MUXER + AVInputFormat h261_demuxer = { "h261", "raw h261", @@ -552,9 +576,8 @@ AVOutputFormat h261_muxer = { 0, 0, CODEC_ID_H261, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -581,9 +604,8 @@ AVOutputFormat h263_muxer = { 0, 0, CODEC_ID_H263, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -610,9 +632,8 @@ AVOutputFormat m4v_muxer = { 0, CODEC_ID_NONE, CODEC_ID_MPEG4, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -639,9 +660,8 @@ AVOutputFormat h264_muxer = { 0, CODEC_ID_NONE, CODEC_ID_H264, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -667,9 +687,8 @@ AVOutputFormat mpeg1video_muxer = { 0, 0, CODEC_ID_MPEG1VIDEO, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -683,9 +702,8 @@ AVOutputFormat mpeg2video_muxer = { 0, 0, CODEC_ID_MPEG2VIDEO, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -725,9 +743,8 @@ AVOutputFormat mjpeg_muxer = { 0, 0, CODEC_ID_MJPEG, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -770,9 +787,8 @@ AVOutputFormat pcm_ ## name ## _muxer = {\ 0,\ codec,\ 0,\ - raw_write_header,\ + NULL,\ raw_write_packet,\ - raw_write_trailer,\ .flags= AVFMT_NOTIMESTAMPS,\ }; @@ -836,11 +852,13 @@ static int rawvideo_read_packet(AVFormatContext *s, AVPacket *pkt) if (packet_size < 0) return -1; - ret= av_get_packet(&s->pb, pkt, packet_size); + ret= av_get_packet(s->pb, pkt, packet_size); + pkt->pts= + pkt->dts= pkt->pos / packet_size; pkt->stream_index = 0; if (ret != packet_size) { - return AVERROR_IO; + return AVERROR(EIO); } else { return 0; } @@ -855,7 +873,7 @@ AVInputFormat rawvideo_demuxer = { rawvideo_read_packet, raw_read_close, .flags= AVFMT_GENERIC_INDEX, - .extensions = "yuv,cif,qcif", + .extensions = "yuv,cif,qcif,rgb", .value = CODEC_ID_RAWVIDEO, }; @@ -864,13 +882,12 @@ AVOutputFormat rawvideo_muxer = { "rawvideo", "raw video format", NULL, - "yuv", + "yuv,rgb", 0, CODEC_ID_NONE, CODEC_ID_RAWVIDEO, - raw_write_header, + NULL, raw_write_packet, - raw_write_trailer, .flags= AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS @@ -893,9 +910,8 @@ AVOutputFormat null_muxer = { CODEC_ID_PCM_S16LE, #endif CODEC_ID_RAWVIDEO, - raw_write_header, + NULL, null_write_packet, - raw_write_trailer, .flags = AVFMT_NOFILE | AVFMT_RAWPICTURE | AVFMT_NOTIMESTAMPS, }; #endif //CONFIG_MUXERS diff --git a/contrib/ffmpeg/libavformat/raw.h b/contrib/ffmpeg/libavformat/raw.h new file mode 100644 index 000000000..3d851c829 --- /dev/null +++ b/contrib/ffmpeg/libavformat/raw.h @@ -0,0 +1,30 @@ +/* + * RAW muxer and demuxer + * Copyright (C) 2007 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 + */ + +#ifndef FFMPEG_RAW_H +#define FFMPEG_RAW_H + +#include "avformat.h" + +int pcm_read_seek(AVFormatContext *s, + int stream_index, int64_t timestamp, int flags); + +#endif /* FFMPEG_RAW_H */ diff --git a/contrib/ffmpeg/libavformat/riff.c b/contrib/ffmpeg/libavformat/riff.c index 4a5553fa4..64891db3e 100644 --- a/contrib/ffmpeg/libavformat/riff.c +++ b/contrib/ffmpeg/libavformat/riff.c @@ -22,7 +22,6 @@ #include "avformat.h" #include "avcodec.h" #include "riff.h" -#include "allformats.h" // for asf_muxer /* Note: when encoding, the first matching tag is used, so order is important if multiple tags possible for a given codec. */ @@ -88,6 +87,8 @@ const AVCodecTag codec_bmp_tags[] = { { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') }, { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') }, { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') }, + { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', '0') }, + { CODEC_ID_DVVIDEO, MKTAG('c', 'd', 'v', 'c') }, // Canopus DV { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') }, { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') }, { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') }, @@ -97,15 +98,16 @@ const AVCodecTag codec_bmp_tags[] = { { CODEC_ID_MPEG1VIDEO, 0x10000001 }, { CODEC_ID_MPEG2VIDEO, 0x10000002 }, { CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') }, + { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') }, { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') }, { CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') }, { CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') }, { CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */ + { CODEC_ID_JPEGLS,MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */ { CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - decoder */ { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, { CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') }, { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') }, - { CODEC_ID_JPEGLS, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */ { CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') }, { CODEC_ID_FFVHUFF, MKTAG('F', 'F', 'V', 'H') }, { CODEC_ID_CYUV, MKTAG('C', 'Y', 'U', 'V') }, @@ -117,8 +119,11 @@ const AVCodecTag codec_bmp_tags[] = { { CODEC_ID_RAWVIDEO, MKTAG('U', 'Y', 'V', 'Y') }, { CODEC_ID_RAWVIDEO, MKTAG('I', 'Y', 'U', 'V') }, { CODEC_ID_RAWVIDEO, MKTAG('Y', '8', '0', '0') }, + { CODEC_ID_RAWVIDEO, MKTAG('H', 'D', 'Y', 'C') }, { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') }, { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') }, + { CODEC_ID_INDEO4, MKTAG('I', 'V', '4', '1') }, + { CODEC_ID_INDEO5, MKTAG('I', 'V', '5', '0') }, { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') }, { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') }, @@ -175,107 +180,49 @@ const AVCodecTag codec_bmp_tags[] = { }; const AVCodecTag codec_wav_tags[] = { - { CODEC_ID_MP2, 0x50 }, - { CODEC_ID_MP3, 0x55 }, - { CODEC_ID_AC3, 0x2000 }, - { CODEC_ID_DTS, 0x2001 }, - { CODEC_ID_PCM_S16LE, 0x01 }, - { CODEC_ID_PCM_U8, 0x01 }, /* must come after s16le in this list */ - { CODEC_ID_PCM_S24LE, 0x01 }, - { CODEC_ID_PCM_S32LE, 0x01 }, - { CODEC_ID_PCM_ALAW, 0x06 }, - { CODEC_ID_PCM_MULAW, 0x07 }, - { CODEC_ID_ADPCM_MS, 0x02 }, - { CODEC_ID_ADPCM_IMA_WAV, 0x11 }, - { CODEC_ID_ADPCM_YAMAHA, 0x20 }, - { CODEC_ID_ADPCM_G726, 0x45 }, - { CODEC_ID_ADPCM_IMA_DK4, 0x61 }, /* rogue format number */ - { CODEC_ID_ADPCM_IMA_DK3, 0x62 }, /* rogue format number */ - { CODEC_ID_WMAV1, 0x160 }, - { CODEC_ID_WMAV2, 0x161 }, - { CODEC_ID_AAC, 0x706d }, - { CODEC_ID_AAC, 0xff }, - { CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id? - { CODEC_ID_SONIC, 0x2048 }, - { CODEC_ID_SONIC_LS, 0x2048 }, - { CODEC_ID_ADPCM_CT, 0x200 }, - { CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' }, - { CODEC_ID_TRUESPEECH, 0x22 }, - { CODEC_ID_FLAC, 0xF1AC }, - { CODEC_ID_IMC, 0x401 }, - { CODEC_ID_GSM_MS, 0x31 }, + { CODEC_ID_PCM_S16LE, 0x0001 }, + { CODEC_ID_PCM_U8, 0x0001 }, /* must come after s16le in this list */ + { CODEC_ID_PCM_S24LE, 0x0001 }, + { CODEC_ID_PCM_S32LE, 0x0001 }, + { CODEC_ID_ADPCM_MS, 0x0002 }, + { CODEC_ID_PCM_ALAW, 0x0006 }, + { CODEC_ID_PCM_MULAW, 0x0007 }, + { CODEC_ID_WMAVOICE, 0x000A }, + { CODEC_ID_ADPCM_IMA_WAV, 0x0011 }, + { CODEC_ID_ADPCM_YAMAHA, 0x0020 }, + { CODEC_ID_TRUESPEECH, 0x0022 }, + { CODEC_ID_GSM_MS, 0x0031 }, + { CODEC_ID_ADPCM_G726, 0x0045 }, + { CODEC_ID_MP2, 0x0050 }, + { CODEC_ID_MP3, 0x0055 }, + { CODEC_ID_ADPCM_IMA_DK4, 0x0061 }, /* rogue format number */ + { CODEC_ID_ADPCM_IMA_DK3, 0x0062 }, /* rogue format number */ + { CODEC_ID_VOXWARE, 0x0075 }, + { CODEC_ID_AAC, 0x00ff }, + { CODEC_ID_WMAV1, 0x0160 }, + { CODEC_ID_WMAV2, 0x0161 }, + { CODEC_ID_WMAPRO, 0x0162 }, + { CODEC_ID_WMALOSSLESS, 0x0163 }, + { CODEC_ID_ADPCM_CT, 0x0200 }, + { CODEC_ID_ATRAC3, 0x0270 }, + { CODEC_ID_IMC, 0x0401 }, + { CODEC_ID_AC3, 0x2000 }, + { CODEC_ID_DTS, 0x2001 }, + { CODEC_ID_SONIC, 0x2048 }, + { CODEC_ID_SONIC_LS, 0x2048 }, + { CODEC_ID_AAC, 0x706d }, + { CODEC_ID_FLAC, 0xF1AC }, + { CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' }, + { CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id? /* FIXME: All of the IDs below are not 16 bit and thus illegal. */ // for NuppelVideo (nuv.c) { CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') }, - { CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') }, - { CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') }, + { CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') }, + { CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') }, { 0, 0 }, }; -unsigned int codec_get_tag(const AVCodecTag *tags, int id) -{ - while (tags->id != CODEC_ID_NONE) { - if (tags->id == id) - return tags->tag; - tags++; - } - return 0; -} - -enum CodecID codec_get_id(const AVCodecTag *tags, unsigned int tag) -{ - while (tags->id != CODEC_ID_NONE) { - if( toupper((tag >> 0)&0xFF) == toupper((tags->tag >> 0)&0xFF) - && toupper((tag >> 8)&0xFF) == toupper((tags->tag >> 8)&0xFF) - && toupper((tag >>16)&0xFF) == toupper((tags->tag >>16)&0xFF) - && toupper((tag >>24)&0xFF) == toupper((tags->tag >>24)&0xFF)) - return tags->id; - tags++; - } - return CODEC_ID_NONE; -} - -unsigned int av_codec_get_tag(const AVCodecTag *tags[4], enum CodecID id) -{ - int i; - for(i=0; tags && tags[i]; i++){ - int tag= codec_get_tag(tags[i], id); - if(tag) return tag; - } - return 0; -} - -enum CodecID av_codec_get_id(const AVCodecTag *tags[4], unsigned int tag) -{ - int i; - for(i=0; tags && tags[i]; i++){ - enum CodecID id= codec_get_id(tags[i], tag); - if(id!=CODEC_ID_NONE) return id; - } - return CODEC_ID_NONE; -} - -unsigned int codec_get_bmp_tag(int id) -{ - return codec_get_tag(codec_bmp_tags, id); -} - -unsigned int codec_get_wav_tag(int id) -{ - return codec_get_tag(codec_wav_tags, id); -} - -enum CodecID codec_get_bmp_id(unsigned int tag) -{ - return codec_get_id(codec_bmp_tags, tag); -} - -enum CodecID codec_get_wav_id(unsigned int tag) -{ - return codec_get_id(codec_wav_tags, tag); -} - #ifdef CONFIG_MUXERS offset_t start_tag(ByteIOContext *pb, const char *tag) { @@ -327,7 +274,7 @@ int put_wav_header(ByteIOContext *pb, AVCodecContext *enc) } if (enc->codec_id == CODEC_ID_MP2 || enc->codec_id == CODEC_ID_MP3 || enc->codec_id == CODEC_ID_GSM_MS) { - blkalign = enc->frame_size; //this is wrong, but seems many demuxers dont work if this is set correctly + blkalign = enc->frame_size; //this is wrong, but it seems many demuxers do not work if this is set correctly //blkalign = 144 * enc->bit_rate/enc->sample_rate; } else if (enc->codec_id == CODEC_ID_ADPCM_G726) { // blkalign = 1; @@ -475,6 +422,8 @@ int wav_codec_get_id(unsigned int tag, int bps) id = CODEC_ID_PCM_S24LE; if (id == CODEC_ID_PCM_S16LE && bps == 32) id = CODEC_ID_PCM_S32LE; + if (id == CODEC_ID_ADPCM_IMA_WAV && bps == 8) + id = CODEC_ID_PCM_ZORK; return id; } #endif // CONFIG_DEMUXERS diff --git a/contrib/ffmpeg/libavformat/riff.h b/contrib/ffmpeg/libavformat/riff.h index 45c72dde6..dc970f619 100644 --- a/contrib/ffmpeg/libavformat/riff.h +++ b/contrib/ffmpeg/libavformat/riff.h @@ -25,8 +25,11 @@ * do NOT include this in end user applications */ -#ifndef FF_RIFF_H -#define FF_RIFF_H +#ifndef FFMPEG_RIFF_H +#define FFMPEG_RIFF_H + +#include "avcodec.h" +#include "avio.h" offset_t start_tag(ByteIOContext *pb, const char *tag); void end_tag(ByteIOContext *pb, offset_t start); @@ -46,10 +49,6 @@ extern const AVCodecTag codec_wav_tags[]; unsigned int codec_get_tag(const AVCodecTag *tags, int id); enum CodecID codec_get_id(const AVCodecTag *tags, unsigned int tag); -unsigned int codec_get_bmp_tag(int id) attribute_deprecated; //use av_codec_get_tag -unsigned int codec_get_wav_tag(int id) attribute_deprecated; //use av_codec_get_tag -enum CodecID codec_get_bmp_id(unsigned int tag) attribute_deprecated; //use av_codec_get_id -enum CodecID codec_get_wav_id(unsigned int tag) attribute_deprecated; //use av_codec_get_id void ff_parse_specific_params(AVCodecContext *stream, int *au_rate, int *au_ssize, int *au_scale); -#endif +#endif /* FFMPEG_RIFF_H */ diff --git a/contrib/ffmpeg/libavformat/rm.c b/contrib/ffmpeg/libavformat/rm.c deleted file mode 100644 index ad2f5ff27..000000000 --- a/contrib/ffmpeg/libavformat/rm.c +++ /dev/null @@ -1,1147 +0,0 @@ -/* - * "Real" compatible muxer and demuxer. - * Copyright (c) 2000, 2001 Fabrice Bellard. - * - * 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" - -/* in ms */ -#define BUFFER_DURATION 0 - -typedef struct { - int nb_packets; - int packet_total_size; - int packet_max_size; - /* codec related output */ - int bit_rate; - float frame_rate; - int nb_frames; /* current frame number */ - int total_frames; /* total number of frames */ - int num; - AVCodecContext *enc; -} StreamInfo; - -typedef struct { - StreamInfo streams[2]; - StreamInfo *audio_stream, *video_stream; - int data_pos; /* position of the data after the header */ - int nb_packets; - int old_format; - int current_stream; - int remaining_len; - /// Audio descrambling matrix parameters - uint8_t *audiobuf; ///< place to store reordered audio data - int64_t audiotimestamp; ///< Audio packet timestamp - int sub_packet_cnt; // Subpacket counter, used while reading - int sub_packet_size, sub_packet_h, coded_framesize; ///< Descrambling parameters from container - int audio_stream_num; ///< Stream number for audio packets - int audio_pkt_cnt; ///< Output packet counter - int audio_framesize; /// Audio frame size from container - int sub_packet_lengths[16]; /// Length of each aac subpacket -} RMContext; - -#ifdef CONFIG_MUXERS -static void put_str(ByteIOContext *s, const char *tag) -{ - put_be16(s,strlen(tag)); - while (*tag) { - put_byte(s, *tag++); - } -} - -static void put_str8(ByteIOContext *s, const char *tag) -{ - put_byte(s, strlen(tag)); - while (*tag) { - put_byte(s, *tag++); - } -} - -static void rv10_write_header(AVFormatContext *ctx, - int data_size, int index_pos) -{ - RMContext *rm = ctx->priv_data; - ByteIOContext *s = &ctx->pb; - StreamInfo *stream; - unsigned char *data_offset_ptr, *start_ptr; - const char *desc, *mimetype; - int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i; - int bit_rate, v, duration, flags, data_pos; - - start_ptr = s->buf_ptr; - - put_tag(s, ".RMF"); - put_be32(s,18); /* header size */ - put_be16(s,0); - put_be32(s,0); - put_be32(s,4 + ctx->nb_streams); /* num headers */ - - put_tag(s,"PROP"); - put_be32(s, 50); - put_be16(s, 0); - packet_max_size = 0; - packet_total_size = 0; - nb_packets = 0; - bit_rate = 0; - duration = 0; - for(i=0;i<ctx->nb_streams;i++) { - StreamInfo *stream = &rm->streams[i]; - bit_rate += stream->bit_rate; - if (stream->packet_max_size > packet_max_size) - packet_max_size = stream->packet_max_size; - nb_packets += stream->nb_packets; - packet_total_size += stream->packet_total_size; - /* select maximum duration */ - v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate); - if (v > duration) - duration = v; - } - put_be32(s, bit_rate); /* max bit rate */ - put_be32(s, bit_rate); /* avg bit rate */ - put_be32(s, packet_max_size); /* max packet size */ - if (nb_packets > 0) - packet_avg_size = packet_total_size / nb_packets; - else - packet_avg_size = 0; - put_be32(s, packet_avg_size); /* avg packet size */ - put_be32(s, nb_packets); /* num packets */ - put_be32(s, duration); /* duration */ - put_be32(s, BUFFER_DURATION); /* preroll */ - put_be32(s, index_pos); /* index offset */ - /* computation of data the data offset */ - data_offset_ptr = s->buf_ptr; - put_be32(s, 0); /* data offset : will be patched after */ - put_be16(s, ctx->nb_streams); /* num streams */ - flags = 1 | 2; /* save allowed & perfect play */ - if (url_is_streamed(s)) - flags |= 4; /* live broadcast */ - put_be16(s, flags); - - /* comments */ - - put_tag(s,"CONT"); - size = strlen(ctx->title) + strlen(ctx->author) + strlen(ctx->copyright) + - strlen(ctx->comment) + 4 * 2 + 10; - put_be32(s,size); - put_be16(s,0); - put_str(s, ctx->title); - put_str(s, ctx->author); - put_str(s, ctx->copyright); - put_str(s, ctx->comment); - - for(i=0;i<ctx->nb_streams;i++) { - int codec_data_size; - - stream = &rm->streams[i]; - - if (stream->enc->codec_type == CODEC_TYPE_AUDIO) { - desc = "The Audio Stream"; - mimetype = "audio/x-pn-realaudio"; - codec_data_size = 73; - } else { - desc = "The Video Stream"; - mimetype = "video/x-pn-realvideo"; - codec_data_size = 34; - } - - put_tag(s,"MDPR"); - size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size; - put_be32(s, size); - put_be16(s, 0); - - put_be16(s, i); /* stream number */ - put_be32(s, stream->bit_rate); /* max bit rate */ - put_be32(s, stream->bit_rate); /* avg bit rate */ - put_be32(s, stream->packet_max_size); /* max packet size */ - if (stream->nb_packets > 0) - packet_avg_size = stream->packet_total_size / - stream->nb_packets; - else - packet_avg_size = 0; - put_be32(s, packet_avg_size); /* avg packet size */ - put_be32(s, 0); /* start time */ - put_be32(s, BUFFER_DURATION); /* preroll */ - /* duration */ - if (url_is_streamed(s) || !stream->total_frames) - put_be32(s, (int)(3600 * 1000)); - else - put_be32(s, (int)(stream->total_frames * 1000 / stream->frame_rate)); - put_str8(s, desc); - put_str8(s, mimetype); - put_be32(s, codec_data_size); - - if (stream->enc->codec_type == CODEC_TYPE_AUDIO) { - int coded_frame_size, fscode, sample_rate; - sample_rate = stream->enc->sample_rate; - coded_frame_size = (stream->enc->bit_rate * - stream->enc->frame_size) / (8 * sample_rate); - /* audio codec info */ - put_tag(s, ".ra"); - put_byte(s, 0xfd); - put_be32(s, 0x00040000); /* version */ - put_tag(s, ".ra4"); - put_be32(s, 0x01b53530); /* stream length */ - put_be16(s, 4); /* unknown */ - put_be32(s, 0x39); /* header size */ - - switch(sample_rate) { - case 48000: - case 24000: - case 12000: - fscode = 1; - break; - default: - case 44100: - case 22050: - case 11025: - fscode = 2; - break; - case 32000: - case 16000: - case 8000: - fscode = 3; - } - put_be16(s, fscode); /* codec additional info, for AC3, seems - to be a frequency code */ - /* special hack to compensate rounding errors... */ - if (coded_frame_size == 557) - coded_frame_size--; - put_be32(s, coded_frame_size); /* frame length */ - put_be32(s, 0x51540); /* unknown */ - put_be32(s, 0x249f0); /* unknown */ - put_be32(s, 0x249f0); /* unknown */ - put_be16(s, 0x01); - /* frame length : seems to be very important */ - put_be16(s, coded_frame_size); - put_be32(s, 0); /* unknown */ - put_be16(s, stream->enc->sample_rate); /* sample rate */ - put_be32(s, 0x10); /* unknown */ - put_be16(s, stream->enc->channels); - put_str8(s, "Int0"); /* codec name */ - put_str8(s, "dnet"); /* codec name */ - put_be16(s, 0); /* title length */ - put_be16(s, 0); /* author length */ - put_be16(s, 0); /* copyright length */ - put_byte(s, 0); /* end of header */ - } else { - /* video codec info */ - put_be32(s,34); /* size */ - if(stream->enc->codec_id == CODEC_ID_RV10) - put_tag(s,"VIDORV10"); - else - put_tag(s,"VIDORV20"); - put_be16(s, stream->enc->width); - put_be16(s, stream->enc->height); - put_be16(s, (int) stream->frame_rate); /* frames per seconds ? */ - put_be32(s,0); /* unknown meaning */ - put_be16(s, (int) stream->frame_rate); /* unknown meaning */ - put_be32(s,0); /* unknown meaning */ - put_be16(s, 8); /* unknown meaning */ - /* Seems to be the codec version: only use basic H263. The next - versions seems to add a diffential DC coding as in - MPEG... nothing new under the sun */ - if(stream->enc->codec_id == CODEC_ID_RV10) - put_be32(s,0x10000000); - else - put_be32(s,0x20103001); - //put_be32(s,0x10003000); - } - } - - /* patch data offset field */ - data_pos = s->buf_ptr - start_ptr; - rm->data_pos = data_pos; - data_offset_ptr[0] = data_pos >> 24; - data_offset_ptr[1] = data_pos >> 16; - data_offset_ptr[2] = data_pos >> 8; - data_offset_ptr[3] = data_pos; - - /* data stream */ - put_tag(s,"DATA"); - put_be32(s,data_size + 10 + 8); - put_be16(s,0); - - put_be32(s, nb_packets); /* number of packets */ - put_be32(s,0); /* next data header */ -} - -static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream, - int length, int key_frame) -{ - int timestamp; - ByteIOContext *s = &ctx->pb; - - stream->nb_packets++; - stream->packet_total_size += length; - if (length > stream->packet_max_size) - stream->packet_max_size = length; - - put_be16(s,0); /* version */ - put_be16(s,length + 12); - put_be16(s, stream->num); /* stream number */ - timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate; - put_be32(s, timestamp); /* timestamp */ - put_byte(s, 0); /* reserved */ - put_byte(s, key_frame ? 2 : 0); /* flags */ -} - -static int rm_write_header(AVFormatContext *s) -{ - RMContext *rm = s->priv_data; - StreamInfo *stream; - int n; - AVCodecContext *codec; - - for(n=0;n<s->nb_streams;n++) { - s->streams[n]->id = n; - codec = s->streams[n]->codec; - stream = &rm->streams[n]; - memset(stream, 0, sizeof(StreamInfo)); - stream->num = n; - stream->bit_rate = codec->bit_rate; - stream->enc = codec; - - switch(codec->codec_type) { - case CODEC_TYPE_AUDIO: - rm->audio_stream = stream; - stream->frame_rate = (float)codec->sample_rate / (float)codec->frame_size; - /* XXX: dummy values */ - stream->packet_max_size = 1024; - stream->nb_packets = 0; - stream->total_frames = stream->nb_packets; - break; - case CODEC_TYPE_VIDEO: - rm->video_stream = stream; - stream->frame_rate = (float)codec->time_base.den / (float)codec->time_base.num; - /* XXX: dummy values */ - stream->packet_max_size = 4096; - stream->nb_packets = 0; - stream->total_frames = stream->nb_packets; - break; - default: - return -1; - } - } - - rv10_write_header(s, 0, 0); - put_flush_packet(&s->pb); - return 0; -} - -static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int flags) -{ - uint8_t *buf1; - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; - StreamInfo *stream = rm->audio_stream; - int i; - - /* XXX: suppress this malloc */ - buf1= (uint8_t*) av_malloc( size * sizeof(uint8_t) ); - - write_packet_header(s, stream, size, !!(flags & PKT_FLAG_KEY)); - - /* for AC3, the words seems to be reversed */ - for(i=0;i<size;i+=2) { - buf1[i] = buf[i+1]; - buf1[i+1] = buf[i]; - } - put_buffer(pb, buf1, size); - put_flush_packet(pb); - stream->nb_frames++; - av_free(buf1); - return 0; -} - -static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int flags) -{ - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; - StreamInfo *stream = rm->video_stream; - int key_frame = !!(flags & PKT_FLAG_KEY); - - /* XXX: this is incorrect: should be a parameter */ - - /* Well, I spent some time finding the meaning of these bits. I am - not sure I understood everything, but it works !! */ -#if 1 - write_packet_header(s, stream, size + 7, key_frame); - /* bit 7: '1' if final packet of a frame converted in several packets */ - put_byte(pb, 0x81); - /* bit 7: '1' if I frame. bits 6..0 : sequence number in current - frame starting from 1 */ - if (key_frame) { - put_byte(pb, 0x81); - } else { - put_byte(pb, 0x01); - } - put_be16(pb, 0x4000 + (size)); /* total frame size */ - put_be16(pb, 0x4000 + (size)); /* offset from the start or the end */ -#else - /* full frame */ - write_packet_header(s, size + 6); - put_byte(pb, 0xc0); - put_be16(pb, 0x4000 + size); /* total frame size */ - put_be16(pb, 0x4000 + packet_number * 126); /* position in stream */ -#endif - put_byte(pb, stream->nb_frames & 0xff); - - put_buffer(pb, buf, size); - put_flush_packet(pb); - - stream->nb_frames++; - return 0; -} - -static int rm_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - if (s->streams[pkt->stream_index]->codec->codec_type == - CODEC_TYPE_AUDIO) - return rm_write_audio(s, pkt->data, pkt->size, pkt->flags); - else - return rm_write_video(s, pkt->data, pkt->size, pkt->flags); -} - -static int rm_write_trailer(AVFormatContext *s) -{ - RMContext *rm = s->priv_data; - int data_size, index_pos, i; - ByteIOContext *pb = &s->pb; - - if (!url_is_streamed(&s->pb)) { - /* end of file: finish to write header */ - index_pos = url_fseek(pb, 0, SEEK_CUR); - data_size = index_pos - rm->data_pos; - - /* index */ - put_tag(pb, "INDX"); - put_be32(pb, 10 + 10 * s->nb_streams); - put_be16(pb, 0); - - for(i=0;i<s->nb_streams;i++) { - put_be32(pb, 0); /* zero indices */ - put_be16(pb, i); /* stream number */ - put_be32(pb, 0); /* next index */ - } - /* undocumented end header */ - put_be32(pb, 0); - put_be32(pb, 0); - - url_fseek(pb, 0, SEEK_SET); - for(i=0;i<s->nb_streams;i++) - rm->streams[i].total_frames = rm->streams[i].nb_frames; - rv10_write_header(s, data_size, index_pos); - } else { - /* undocumented end header */ - put_be32(pb, 0); - put_be32(pb, 0); - } - put_flush_packet(pb); - return 0; -} -#endif //CONFIG_MUXERS - -/***************************************************/ - -static void get_str(ByteIOContext *pb, char *buf, int buf_size) -{ - int len, i; - char *q; - - len = get_be16(pb); - q = buf; - for(i=0;i<len;i++) { - if (i < buf_size - 1) - *q++ = get_byte(pb); - } - *q = '\0'; -} - -static void get_str8(ByteIOContext *pb, char *buf, int buf_size) -{ - int len, i; - char *q; - - len = get_byte(pb); - q = buf; - for(i=0;i<len;i++) { - if (i < buf_size - 1) - *q++ = get_byte(pb); - } - *q = '\0'; -} - -static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, - int read_all) -{ - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; - char buf[256]; - uint32_t version; - int i; - - /* ra type header */ - version = get_be32(pb); /* version */ - if (((version >> 16) & 0xff) == 3) { - int64_t startpos = url_ftell(pb); - /* very old version */ - for(i = 0; i < 14; i++) - get_byte(pb); - get_str8(pb, s->title, sizeof(s->title)); - get_str8(pb, s->author, sizeof(s->author)); - get_str8(pb, s->copyright, sizeof(s->copyright)); - get_str8(pb, s->comment, sizeof(s->comment)); - if ((startpos + (version & 0xffff)) >= url_ftell(pb) + 2) { - // fourcc (should always be "lpcJ") - get_byte(pb); - get_str8(pb, buf, sizeof(buf)); - } - // Skip extra header crap (this should never happen) - if ((startpos + (version & 0xffff)) > url_ftell(pb)) - url_fskip(pb, (version & 0xffff) + startpos - url_ftell(pb)); - st->codec->sample_rate = 8000; - st->codec->channels = 1; - st->codec->codec_type = CODEC_TYPE_AUDIO; - st->codec->codec_id = CODEC_ID_RA_144; - } else { - int flavor, sub_packet_h, coded_framesize, sub_packet_size; - /* old version (4) */ - get_be32(pb); /* .ra4 */ - get_be32(pb); /* data size */ - get_be16(pb); /* version2 */ - get_be32(pb); /* header size */ - flavor= get_be16(pb); /* add codec info / flavor */ - rm->coded_framesize = coded_framesize = get_be32(pb); /* coded frame size */ - get_be32(pb); /* ??? */ - get_be32(pb); /* ??? */ - get_be32(pb); /* ??? */ - rm->sub_packet_h = sub_packet_h = get_be16(pb); /* 1 */ - st->codec->block_align= get_be16(pb); /* frame size */ - rm->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */ - get_be16(pb); /* ??? */ - if (((version >> 16) & 0xff) == 5) { - get_be16(pb); get_be16(pb); get_be16(pb); } - st->codec->sample_rate = get_be16(pb); - get_be32(pb); - st->codec->channels = get_be16(pb); - if (((version >> 16) & 0xff) == 5) { - get_be32(pb); - buf[0] = get_byte(pb); - buf[1] = get_byte(pb); - buf[2] = get_byte(pb); - buf[3] = get_byte(pb); - buf[4] = 0; - } else { - get_str8(pb, buf, sizeof(buf)); /* desc */ - get_str8(pb, buf, sizeof(buf)); /* desc */ - } - st->codec->codec_type = CODEC_TYPE_AUDIO; - if (!strcmp(buf, "dnet")) { - st->codec->codec_id = CODEC_ID_AC3; - } else if (!strcmp(buf, "28_8")) { - st->codec->codec_id = CODEC_ID_RA_288; - st->codec->extradata_size= 0; - rm->audio_framesize = st->codec->block_align; - st->codec->block_align = coded_framesize; - - if(rm->audio_framesize >= UINT_MAX / sub_packet_h){ - av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); - return -1; - } - - rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h); - } else if (!strcmp(buf, "cook")) { - int codecdata_length, i; - get_be16(pb); get_byte(pb); - if (((version >> 16) & 0xff) == 5) - get_byte(pb); - codecdata_length = get_be32(pb); - if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ - av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); - return -1; - } - - st->codec->codec_id = CODEC_ID_COOK; - st->codec->extradata_size= codecdata_length; - st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - for(i = 0; i < codecdata_length; i++) - ((uint8_t*)st->codec->extradata)[i] = get_byte(pb); - rm->audio_framesize = st->codec->block_align; - st->codec->block_align = rm->sub_packet_size; - - if(rm->audio_framesize >= UINT_MAX / sub_packet_h){ - av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); - return -1; - } - - rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h); - } else if (!strcmp(buf, "raac") || !strcmp(buf, "racp")) { - int codecdata_length, i; - get_be16(pb); get_byte(pb); - if (((version >> 16) & 0xff) == 5) - get_byte(pb); - st->codec->codec_id = CODEC_ID_AAC; - codecdata_length = get_be32(pb); - if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ - av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); - return -1; - } - if (codecdata_length >= 1) { - st->codec->extradata_size = codecdata_length - 1; - st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_byte(pb); - for(i = 0; i < st->codec->extradata_size; i++) - ((uint8_t*)st->codec->extradata)[i] = get_byte(pb); - } - } else { - st->codec->codec_id = CODEC_ID_NONE; - pstrcpy(st->codec->codec_name, sizeof(st->codec->codec_name), - buf); - } - if (read_all) { - get_byte(pb); - get_byte(pb); - get_byte(pb); - - get_str8(pb, s->title, sizeof(s->title)); - get_str8(pb, s->author, sizeof(s->author)); - get_str8(pb, s->copyright, sizeof(s->copyright)); - get_str8(pb, s->comment, sizeof(s->comment)); - } - } - return 0; -} - -static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap) -{ - RMContext *rm = s->priv_data; - AVStream *st; - - rm->old_format = 1; - st = av_new_stream(s, 0); - if (!st) - return -1; - return rm_read_audio_stream_info(s, st, 1); -} - -static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) -{ - RMContext *rm = s->priv_data; - AVStream *st; - ByteIOContext *pb = &s->pb; - unsigned int tag, v; - int tag_size, size, codec_data_size, i; - int64_t codec_pos; - unsigned int start_time, duration; - char buf[128]; - int flags = 0; - - tag = get_le32(pb); - if (tag == MKTAG('.', 'r', 'a', 0xfd)) { - /* very old .ra format */ - return rm_read_header_old(s, ap); - } else if (tag != MKTAG('.', 'R', 'M', 'F')) { - return AVERROR_IO; - } - - get_be32(pb); /* header size */ - get_be16(pb); - get_be32(pb); - get_be32(pb); /* number of headers */ - - for(;;) { - if (url_feof(pb)) - goto fail; - tag = get_le32(pb); - tag_size = get_be32(pb); - get_be16(pb); -#if 0 - printf("tag=%c%c%c%c (%08x) size=%d\n", - (tag) & 0xff, - (tag >> 8) & 0xff, - (tag >> 16) & 0xff, - (tag >> 24) & 0xff, - tag, - tag_size); -#endif - if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A')) - goto fail; - switch(tag) { - case MKTAG('P', 'R', 'O', 'P'): - /* file header */ - get_be32(pb); /* max bit rate */ - get_be32(pb); /* avg bit rate */ - get_be32(pb); /* max packet size */ - get_be32(pb); /* avg packet size */ - get_be32(pb); /* nb packets */ - get_be32(pb); /* duration */ - get_be32(pb); /* preroll */ - get_be32(pb); /* index offset */ - get_be32(pb); /* data offset */ - get_be16(pb); /* nb streams */ - flags = get_be16(pb); /* flags */ - break; - case MKTAG('C', 'O', 'N', 'T'): - get_str(pb, s->title, sizeof(s->title)); - get_str(pb, s->author, sizeof(s->author)); - get_str(pb, s->copyright, sizeof(s->copyright)); - get_str(pb, s->comment, sizeof(s->comment)); - break; - case MKTAG('M', 'D', 'P', 'R'): - st = av_new_stream(s, 0); - if (!st) - goto fail; - st->id = get_be16(pb); - get_be32(pb); /* max bit rate */ - st->codec->bit_rate = get_be32(pb); /* bit rate */ - get_be32(pb); /* max packet size */ - get_be32(pb); /* avg packet size */ - start_time = get_be32(pb); /* start time */ - get_be32(pb); /* preroll */ - duration = get_be32(pb); /* duration */ - st->start_time = start_time; - st->duration = duration; - get_str8(pb, buf, sizeof(buf)); /* desc */ - get_str8(pb, buf, sizeof(buf)); /* mimetype */ - codec_data_size = get_be32(pb); - codec_pos = url_ftell(pb); - st->codec->codec_type = CODEC_TYPE_DATA; - av_set_pts_info(st, 64, 1, 1000); - - v = get_be32(pb); - if (v == MKTAG(0xfd, 'a', 'r', '.')) { - /* ra type header */ - if (rm_read_audio_stream_info(s, st, 0)) - return -1; - } else { - int fps, fps2; - if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) { - fail1: - av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n"); - goto skip; - } - st->codec->codec_tag = get_le32(pb); -// av_log(NULL, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); - if ( st->codec->codec_tag != MKTAG('R', 'V', '1', '0') - && st->codec->codec_tag != MKTAG('R', 'V', '2', '0') - && st->codec->codec_tag != MKTAG('R', 'V', '3', '0') - && st->codec->codec_tag != MKTAG('R', 'V', '4', '0')) - goto fail1; - st->codec->width = get_be16(pb); - st->codec->height = get_be16(pb); - st->codec->time_base.num= 1; - fps= get_be16(pb); - st->codec->codec_type = CODEC_TYPE_VIDEO; - get_be32(pb); - fps2= get_be16(pb); - get_be16(pb); - - st->codec->extradata_size= codec_data_size - (url_ftell(pb) - codec_pos); - - if(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ - //check is redundant as get_buffer() will catch this - av_log(s, AV_LOG_ERROR, "st->codec->extradata_size too large\n"); - return -1; - } - st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - get_buffer(pb, st->codec->extradata, st->codec->extradata_size); - -// av_log(NULL, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2); - st->codec->time_base.den = fps * st->codec->time_base.num; - switch(((uint8_t*)st->codec->extradata)[4]>>4){ - case 1: st->codec->codec_id = CODEC_ID_RV10; break; - case 2: st->codec->codec_id = CODEC_ID_RV20; break; - case 3: st->codec->codec_id = CODEC_ID_RV30; break; - case 4: st->codec->codec_id = CODEC_ID_RV40; break; - default: goto fail1; - } - } -skip: - /* skip codec info */ - size = url_ftell(pb) - codec_pos; - url_fskip(pb, codec_data_size - size); - break; - case MKTAG('D', 'A', 'T', 'A'): - goto header_end; - default: - /* unknown tag: skip it */ - url_fskip(pb, tag_size - 10); - break; - } - } - header_end: - rm->nb_packets = get_be32(pb); /* number of packets */ - if (!rm->nb_packets && (flags & 4)) - rm->nb_packets = 3600 * 25; - get_be32(pb); /* next data header */ - return 0; - - fail: - for(i=0;i<s->nb_streams;i++) { - av_free(s->streams[i]); - } - return AVERROR_IO; -} - -static int get_num(ByteIOContext *pb, int *len) -{ - int n, n1; - - n = get_be16(pb); - (*len)-=2; - if (n >= 0x4000) { - return n - 0x4000; - } else { - n1 = get_be16(pb); - (*len)-=2; - return (n << 16) | n1; - } -} - -/* multiple of 20 bytes for ra144 (ugly) */ -#define RAW_PACKET_SIZE 1000 - -static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){ - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; - int len, num, res, i; - AVStream *st; - uint32_t state=0xFFFFFFFF; - - while(!url_feof(pb)){ - *pos= url_ftell(pb); - if(rm->remaining_len > 0){ - num= rm->current_stream; - len= rm->remaining_len; - *timestamp = AV_NOPTS_VALUE; - *flags= 0; - }else{ - state= (state<<8) + get_byte(pb); - - if(state == MKBETAG('I', 'N', 'D', 'X')){ - len = get_be16(pb) - 6; - if(len<0) - continue; - goto skip; - } - - if(state > (unsigned)0xFFFF || state < 12) - continue; - len=state; - state= 0xFFFFFFFF; - - num = get_be16(pb); - *timestamp = get_be32(pb); - res= get_byte(pb); /* reserved */ - *flags = get_byte(pb); /* flags */ - - - len -= 12; - } - for(i=0;i<s->nb_streams;i++) { - st = s->streams[i]; - if (num == st->id) - break; - } - if (i == s->nb_streams) { -skip: - /* skip packet if unknown number */ - url_fskip(pb, len); - rm->remaining_len -= len; - continue; - } - *stream_index= i; - - return len; - } - return -1; -} - -static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - RMContext *rm = s->priv_data; - ByteIOContext *pb = &s->pb; - AVStream *st; - int i, len, tmp, j; - int64_t timestamp, pos; - uint8_t *ptr; - int flags; - - if (rm->audio_pkt_cnt) { - // If there are queued audio packet return them first - st = s->streams[rm->audio_stream_num]; - if (st->codec->codec_id == CODEC_ID_AAC) - av_get_packet(pb, pkt, rm->sub_packet_lengths[rm->sub_packet_cnt - rm->audio_pkt_cnt]); - else { - av_new_packet(pkt, st->codec->block_align); - memcpy(pkt->data, rm->audiobuf + st->codec->block_align * - (rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), - st->codec->block_align); - } - rm->audio_pkt_cnt--; - pkt->flags = 0; - pkt->stream_index = rm->audio_stream_num; - } else if (rm->old_format) { - st = s->streams[0]; - if (st->codec->codec_id == CODEC_ID_RA_288) { - int x, y; - - for (y = 0; y < rm->sub_packet_h; y++) - for (x = 0; x < rm->sub_packet_h/2; x++) - if (get_buffer(pb, rm->audiobuf+x*2*rm->audio_framesize+y*rm->coded_framesize, rm->coded_framesize) <= 0) - return AVERROR_IO; - rm->audio_stream_num = 0; - rm->audio_pkt_cnt = rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - 1; - // Release first audio packet - av_new_packet(pkt, st->codec->block_align); - memcpy(pkt->data, rm->audiobuf, st->codec->block_align); - pkt->flags |= PKT_FLAG_KEY; // Mark first packet as keyframe - pkt->stream_index = 0; - } else { - /* just read raw bytes */ - len = RAW_PACKET_SIZE; - len= av_get_packet(pb, pkt, len); - pkt->stream_index = 0; - if (len <= 0) { - return AVERROR_IO; - } - pkt->size = len; - } - } else { - int seq=1; -resync: - len=sync(s, ×tamp, &flags, &i, &pos); - if(len<0) - return AVERROR_IO; - st = s->streams[i]; - - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - int h, pic_num, len2, pos; - - h= get_byte(pb); len--; - if(!(h & 0x40)){ - seq = get_byte(pb); len--; - } - - if((h & 0xc0) == 0x40){ - len2= pos= 0; - }else{ - len2 = get_num(pb, &len); - pos = get_num(pb, &len); - } - /* picture number */ - pic_num= get_byte(pb); len--; - rm->remaining_len= len; - rm->current_stream= st->id; - -// av_log(NULL, AV_LOG_DEBUG, "%X len:%d pos:%d len2:%d pic_num:%d\n",h, len, pos, len2, pic_num); - if(len2 && len2<len) - len=len2; - rm->remaining_len-= len; - av_get_packet(pb, pkt, len); - - } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { - if ((st->codec->codec_id == CODEC_ID_RA_288) || - (st->codec->codec_id == CODEC_ID_COOK)) { - int x; - int sps = rm->sub_packet_size; - int cfs = rm->coded_framesize; - int h = rm->sub_packet_h; - int y = rm->sub_packet_cnt; - int w = rm->audio_framesize; - - if (flags & 2) - y = rm->sub_packet_cnt = 0; - if (!y) - rm->audiotimestamp = timestamp; - - switch(st->codec->codec_id) { - case CODEC_ID_RA_288: - for (x = 0; x < h/2; x++) - get_buffer(pb, rm->audiobuf+x*2*w+y*cfs, cfs); - break; - case CODEC_ID_COOK: - for (x = 0; x < w/sps; x++) - get_buffer(pb, rm->audiobuf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); - break; - } - - if (++(rm->sub_packet_cnt) < h) - goto resync; - else { - rm->sub_packet_cnt = 0; - rm->audio_stream_num = i; - rm->audio_pkt_cnt = h * w / st->codec->block_align - 1; - // Release first audio packet - av_new_packet(pkt, st->codec->block_align); - memcpy(pkt->data, rm->audiobuf, st->codec->block_align); - timestamp = rm->audiotimestamp; - flags = 2; // Mark first packet as keyframe - } - } else if (st->codec->codec_id == CODEC_ID_AAC) { - int x; - rm->audio_stream_num = i; - rm->sub_packet_cnt = (get_be16(pb) & 0xf0) >> 4; - if (rm->sub_packet_cnt) { - for (x = 0; x < rm->sub_packet_cnt; x++) - rm->sub_packet_lengths[x] = get_be16(pb); - // Release first audio packet - rm->audio_pkt_cnt = rm->sub_packet_cnt - 1; - av_get_packet(pb, pkt, rm->sub_packet_lengths[0]); - flags = 2; // Mark first packet as keyframe - } - } else - av_get_packet(pb, pkt, len); - - } else - av_get_packet(pb, pkt, len); - - if( (st->discard >= AVDISCARD_NONKEY && !(flags&2)) - || st->discard >= AVDISCARD_ALL){ - av_free_packet(pkt); - goto resync; - } - - pkt->stream_index = i; - -#if 0 - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - if(st->codec->codec_id == CODEC_ID_RV20){ - int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); - av_log(NULL, AV_LOG_DEBUG, "%d %"PRId64" %d\n", timestamp, timestamp*512LL/25, seq); - - seq |= (timestamp&~0x3FFF); - if(seq - timestamp > 0x2000) seq -= 0x4000; - if(seq - timestamp < -0x2000) seq += 0x4000; - } - } -#endif - pkt->pts= timestamp; - if(flags&2){ - pkt->flags |= PKT_FLAG_KEY; - if((seq&0x7F) == 1) - av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); - } - } - - /* for AC3, needs to swap bytes */ - if (st->codec->codec_id == CODEC_ID_AC3) { - ptr = pkt->data; - for(j=0;j<len;j+=2) { - tmp = ptr[0]; - ptr[0] = ptr[1]; - ptr[1] = tmp; - ptr += 2; - } - } - return 0; -} - -static int rm_read_close(AVFormatContext *s) -{ - RMContext *rm = s->priv_data; - - av_free(rm->audiobuf); - return 0; -} - -static int rm_probe(AVProbeData *p) -{ - /* check file header */ - if (p->buf_size <= 32) - return 0; - if ((p->buf[0] == '.' && p->buf[1] == 'R' && - p->buf[2] == 'M' && p->buf[3] == 'F' && - p->buf[4] == 0 && p->buf[5] == 0) || - (p->buf[0] == '.' && p->buf[1] == 'r' && - p->buf[2] == 'a' && p->buf[3] == 0xfd)) - return AVPROBE_SCORE_MAX; - else - return 0; -} - -static int64_t rm_read_dts(AVFormatContext *s, int stream_index, - int64_t *ppos, int64_t pos_limit) -{ - RMContext *rm = s->priv_data; - int64_t pos, dts; - int stream_index2, flags, len, h; - - pos = *ppos; - - if(rm->old_format) - return AV_NOPTS_VALUE; - - url_fseek(&s->pb, pos, SEEK_SET); - rm->remaining_len=0; - for(;;){ - int seq=1; - AVStream *st; - - len=sync(s, &dts, &flags, &stream_index2, &pos); - if(len<0) - return AV_NOPTS_VALUE; - - st = s->streams[stream_index2]; - if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - h= get_byte(&s->pb); len--; - if(!(h & 0x40)){ - seq = get_byte(&s->pb); len--; - } - } - - if((flags&2) && (seq&0x7F) == 1){ -// av_log(s, AV_LOG_DEBUG, "%d %d-%d %"PRId64" %d\n", flags, stream_index2, stream_index, dts, seq); - av_add_index_entry(st, pos, dts, 0, 0, AVINDEX_KEYFRAME); - if(stream_index2 == stream_index) - break; - } - - url_fskip(&s->pb, len); - } - *ppos = pos; - return dts; -} - -#ifdef CONFIG_RM_DEMUXER -AVInputFormat rm_demuxer = { - "rm", - "rm format", - sizeof(RMContext), - rm_probe, - rm_read_header, - rm_read_packet, - rm_read_close, - NULL, - rm_read_dts, -}; -#endif -#ifdef CONFIG_RM_MUXER -AVOutputFormat rm_muxer = { - "rm", - "rm format", - "application/vnd.rn-realmedia", - "rm,ra", - sizeof(RMContext), - CODEC_ID_AC3, - CODEC_ID_RV10, - rm_write_header, - rm_write_packet, - rm_write_trailer, -}; -#endif diff --git a/contrib/ffmpeg/libavformat/rm.h b/contrib/ffmpeg/libavformat/rm.h new file mode 100644 index 000000000..2f7f8df2e --- /dev/null +++ b/contrib/ffmpeg/libavformat/rm.h @@ -0,0 +1,108 @@ +/* + * "Real" compatible muxer and demuxer. + * Copyright (c) 2000, 2001 Fabrice Bellard. + * + * 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 FFMPEG_RM_H +#define FFMPEG_RM_H + +#include "avformat.h" + + +typedef struct { + int nb_packets; + int packet_total_size; + int packet_max_size; + /* codec related output */ + int bit_rate; + float frame_rate; + int nb_frames; /* current frame number */ + int total_frames; /* total number of frames */ + int num; + AVCodecContext *enc; +} StreamInfo; + +typedef struct { + StreamInfo streams[2]; + StreamInfo *audio_stream, *video_stream; + int data_pos; /* position of the data after the header */ + int nb_packets; + int old_format; + int current_stream; + int remaining_len; + uint8_t *videobuf; ///< place to store merged video frame + int videobufsize; ///< current assembled frame size + int videobufpos; ///< position for the next slice in the video buffer + int curpic_num; ///< picture number of current frame + int cur_slice, slices; + int64_t pktpos; ///< first slice position in file + /// Audio descrambling matrix parameters + uint8_t *audiobuf; ///< place to store reordered audio data + int64_t audiotimestamp; ///< Audio packet timestamp + int sub_packet_cnt; // Subpacket counter, used while reading + int sub_packet_size, sub_packet_h, coded_framesize; ///< Descrambling parameters from container + int audio_stream_num; ///< Stream number for audio packets + int audio_pkt_cnt; ///< Output packet counter + int audio_framesize; /// Audio frame size from container + int sub_packet_lengths[16]; /// Length of each aac subpacket +} RMContext; + +/** + * Read the MDPR chunk, which contains stream-specific codec initialization + * parameters. + * + * @param s context containing RMContext and ByteIOContext for stream reading + * @param st the stream that the MDPR chunk belongs to and where to store the + * parameters read from the chunk into + * @return 0 on success, errno codes on error + */ +int ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVStream *st); + +/** + * Parse one rm-stream packet from the input bytestream. + * + * @param s context containing RMContext and ByteIOContext for stream reading + * @param st stream to which the packet to be read belongs + * @param len packet length to read from the input + * @param pkt packet location to store the parsed packet data + * @param seq pointer to an integer containing the sequence number, may be + * updated + * @param flags pointer to an integer containing the packet flags, may be + updated + * @param ts pointer to timestamp, may be updated + * @return 0 on success, errno codes on error + */ +int ff_rm_parse_packet (AVFormatContext *s, AVStream *st, int len, + AVPacket *pkt, int *seq, int *flags, int64_t *ts); + +/** + * Retrieve one cached packet from the rm-context. The real container can + * store several packets (as interpreted by the codec) in a single container + * packet, which means the demuxer holds some back when the first container + * packet is parsed and returned. The result is that rm->audio_pkt_cnt is + * a positive number, the amount of cached packets. Using this function, each + * of those packets can be retrieved sequentially. + * + * @param s context containing RMContext and ByteIOContext for stream reading + * @param st stream that this packet belongs to + * @param pkt location to store the packet data + */ +void ff_rm_retrieve_cache (AVFormatContext *s, AVStream *st, AVPacket *pkt); + +#endif /* FFMPEG_RM_H */ diff --git a/contrib/ffmpeg/libavformat/rmdec.c b/contrib/ffmpeg/libavformat/rmdec.c new file mode 100644 index 000000000..9a770cf4d --- /dev/null +++ b/contrib/ffmpeg/libavformat/rmdec.c @@ -0,0 +1,801 @@ +/* + * "Real" compatible demuxer. + * Copyright (c) 2000, 2001 Fabrice Bellard. + * + * 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 "rm.h" +#include "avstring.h" + +static inline void get_strl(ByteIOContext *pb, char *buf, int buf_size, int len) +{ + int i; + char *q, r; + + q = buf; + for(i=0;i<len;i++) { + r = get_byte(pb); + if (i < buf_size - 1) + *q++ = r; + } + if (buf_size > 0) *q = '\0'; +} + +static void get_str16(ByteIOContext *pb, char *buf, int buf_size) +{ + get_strl(pb, buf, buf_size, get_be16(pb)); +} + +static void get_str8(ByteIOContext *pb, char *buf, int buf_size) +{ + get_strl(pb, buf, buf_size, get_byte(pb)); +} + +static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st, + int read_all) +{ + RMContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; + char buf[256]; + uint32_t version; + int i; + + /* ra type header */ + version = get_be32(pb); /* version */ + if (((version >> 16) & 0xff) == 3) { + int64_t startpos = url_ftell(pb); + /* very old version */ + for(i = 0; i < 14; i++) + get_byte(pb); + get_str8(pb, s->title, sizeof(s->title)); + get_str8(pb, s->author, sizeof(s->author)); + get_str8(pb, s->copyright, sizeof(s->copyright)); + get_str8(pb, s->comment, sizeof(s->comment)); + if ((startpos + (version & 0xffff)) >= url_ftell(pb) + 2) { + // fourcc (should always be "lpcJ") + get_byte(pb); + get_str8(pb, buf, sizeof(buf)); + } + // Skip extra header crap (this should never happen) + if ((startpos + (version & 0xffff)) > url_ftell(pb)) + url_fskip(pb, (version & 0xffff) + startpos - url_ftell(pb)); + st->codec->sample_rate = 8000; + st->codec->channels = 1; + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_RA_144; + } else { + int flavor, sub_packet_h, coded_framesize, sub_packet_size; + /* old version (4) */ + get_be32(pb); /* .ra4 */ + get_be32(pb); /* data size */ + get_be16(pb); /* version2 */ + get_be32(pb); /* header size */ + flavor= get_be16(pb); /* add codec info / flavor */ + rm->coded_framesize = coded_framesize = get_be32(pb); /* coded frame size */ + get_be32(pb); /* ??? */ + get_be32(pb); /* ??? */ + get_be32(pb); /* ??? */ + rm->sub_packet_h = sub_packet_h = get_be16(pb); /* 1 */ + st->codec->block_align= get_be16(pb); /* frame size */ + rm->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */ + get_be16(pb); /* ??? */ + if (((version >> 16) & 0xff) == 5) { + get_be16(pb); get_be16(pb); get_be16(pb); } + st->codec->sample_rate = get_be16(pb); + get_be32(pb); + st->codec->channels = get_be16(pb); + if (((version >> 16) & 0xff) == 5) { + get_be32(pb); + buf[0] = get_byte(pb); + buf[1] = get_byte(pb); + buf[2] = get_byte(pb); + buf[3] = get_byte(pb); + buf[4] = 0; + } else { + get_str8(pb, buf, sizeof(buf)); /* desc */ + get_str8(pb, buf, sizeof(buf)); /* desc */ + } + st->codec->codec_type = CODEC_TYPE_AUDIO; + if (!strcmp(buf, "dnet")) { + st->codec->codec_id = CODEC_ID_AC3; + st->need_parsing = AVSTREAM_PARSE_FULL; + } else if (!strcmp(buf, "28_8")) { + st->codec->codec_id = CODEC_ID_RA_288; + st->codec->extradata_size= 0; + rm->audio_framesize = st->codec->block_align; + st->codec->block_align = coded_framesize; + + if(rm->audio_framesize >= UINT_MAX / sub_packet_h){ + av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); + return -1; + } + + rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h); + } else if ((!strcmp(buf, "cook")) || (!strcmp(buf, "atrc"))) { + int codecdata_length, i; + get_be16(pb); get_byte(pb); + if (((version >> 16) & 0xff) == 5) + get_byte(pb); + codecdata_length = get_be32(pb); + if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ + av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); + return -1; + } + + if (!strcmp(buf, "cook")) st->codec->codec_id = CODEC_ID_COOK; + else st->codec->codec_id = CODEC_ID_ATRAC3; + st->codec->extradata_size= codecdata_length; + st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + for(i = 0; i < codecdata_length; i++) + ((uint8_t*)st->codec->extradata)[i] = get_byte(pb); + rm->audio_framesize = st->codec->block_align; + st->codec->block_align = rm->sub_packet_size; + + if(rm->audio_framesize >= UINT_MAX / sub_packet_h){ + av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); + return -1; + } + + rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h); + } else if (!strcmp(buf, "raac") || !strcmp(buf, "racp")) { + int codecdata_length, i; + get_be16(pb); get_byte(pb); + if (((version >> 16) & 0xff) == 5) + get_byte(pb); + st->codec->codec_id = CODEC_ID_AAC; + codecdata_length = get_be32(pb); + if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ + av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); + return -1; + } + if (codecdata_length >= 1) { + st->codec->extradata_size = codecdata_length - 1; + st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + get_byte(pb); + for(i = 0; i < st->codec->extradata_size; i++) + ((uint8_t*)st->codec->extradata)[i] = get_byte(pb); + } + } else { + st->codec->codec_id = CODEC_ID_NONE; + av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); + } + if (read_all) { + get_byte(pb); + get_byte(pb); + get_byte(pb); + + get_str8(pb, s->title, sizeof(s->title)); + get_str8(pb, s->author, sizeof(s->author)); + get_str8(pb, s->copyright, sizeof(s->copyright)); + get_str8(pb, s->comment, sizeof(s->comment)); + } + } + return 0; +} + +int +ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVStream *st) +{ + ByteIOContext *pb = s->pb; + unsigned int v; + int codec_data_size, size; + int64_t codec_pos; + + codec_data_size = get_be32(pb); + codec_pos = url_ftell(pb); + v = get_be32(pb); + if (v == MKTAG(0xfd, 'a', 'r', '.')) { + /* ra type header */ + if (rm_read_audio_stream_info(s, st, 0)) + return -1; + } else { + int fps, fps2; + if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) { + fail1: + av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n"); + goto skip; + } + st->codec->codec_tag = get_le32(pb); +// av_log(NULL, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); + if ( st->codec->codec_tag != MKTAG('R', 'V', '1', '0') + && st->codec->codec_tag != MKTAG('R', 'V', '2', '0') + && st->codec->codec_tag != MKTAG('R', 'V', '3', '0') + && st->codec->codec_tag != MKTAG('R', 'V', '4', '0')) + goto fail1; + st->codec->width = get_be16(pb); + st->codec->height = get_be16(pb); + st->codec->time_base.num= 1; + fps= get_be16(pb); + st->codec->codec_type = CODEC_TYPE_VIDEO; + get_be32(pb); + fps2= get_be16(pb); + get_be16(pb); + + st->codec->extradata_size= codec_data_size - (url_ftell(pb) - codec_pos); + + if(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ + //check is redundant as get_buffer() will catch this + av_log(s, AV_LOG_ERROR, "st->codec->extradata_size too large\n"); + return -1; + } + st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + get_buffer(pb, st->codec->extradata, st->codec->extradata_size); + +// av_log(NULL, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2); + st->codec->time_base.den = fps * st->codec->time_base.num; + switch(((uint8_t*)st->codec->extradata)[4]>>4){ + case 1: st->codec->codec_id = CODEC_ID_RV10; break; + case 2: st->codec->codec_id = CODEC_ID_RV20; break; + case 3: st->codec->codec_id = CODEC_ID_RV30; break; + case 4: st->codec->codec_id = CODEC_ID_RV40; break; + default: goto fail1; + } + } + +skip: + /* skip codec info */ + size = url_ftell(pb) - codec_pos; + url_fskip(pb, codec_data_size - size); + + return 0; +} + + +static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap) +{ + RMContext *rm = s->priv_data; + AVStream *st; + + rm->old_format = 1; + st = av_new_stream(s, 0); + if (!st) + return -1; + return rm_read_audio_stream_info(s, st, 1); +} + +static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + RMContext *rm = s->priv_data; + AVStream *st; + ByteIOContext *pb = s->pb; + unsigned int tag; + int tag_size, i; + unsigned int start_time, duration; + char buf[128]; + int flags = 0; + + tag = get_le32(pb); + if (tag == MKTAG('.', 'r', 'a', 0xfd)) { + /* very old .ra format */ + return rm_read_header_old(s, ap); + } else if (tag != MKTAG('.', 'R', 'M', 'F')) { + return AVERROR(EIO); + } + + get_be32(pb); /* header size */ + get_be16(pb); + get_be32(pb); + get_be32(pb); /* number of headers */ + + for(;;) { + if (url_feof(pb)) + goto fail; + tag = get_le32(pb); + tag_size = get_be32(pb); + get_be16(pb); +#if 0 + printf("tag=%c%c%c%c (%08x) size=%d\n", + (tag) & 0xff, + (tag >> 8) & 0xff, + (tag >> 16) & 0xff, + (tag >> 24) & 0xff, + tag, + tag_size); +#endif + if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A')) + goto fail; + switch(tag) { + case MKTAG('P', 'R', 'O', 'P'): + /* file header */ + get_be32(pb); /* max bit rate */ + get_be32(pb); /* avg bit rate */ + get_be32(pb); /* max packet size */ + get_be32(pb); /* avg packet size */ + get_be32(pb); /* nb packets */ + get_be32(pb); /* duration */ + get_be32(pb); /* preroll */ + get_be32(pb); /* index offset */ + get_be32(pb); /* data offset */ + get_be16(pb); /* nb streams */ + flags = get_be16(pb); /* flags */ + break; + case MKTAG('C', 'O', 'N', 'T'): + get_str16(pb, s->title, sizeof(s->title)); + get_str16(pb, s->author, sizeof(s->author)); + get_str16(pb, s->copyright, sizeof(s->copyright)); + get_str16(pb, s->comment, sizeof(s->comment)); + break; + case MKTAG('M', 'D', 'P', 'R'): + st = av_new_stream(s, 0); + if (!st) + goto fail; + st->id = get_be16(pb); + get_be32(pb); /* max bit rate */ + st->codec->bit_rate = get_be32(pb); /* bit rate */ + get_be32(pb); /* max packet size */ + get_be32(pb); /* avg packet size */ + start_time = get_be32(pb); /* start time */ + get_be32(pb); /* preroll */ + duration = get_be32(pb); /* duration */ + st->start_time = start_time; + st->duration = duration; + get_str8(pb, buf, sizeof(buf)); /* desc */ + get_str8(pb, buf, sizeof(buf)); /* mimetype */ + st->codec->codec_type = CODEC_TYPE_DATA; + av_set_pts_info(st, 64, 1, 1000); + if (ff_rm_read_mdpr_codecdata(s, st) < 0) + return -1; + break; + case MKTAG('D', 'A', 'T', 'A'): + goto header_end; + default: + /* unknown tag: skip it */ + url_fskip(pb, tag_size - 10); + break; + } + } + header_end: + rm->nb_packets = get_be32(pb); /* number of packets */ + if (!rm->nb_packets && (flags & 4)) + rm->nb_packets = 3600 * 25; + get_be32(pb); /* next data header */ + rm->curpic_num = -1; + return 0; + + fail: + for(i=0;i<s->nb_streams;i++) { + av_free(s->streams[i]); + } + return AVERROR(EIO); +} + +static int get_num(ByteIOContext *pb, int *len) +{ + int n, n1; + + n = get_be16(pb); + (*len)-=2; + n &= 0x7FFF; + if (n >= 0x4000) { + return n - 0x4000; + } else { + n1 = get_be16(pb); + (*len)-=2; + return (n << 16) | n1; + } +} + +/* multiple of 20 bytes for ra144 (ugly) */ +#define RAW_PACKET_SIZE 1000 + +static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){ + RMContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; + int len, num, res, i; + AVStream *st; + uint32_t state=0xFFFFFFFF; + + while(!url_feof(pb)){ + *pos= url_ftell(pb); + if(rm->remaining_len > 0){ + num= rm->current_stream; + len= rm->remaining_len; + *timestamp = AV_NOPTS_VALUE; + *flags= 0; + }else{ + state= (state<<8) + get_byte(pb); + + if(state == MKBETAG('I', 'N', 'D', 'X')){ + len = get_be16(pb) - 6; + if(len<0) + continue; + goto skip; + } + + if(state > (unsigned)0xFFFF || state < 12) + continue; + len=state; + state= 0xFFFFFFFF; + + num = get_be16(pb); + *timestamp = get_be32(pb); + res= get_byte(pb); /* reserved */ + *flags = get_byte(pb); /* flags */ + + + len -= 12; + } + for(i=0;i<s->nb_streams;i++) { + st = s->streams[i]; + if (num == st->id) + break; + } + if (i == s->nb_streams) { +skip: + /* skip packet if unknown number */ + url_fskip(pb, len); + rm->remaining_len -= len; + continue; + } + *stream_index= i; + + return len; + } + return -1; +} + +static int rm_assemble_video_frame(AVFormatContext *s, RMContext *rm, AVPacket *pkt, int len) +{ + ByteIOContext *pb = s->pb; + int hdr, seq, pic_num, len2, pos; + int type; + + hdr = get_byte(pb); len--; + type = hdr >> 6; + switch(type){ + case 0: // slice + case 2: // last slice + seq = get_byte(pb); len--; + len2 = get_num(pb, &len); + pos = get_num(pb, &len); + pic_num = get_byte(pb); len--; + rm->remaining_len = len; + break; + case 1: //whole frame + seq = get_byte(pb); len--; + if(av_new_packet(pkt, len + 9) < 0) + return AVERROR(EIO); + pkt->data[0] = 0; + AV_WL32(pkt->data + 1, 1); + AV_WL32(pkt->data + 5, 0); + get_buffer(pb, pkt->data + 9, len); + rm->remaining_len = 0; + return 0; + case 3: //frame as a part of packet + len2 = get_num(pb, &len); + pos = get_num(pb, &len); + pic_num = get_byte(pb); len--; + rm->remaining_len = len - len2; + if(av_new_packet(pkt, len2 + 9) < 0) + return AVERROR(EIO); + pkt->data[0] = 0; + AV_WL32(pkt->data + 1, 1); + AV_WL32(pkt->data + 5, 0); + get_buffer(pb, pkt->data + 9, len2); + return 0; + } + //now we have to deal with single slice + + if((seq & 0x7F) == 1 || rm->curpic_num != pic_num){ + rm->slices = ((hdr & 0x3F) << 1) + 1; + rm->videobufsize = len2 + 8*rm->slices + 1; + av_free(rm->videobuf); + if(!(rm->videobuf = av_malloc(rm->videobufsize))) + return AVERROR(ENOMEM); + rm->videobufpos = 8*rm->slices + 1; + rm->cur_slice = 0; + rm->curpic_num = pic_num; + rm->pktpos = url_ftell(pb); + } + if(type == 2) + len = FFMIN(len, pos); + + if(++rm->cur_slice > rm->slices) + return 1; + AV_WL32(rm->videobuf - 7 + 8*rm->cur_slice, 1); + AV_WL32(rm->videobuf - 3 + 8*rm->cur_slice, rm->videobufpos - 8*rm->slices - 1); + if(rm->videobufpos + len > rm->videobufsize) + return 1; + if (get_buffer(pb, rm->videobuf + rm->videobufpos, len) != len) + return AVERROR(EIO); + rm->videobufpos += len; + rm->remaining_len-= len; + + if(type == 2 || (rm->videobufpos) == rm->videobufsize){ + rm->videobuf[0] = rm->cur_slice-1; + if(av_new_packet(pkt, rm->videobufpos - 8*(rm->slices - rm->cur_slice)) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, rm->videobuf, 1 + 8*rm->cur_slice); + memcpy(pkt->data + 1 + 8*rm->cur_slice, rm->videobuf + 1 + 8*rm->slices, + rm->videobufpos - 1 - 8*rm->slices); + pkt->pts = AV_NOPTS_VALUE; + pkt->pos = rm->pktpos; + return 0; + } + + return 1; +} + +static inline void +rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) +{ + uint8_t *ptr; + int j; + + if (st->codec->codec_id == CODEC_ID_AC3) { + ptr = pkt->data; + for (j=0;j<pkt->size;j+=2) { + FFSWAP(int, ptr[0], ptr[1]); + ptr += 2; + } + } +} + +int +ff_rm_parse_packet (AVFormatContext *s, AVStream *st, int len, AVPacket *pkt, + int *seq, int *flags, int64_t *timestamp) +{ + ByteIOContext *pb = s->pb; + RMContext *rm = s->priv_data; + + if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + rm->current_stream= st->id; + if(rm_assemble_video_frame(s, rm, pkt, len) == 1) + return -1; //got partial frame + } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { + if ((st->codec->codec_id == CODEC_ID_RA_288) || + (st->codec->codec_id == CODEC_ID_COOK) || + (st->codec->codec_id == CODEC_ID_ATRAC3)) { + int x; + int sps = rm->sub_packet_size; + int cfs = rm->coded_framesize; + int h = rm->sub_packet_h; + int y = rm->sub_packet_cnt; + int w = rm->audio_framesize; + + if (*flags & 2) + y = rm->sub_packet_cnt = 0; + if (!y) + rm->audiotimestamp = *timestamp; + + switch(st->codec->codec_id) { + case CODEC_ID_RA_288: + for (x = 0; x < h/2; x++) + get_buffer(pb, rm->audiobuf+x*2*w+y*cfs, cfs); + break; + case CODEC_ID_ATRAC3: + case CODEC_ID_COOK: + for (x = 0; x < w/sps; x++) + get_buffer(pb, rm->audiobuf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); + break; + } + + if (++(rm->sub_packet_cnt) < h) + return -1; + else { + rm->sub_packet_cnt = 0; + rm->audio_stream_num = st->index; + rm->audio_pkt_cnt = h * w / st->codec->block_align - 1; + // Release first audio packet + av_new_packet(pkt, st->codec->block_align); + memcpy(pkt->data, rm->audiobuf, st->codec->block_align); + *timestamp = rm->audiotimestamp; + *flags = 2; // Mark first packet as keyframe + } + } else if (st->codec->codec_id == CODEC_ID_AAC) { + int x; + rm->audio_stream_num = st->index; + rm->sub_packet_cnt = (get_be16(pb) & 0xf0) >> 4; + if (rm->sub_packet_cnt) { + for (x = 0; x < rm->sub_packet_cnt; x++) + rm->sub_packet_lengths[x] = get_be16(pb); + // Release first audio packet + rm->audio_pkt_cnt = rm->sub_packet_cnt - 1; + av_get_packet(pb, pkt, rm->sub_packet_lengths[0]); + *flags = 2; // Mark first packet as keyframe + } + } else { + av_get_packet(pb, pkt, len); + rm_ac3_swap_bytes(st, pkt); + } + } else + av_get_packet(pb, pkt, len); + + if( (st->discard >= AVDISCARD_NONKEY && !(*flags&2)) + || st->discard >= AVDISCARD_ALL){ + av_free_packet(pkt); + return -1; + } + + pkt->stream_index = st->index; + +#if 0 + if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + if(st->codec->codec_id == CODEC_ID_RV20){ + int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); + av_log(NULL, AV_LOG_DEBUG, "%d %"PRId64" %d\n", *timestamp, *timestamp*512LL/25, seq); + + seq |= (*timestamp&~0x3FFF); + if(seq - *timestamp > 0x2000) seq -= 0x4000; + if(seq - *timestamp < -0x2000) seq += 0x4000; + } + } +#endif + + pkt->pts= *timestamp; + if (*flags & 2) + pkt->flags |= PKT_FLAG_KEY; + + return 0; +} + +void +ff_rm_retrieve_cache (AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + ByteIOContext *pb = s->pb; + RMContext *rm = s->priv_data; + + assert (rm->audio_pkt_cnt > 0); + + if (st->codec->codec_id == CODEC_ID_AAC) + av_get_packet(pb, pkt, rm->sub_packet_lengths[rm->sub_packet_cnt - rm->audio_pkt_cnt]); + else { + av_new_packet(pkt, st->codec->block_align); + memcpy(pkt->data, rm->audiobuf + st->codec->block_align * + (rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), + st->codec->block_align); + } + rm->audio_pkt_cnt--; + pkt->flags = 0; + pkt->stream_index = st->index; +} + +static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + RMContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; + AVStream *st; + int i, len; + int64_t timestamp, pos; + int flags; + + if (rm->audio_pkt_cnt) { + // If there are queued audio packet return them first + st = s->streams[rm->audio_stream_num]; + ff_rm_retrieve_cache(s, st, pkt); + } else if (rm->old_format) { + st = s->streams[0]; + if (st->codec->codec_id == CODEC_ID_RA_288) { + int x, y; + + for (y = 0; y < rm->sub_packet_h; y++) + for (x = 0; x < rm->sub_packet_h/2; x++) + if (get_buffer(pb, rm->audiobuf+x*2*rm->audio_framesize+y*rm->coded_framesize, rm->coded_framesize) <= 0) + return AVERROR(EIO); + rm->audio_stream_num = 0; + rm->audio_pkt_cnt = rm->sub_packet_h * rm->audio_framesize / st->codec->block_align - 1; + // Release first audio packet + av_new_packet(pkt, st->codec->block_align); + memcpy(pkt->data, rm->audiobuf, st->codec->block_align); + pkt->flags |= PKT_FLAG_KEY; // Mark first packet as keyframe + pkt->stream_index = 0; + } else { + /* just read raw bytes */ + len = RAW_PACKET_SIZE; + len= av_get_packet(pb, pkt, len); + pkt->stream_index = 0; + if (len <= 0) { + return AVERROR(EIO); + } + pkt->size = len; + } + rm_ac3_swap_bytes(st, pkt); + } else { + int seq=1; +resync: + len=sync(s, ×tamp, &flags, &i, &pos); + if(len<0) + return AVERROR(EIO); + st = s->streams[i]; + + if (ff_rm_parse_packet (s, st, len, pkt, &seq, &flags, ×tamp) < 0) + goto resync; + + if((flags&2) && (seq&0x7F) == 1) + av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); + } + + return 0; +} + +static int rm_read_close(AVFormatContext *s) +{ + RMContext *rm = s->priv_data; + + av_free(rm->audiobuf); + av_free(rm->videobuf); + return 0; +} + +static int rm_probe(AVProbeData *p) +{ + /* check file header */ + if ((p->buf[0] == '.' && p->buf[1] == 'R' && + p->buf[2] == 'M' && p->buf[3] == 'F' && + p->buf[4] == 0 && p->buf[5] == 0) || + (p->buf[0] == '.' && p->buf[1] == 'r' && + p->buf[2] == 'a' && p->buf[3] == 0xfd)) + return AVPROBE_SCORE_MAX; + else + return 0; +} + +static int64_t rm_read_dts(AVFormatContext *s, int stream_index, + int64_t *ppos, int64_t pos_limit) +{ + RMContext *rm = s->priv_data; + int64_t pos, dts; + int stream_index2, flags, len, h; + + pos = *ppos; + + if(rm->old_format) + return AV_NOPTS_VALUE; + + url_fseek(s->pb, pos, SEEK_SET); + rm->remaining_len=0; + for(;;){ + int seq=1; + AVStream *st; + + len=sync(s, &dts, &flags, &stream_index2, &pos); + if(len<0) + return AV_NOPTS_VALUE; + + st = s->streams[stream_index2]; + if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + h= get_byte(s->pb); len--; + if(!(h & 0x40)){ + seq = get_byte(s->pb); len--; + } + } + + if((flags&2) && (seq&0x7F) == 1){ +// av_log(s, AV_LOG_DEBUG, "%d %d-%d %"PRId64" %d\n", flags, stream_index2, stream_index, dts, seq); + av_add_index_entry(st, pos, dts, 0, 0, AVINDEX_KEYFRAME); + if(stream_index2 == stream_index) + break; + } + + url_fskip(s->pb, len); + } + *ppos = pos; + return dts; +} + +AVInputFormat rm_demuxer = { + "rm", + "rm format", + sizeof(RMContext), + rm_probe, + rm_read_header, + rm_read_packet, + rm_read_close, + NULL, + rm_read_dts, +}; diff --git a/contrib/ffmpeg/libavformat/rmenc.c b/contrib/ffmpeg/libavformat/rmenc.c new file mode 100644 index 000000000..3a3525d96 --- /dev/null +++ b/contrib/ffmpeg/libavformat/rmenc.c @@ -0,0 +1,444 @@ +/* + * "Real" compatible muxer. + * Copyright (c) 2000, 2001 Fabrice Bellard. + * + * 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 "rm.h" + +/* in ms */ +#define BUFFER_DURATION 0 + + +static void put_str(ByteIOContext *s, const char *tag) +{ + put_be16(s,strlen(tag)); + while (*tag) { + put_byte(s, *tag++); + } +} + +static void put_str8(ByteIOContext *s, const char *tag) +{ + put_byte(s, strlen(tag)); + while (*tag) { + put_byte(s, *tag++); + } +} + +static void rv10_write_header(AVFormatContext *ctx, + int data_size, int index_pos) +{ + RMContext *rm = ctx->priv_data; + ByteIOContext *s = ctx->pb; + StreamInfo *stream; + unsigned char *data_offset_ptr, *start_ptr; + const char *desc, *mimetype; + int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i; + int bit_rate, v, duration, flags, data_pos; + + start_ptr = s->buf_ptr; + + put_tag(s, ".RMF"); + put_be32(s,18); /* header size */ + put_be16(s,0); + put_be32(s,0); + put_be32(s,4 + ctx->nb_streams); /* num headers */ + + put_tag(s,"PROP"); + put_be32(s, 50); + put_be16(s, 0); + packet_max_size = 0; + packet_total_size = 0; + nb_packets = 0; + bit_rate = 0; + duration = 0; + for(i=0;i<ctx->nb_streams;i++) { + StreamInfo *stream = &rm->streams[i]; + bit_rate += stream->bit_rate; + if (stream->packet_max_size > packet_max_size) + packet_max_size = stream->packet_max_size; + nb_packets += stream->nb_packets; + packet_total_size += stream->packet_total_size; + /* select maximum duration */ + v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate); + if (v > duration) + duration = v; + } + put_be32(s, bit_rate); /* max bit rate */ + put_be32(s, bit_rate); /* avg bit rate */ + put_be32(s, packet_max_size); /* max packet size */ + if (nb_packets > 0) + packet_avg_size = packet_total_size / nb_packets; + else + packet_avg_size = 0; + put_be32(s, packet_avg_size); /* avg packet size */ + put_be32(s, nb_packets); /* num packets */ + put_be32(s, duration); /* duration */ + put_be32(s, BUFFER_DURATION); /* preroll */ + put_be32(s, index_pos); /* index offset */ + /* computation of data the data offset */ + data_offset_ptr = s->buf_ptr; + put_be32(s, 0); /* data offset : will be patched after */ + put_be16(s, ctx->nb_streams); /* num streams */ + flags = 1 | 2; /* save allowed & perfect play */ + if (url_is_streamed(s)) + flags |= 4; /* live broadcast */ + put_be16(s, flags); + + /* comments */ + + put_tag(s,"CONT"); + size = strlen(ctx->title) + strlen(ctx->author) + strlen(ctx->copyright) + + strlen(ctx->comment) + 4 * 2 + 10; + put_be32(s,size); + put_be16(s,0); + put_str(s, ctx->title); + put_str(s, ctx->author); + put_str(s, ctx->copyright); + put_str(s, ctx->comment); + + for(i=0;i<ctx->nb_streams;i++) { + int codec_data_size; + + stream = &rm->streams[i]; + + if (stream->enc->codec_type == CODEC_TYPE_AUDIO) { + desc = "The Audio Stream"; + mimetype = "audio/x-pn-realaudio"; + codec_data_size = 73; + } else { + desc = "The Video Stream"; + mimetype = "video/x-pn-realvideo"; + codec_data_size = 34; + } + + put_tag(s,"MDPR"); + size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size; + put_be32(s, size); + put_be16(s, 0); + + put_be16(s, i); /* stream number */ + put_be32(s, stream->bit_rate); /* max bit rate */ + put_be32(s, stream->bit_rate); /* avg bit rate */ + put_be32(s, stream->packet_max_size); /* max packet size */ + if (stream->nb_packets > 0) + packet_avg_size = stream->packet_total_size / + stream->nb_packets; + else + packet_avg_size = 0; + put_be32(s, packet_avg_size); /* avg packet size */ + put_be32(s, 0); /* start time */ + put_be32(s, BUFFER_DURATION); /* preroll */ + /* duration */ + if (url_is_streamed(s) || !stream->total_frames) + put_be32(s, (int)(3600 * 1000)); + else + put_be32(s, (int)(stream->total_frames * 1000 / stream->frame_rate)); + put_str8(s, desc); + put_str8(s, mimetype); + put_be32(s, codec_data_size); + + if (stream->enc->codec_type == CODEC_TYPE_AUDIO) { + int coded_frame_size, fscode, sample_rate; + sample_rate = stream->enc->sample_rate; + coded_frame_size = (stream->enc->bit_rate * + stream->enc->frame_size) / (8 * sample_rate); + /* audio codec info */ + put_tag(s, ".ra"); + put_byte(s, 0xfd); + put_be32(s, 0x00040000); /* version */ + put_tag(s, ".ra4"); + put_be32(s, 0x01b53530); /* stream length */ + put_be16(s, 4); /* unknown */ + put_be32(s, 0x39); /* header size */ + + switch(sample_rate) { + case 48000: + case 24000: + case 12000: + fscode = 1; + break; + default: + case 44100: + case 22050: + case 11025: + fscode = 2; + break; + case 32000: + case 16000: + case 8000: + fscode = 3; + } + put_be16(s, fscode); /* codec additional info, for AC3, seems + to be a frequency code */ + /* special hack to compensate rounding errors... */ + if (coded_frame_size == 557) + coded_frame_size--; + put_be32(s, coded_frame_size); /* frame length */ + put_be32(s, 0x51540); /* unknown */ + put_be32(s, 0x249f0); /* unknown */ + put_be32(s, 0x249f0); /* unknown */ + put_be16(s, 0x01); + /* frame length : seems to be very important */ + put_be16(s, coded_frame_size); + put_be32(s, 0); /* unknown */ + put_be16(s, stream->enc->sample_rate); /* sample rate */ + put_be32(s, 0x10); /* unknown */ + put_be16(s, stream->enc->channels); + put_str8(s, "Int0"); /* codec name */ + put_str8(s, "dnet"); /* codec name */ + put_be16(s, 0); /* title length */ + put_be16(s, 0); /* author length */ + put_be16(s, 0); /* copyright length */ + put_byte(s, 0); /* end of header */ + } else { + /* video codec info */ + put_be32(s,34); /* size */ + if(stream->enc->codec_id == CODEC_ID_RV10) + put_tag(s,"VIDORV10"); + else + put_tag(s,"VIDORV20"); + put_be16(s, stream->enc->width); + put_be16(s, stream->enc->height); + put_be16(s, (int) stream->frame_rate); /* frames per seconds ? */ + put_be32(s,0); /* unknown meaning */ + put_be16(s, (int) stream->frame_rate); /* unknown meaning */ + put_be32(s,0); /* unknown meaning */ + put_be16(s, 8); /* unknown meaning */ + /* Seems to be the codec version: only use basic H263. The next + versions seems to add a diffential DC coding as in + MPEG... nothing new under the sun */ + if(stream->enc->codec_id == CODEC_ID_RV10) + put_be32(s,0x10000000); + else + put_be32(s,0x20103001); + //put_be32(s,0x10003000); + } + } + + /* patch data offset field */ + data_pos = s->buf_ptr - start_ptr; + rm->data_pos = data_pos; + data_offset_ptr[0] = data_pos >> 24; + data_offset_ptr[1] = data_pos >> 16; + data_offset_ptr[2] = data_pos >> 8; + data_offset_ptr[3] = data_pos; + + /* data stream */ + put_tag(s,"DATA"); + put_be32(s,data_size + 10 + 8); + put_be16(s,0); + + put_be32(s, nb_packets); /* number of packets */ + put_be32(s,0); /* next data header */ +} + +static void write_packet_header(AVFormatContext *ctx, StreamInfo *stream, + int length, int key_frame) +{ + int timestamp; + ByteIOContext *s = ctx->pb; + + stream->nb_packets++; + stream->packet_total_size += length; + if (length > stream->packet_max_size) + stream->packet_max_size = length; + + put_be16(s,0); /* version */ + put_be16(s,length + 12); + put_be16(s, stream->num); /* stream number */ + timestamp = (1000 * (float)stream->nb_frames) / stream->frame_rate; + put_be32(s, timestamp); /* timestamp */ + put_byte(s, 0); /* reserved */ + put_byte(s, key_frame ? 2 : 0); /* flags */ +} + +static int rm_write_header(AVFormatContext *s) +{ + RMContext *rm = s->priv_data; + StreamInfo *stream; + int n; + AVCodecContext *codec; + + for(n=0;n<s->nb_streams;n++) { + s->streams[n]->id = n; + codec = s->streams[n]->codec; + stream = &rm->streams[n]; + memset(stream, 0, sizeof(StreamInfo)); + stream->num = n; + stream->bit_rate = codec->bit_rate; + stream->enc = codec; + + switch(codec->codec_type) { + case CODEC_TYPE_AUDIO: + rm->audio_stream = stream; + stream->frame_rate = (float)codec->sample_rate / (float)codec->frame_size; + /* XXX: dummy values */ + stream->packet_max_size = 1024; + stream->nb_packets = 0; + stream->total_frames = stream->nb_packets; + break; + case CODEC_TYPE_VIDEO: + rm->video_stream = stream; + stream->frame_rate = (float)codec->time_base.den / (float)codec->time_base.num; + /* XXX: dummy values */ + stream->packet_max_size = 4096; + stream->nb_packets = 0; + stream->total_frames = stream->nb_packets; + break; + default: + return -1; + } + } + + rv10_write_header(s, 0, 0); + put_flush_packet(s->pb); + return 0; +} + +static int rm_write_audio(AVFormatContext *s, const uint8_t *buf, int size, int flags) +{ + uint8_t *buf1; + RMContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; + StreamInfo *stream = rm->audio_stream; + int i; + + /* XXX: suppress this malloc */ + buf1= (uint8_t*) av_malloc( size * sizeof(uint8_t) ); + + write_packet_header(s, stream, size, !!(flags & PKT_FLAG_KEY)); + + /* for AC3, the words seems to be reversed */ + for(i=0;i<size;i+=2) { + buf1[i] = buf[i+1]; + buf1[i+1] = buf[i]; + } + put_buffer(pb, buf1, size); + put_flush_packet(pb); + stream->nb_frames++; + av_free(buf1); + return 0; +} + +static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int flags) +{ + RMContext *rm = s->priv_data; + ByteIOContext *pb = s->pb; + StreamInfo *stream = rm->video_stream; + int key_frame = !!(flags & PKT_FLAG_KEY); + + /* XXX: this is incorrect: should be a parameter */ + + /* Well, I spent some time finding the meaning of these bits. I am + not sure I understood everything, but it works !! */ +#if 1 + write_packet_header(s, stream, size + 7 + (size >= 0x4000)*4, key_frame); + /* bit 7: '1' if final packet of a frame converted in several packets */ + put_byte(pb, 0x81); + /* bit 7: '1' if I frame. bits 6..0 : sequence number in current + frame starting from 1 */ + if (key_frame) { + put_byte(pb, 0x81); + } else { + put_byte(pb, 0x01); + } + if(size >= 0x4000){ + put_be32(pb, size); /* total frame size */ + put_be32(pb, size); /* offset from the start or the end */ + }else{ + put_be16(pb, 0x4000 | size); /* total frame size */ + put_be16(pb, 0x4000 | size); /* offset from the start or the end */ + } +#else + /* full frame */ + write_packet_header(s, size + 6); + put_byte(pb, 0xc0); + put_be16(pb, 0x4000 + size); /* total frame size */ + put_be16(pb, 0x4000 + packet_number * 126); /* position in stream */ +#endif + put_byte(pb, stream->nb_frames & 0xff); + + put_buffer(pb, buf, size); + put_flush_packet(pb); + + stream->nb_frames++; + return 0; +} + +static int rm_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + if (s->streams[pkt->stream_index]->codec->codec_type == + CODEC_TYPE_AUDIO) + return rm_write_audio(s, pkt->data, pkt->size, pkt->flags); + else + return rm_write_video(s, pkt->data, pkt->size, pkt->flags); +} + +static int rm_write_trailer(AVFormatContext *s) +{ + RMContext *rm = s->priv_data; + int data_size, index_pos, i; + ByteIOContext *pb = s->pb; + + if (!url_is_streamed(s->pb)) { + /* end of file: finish to write header */ + index_pos = url_fseek(pb, 0, SEEK_CUR); + data_size = index_pos - rm->data_pos; + + /* index */ + put_tag(pb, "INDX"); + put_be32(pb, 10 + 10 * s->nb_streams); + put_be16(pb, 0); + + for(i=0;i<s->nb_streams;i++) { + put_be32(pb, 0); /* zero indices */ + put_be16(pb, i); /* stream number */ + put_be32(pb, 0); /* next index */ + } + /* undocumented end header */ + put_be32(pb, 0); + put_be32(pb, 0); + + url_fseek(pb, 0, SEEK_SET); + for(i=0;i<s->nb_streams;i++) + rm->streams[i].total_frames = rm->streams[i].nb_frames; + rv10_write_header(s, data_size, index_pos); + } else { + /* undocumented end header */ + put_be32(pb, 0); + put_be32(pb, 0); + } + put_flush_packet(pb); + return 0; +} + + +AVOutputFormat rm_muxer = { + "rm", + "rm format", + "application/vnd.rn-realmedia", + "rm,ra", + sizeof(RMContext), + CODEC_ID_AC3, + CODEC_ID_RV10, + rm_write_header, + rm_write_packet, + rm_write_trailer, +}; diff --git a/contrib/ffmpeg/libavformat/rtp.c b/contrib/ffmpeg/libavformat/rtp.c index 493a89cf3..6b038c825 100644 --- a/contrib/ffmpeg/libavformat/rtp.c +++ b/contrib/ffmpeg/libavformat/rtp.c @@ -19,29 +19,25 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "mpegts.h" #include "bitstream.h" #include <unistd.h> #include "network.h" #include "rtp_internal.h" -#include "rtp_h264.h" //#define DEBUG - -/* TODO: - add RTCP statistics reporting (should be optional). - - - add support for h263/mpeg4 packetized output : IDEA: send a - buffer to 'rtp_write_packet' contains all the packets for ONE - frame. Each packet should have a four byte header containing - the length in big endian format (same trick as - 'url_open_dyn_packet_buf') -*/ - /* from http://www.iana.org/assignments/rtp-parameters last updated 05 January 2005 */ -AVRtpPayloadType_t AVRtpPayloadTypes[]= +static const struct +{ + int pt; + const char enc_name[50]; /* XXX: why 50 ? */ + enum CodecType codec_type; + enum CodecID codec_id; + int clock_rate; + int audio_channels; +} AVRtpPayloadTypes[]= { {0, "PCMU", CODEC_TYPE_AUDIO, CODEC_ID_PCM_MULAW, 8000, 1}, {1, "Reserved", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, @@ -76,6 +72,7 @@ AVRtpPayloadType_t AVRtpPayloadTypes[]= {30, "unassigned", CODEC_TYPE_VIDEO, CODEC_ID_NONE, -1, -1}, {31, "H261", CODEC_TYPE_VIDEO, CODEC_ID_H261, 90000, -1}, {32, "MPV", CODEC_TYPE_VIDEO, CODEC_ID_MPEG1VIDEO, 90000, -1}, + {32, "MPV", CODEC_TYPE_VIDEO, CODEC_ID_MPEG2VIDEO, 90000, -1}, {33, "MP2T", CODEC_TYPE_DATA, CODEC_ID_MPEG2TS, 90000, -1}, {34, "H263", CODEC_TYPE_VIDEO, CODEC_ID_H263, 90000, -1}, {35, "unassigned", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1}, @@ -174,36 +171,22 @@ AVRtpPayloadType_t AVRtpPayloadTypes[]= {-1, "", CODEC_TYPE_UNKNOWN, CODEC_ID_NONE, -1, -1} }; -/* statistics functions */ -RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler= NULL; - -static RTPDynamicProtocolHandler mp4v_es_handler= {"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4}; -static RTPDynamicProtocolHandler mpeg4_generic_handler= {"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_AAC}; - -static void register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) -{ - handler->next= RTPFirstDynamicPayloadHandler; - RTPFirstDynamicPayloadHandler= handler; -} - -void av_register_rtp_dynamic_payload_handlers() -{ - register_dynamic_payload_handler(&mp4v_es_handler); - register_dynamic_payload_handler(&mpeg4_generic_handler); - register_dynamic_payload_handler(&ff_h264_dynamic_handler); -} - int rtp_get_codec_info(AVCodecContext *codec, int payload_type) { - if (AVRtpPayloadTypes[payload_type].codec_id != CODEC_ID_NONE) { - codec->codec_type = AVRtpPayloadTypes[payload_type].codec_type; - codec->codec_id = AVRtpPayloadTypes[payload_type].codec_id; - if (AVRtpPayloadTypes[payload_type].audio_channels > 0) - codec->channels = AVRtpPayloadTypes[payload_type].audio_channels; - if (AVRtpPayloadTypes[payload_type].clock_rate > 0) - codec->sample_rate = AVRtpPayloadTypes[payload_type].clock_rate; - return 0; - } + int i = 0; + + for (i = 0; AVRtpPayloadTypes[i].pt >= 0; i++) + if (AVRtpPayloadTypes[i].pt == payload_type) { + if (AVRtpPayloadTypes[i].codec_id != CODEC_ID_NONE) { + codec->codec_type = AVRtpPayloadTypes[i].codec_type; + codec->codec_id = AVRtpPayloadTypes[i].codec_id; + if (AVRtpPayloadTypes[i].audio_channels > 0) + codec->channels = AVRtpPayloadTypes[i].audio_channels; + if (AVRtpPayloadTypes[i].clock_rate > 0) + codec->sample_rate = AVRtpPayloadTypes[i].clock_rate; + return 0; + } + } return -1; } @@ -222,864 +205,26 @@ int rtp_get_payload_type(AVCodecContext *codec) return payload_type; } -static inline uint32_t decode_be32(const uint8_t *p) -{ - return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; -} - -static inline uint64_t decode_be64(const uint8_t *p) -{ - return ((uint64_t)decode_be32(p) << 32) | decode_be32(p + 4); -} - -static int rtcp_parse_packet(RTPDemuxContext *s, const unsigned char *buf, int len) -{ - if (buf[1] != 200) - return -1; - s->last_rtcp_ntp_time = decode_be64(buf + 8); - if (s->first_rtcp_ntp_time == AV_NOPTS_VALUE) - s->first_rtcp_ntp_time = s->last_rtcp_ntp_time; - s->last_rtcp_timestamp = decode_be32(buf + 16); - return 0; -} - -#define RTP_SEQ_MOD (1<<16) - -/** -* called on parse open packet -*/ -static void rtp_init_statistics(RTPStatistics *s, uint16_t base_sequence) // called on parse open packet. -{ - memset(s, 0, sizeof(RTPStatistics)); - s->max_seq= base_sequence; - s->probation= 1; -} - -/** -* called whenever there is a large jump in sequence numbers, or when they get out of probation... -*/ -static void rtp_init_sequence(RTPStatistics *s, uint16_t seq) -{ - s->max_seq= seq; - s->cycles= 0; - s->base_seq= seq -1; - s->bad_seq= RTP_SEQ_MOD + 1; - s->received= 0; - s->expected_prior= 0; - s->received_prior= 0; - s->jitter= 0; - s->transit= 0; -} - -/** -* returns 1 if we should handle this packet. -*/ -static int rtp_valid_packet_in_sequence(RTPStatistics *s, uint16_t seq) -{ - uint16_t udelta= seq - s->max_seq; - const int MAX_DROPOUT= 3000; - const int MAX_MISORDER = 100; - const int MIN_SEQUENTIAL = 2; - - /* source not valid until MIN_SEQUENTIAL packets with sequence seq. numbers have been received */ - if(s->probation) - { - if(seq==s->max_seq + 1) { - s->probation--; - s->max_seq= seq; - if(s->probation==0) { - rtp_init_sequence(s, seq); - s->received++; - return 1; - } - } else { - s->probation= MIN_SEQUENTIAL - 1; - s->max_seq = seq; - } - } else if (udelta < MAX_DROPOUT) { - // in order, with permissible gap - if(seq < s->max_seq) { - //sequence number wrapped; count antother 64k cycles - s->cycles += RTP_SEQ_MOD; - } - s->max_seq= seq; - } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { - // sequence made a large jump... - if(seq==s->bad_seq) { - // two sequential packets-- assume that the other side restarted without telling us; just resync. - rtp_init_sequence(s, seq); - } else { - s->bad_seq= (seq + 1) & (RTP_SEQ_MOD-1); - return 0; - } - } else { - // duplicate or reordered packet... - } - s->received++; - return 1; -} - -#if 0 -/** -* This function is currently unused; without a valid local ntp time, I don't see how we could calculate the -* difference between the arrival and sent timestamp. As a result, the jitter and transit statistics values -* never change. I left this in in case someone else can see a way. (rdm) -*/ -static void rtcp_update_jitter(RTPStatistics *s, uint32_t sent_timestamp, uint32_t arrival_timestamp) -{ - uint32_t transit= arrival_timestamp - sent_timestamp; - int d; - s->transit= transit; - d= FFABS(transit - s->transit); - s->jitter += d - ((s->jitter + 8)>>4); -} -#endif - -int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count) -{ - ByteIOContext pb; - uint8_t *buf; - int len; - int rtcp_bytes; - RTPStatistics *stats= &s->statistics; - uint32_t lost; - uint32_t extended_max; - uint32_t expected_interval; - uint32_t received_interval; - uint32_t lost_interval; - uint32_t expected; - uint32_t fraction; - uint64_t ntp_time= s->last_rtcp_ntp_time; // TODO: Get local ntp time? - - if (!s->rtp_ctx || (count < 1)) - return -1; - - /* TODO: I think this is way too often; RFC 1889 has algorithm for this */ - /* XXX: mpeg pts hardcoded. RTCP send every 0.5 seconds */ - s->octet_count += count; - rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) / - RTCP_TX_RATIO_DEN; - rtcp_bytes /= 50; // mmu_man: that's enough for me... VLC sends much less btw !? - if (rtcp_bytes < 28) - return -1; - s->last_octet_count = s->octet_count; - - if (url_open_dyn_buf(&pb) < 0) - return -1; - - // Receiver Report - put_byte(&pb, (RTP_VERSION << 6) + 1); /* 1 report block */ - put_byte(&pb, 201); - put_be16(&pb, 7); /* length in words - 1 */ - put_be32(&pb, s->ssrc); // our own SSRC - put_be32(&pb, s->ssrc); // XXX: should be the server's here! - // some placeholders we should really fill... - // RFC 1889/p64 - extended_max= stats->cycles + stats->max_seq; - expected= extended_max - stats->base_seq + 1; - lost= expected - stats->received; - lost= FFMIN(lost, 0xffffff); // clamp it since it's only 24 bits... - expected_interval= expected - stats->expected_prior; - stats->expected_prior= expected; - received_interval= stats->received - stats->received_prior; - stats->received_prior= stats->received; - lost_interval= expected_interval - received_interval; - if (expected_interval==0 || lost_interval<=0) fraction= 0; - else fraction = (lost_interval<<8)/expected_interval; - - fraction= (fraction<<24) | lost; - - put_be32(&pb, fraction); /* 8 bits of fraction, 24 bits of total packets lost */ - put_be32(&pb, extended_max); /* max sequence received */ - put_be32(&pb, stats->jitter>>4); /* jitter */ - - if(s->last_rtcp_ntp_time==AV_NOPTS_VALUE) - { - put_be32(&pb, 0); /* last SR timestamp */ - put_be32(&pb, 0); /* delay since last SR */ - } else { - uint32_t middle_32_bits= s->last_rtcp_ntp_time>>16; // this is valid, right? do we need to handle 64 bit values special? - uint32_t delay_since_last= ntp_time - s->last_rtcp_ntp_time; - - put_be32(&pb, middle_32_bits); /* last SR timestamp */ - put_be32(&pb, delay_since_last); /* delay since last SR */ - } - - // CNAME - put_byte(&pb, (RTP_VERSION << 6) + 1); /* 1 report block */ - put_byte(&pb, 202); - len = strlen(s->hostname); - put_be16(&pb, (6 + len + 3) / 4); /* length in words - 1 */ - put_be32(&pb, s->ssrc); - put_byte(&pb, 0x01); - put_byte(&pb, len); - put_buffer(&pb, s->hostname, len); - // padding - for (len = (6 + len) % 4; len % 4; len++) { - put_byte(&pb, 0); - } - - put_flush_packet(&pb); - len = url_close_dyn_buf(&pb, &buf); - if ((len > 0) && buf) { - int result; -#if defined(DEBUG) - printf("sending %d bytes of RR\n", len); -#endif - result= url_write(s->rtp_ctx, buf, len); -#if defined(DEBUG) - printf("result from url_write: %d\n", result); -#endif - av_free(buf); - } - return 0; -} - -/** - * open a new RTP parse context for stream 'st'. 'st' can be NULL for - * MPEG2TS streams to indicate that they should be demuxed inside the - * rtp demux (otherwise CODEC_ID_MPEG2TS packets are returned) - * TODO: change this to not take rtp_payload data, and use the new dynamic payload system. - */ -RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_t *rtp_payload_data) -{ - RTPDemuxContext *s; - - s = av_mallocz(sizeof(RTPDemuxContext)); - if (!s) - return NULL; - s->payload_type = payload_type; - s->last_rtcp_ntp_time = AV_NOPTS_VALUE; - s->first_rtcp_ntp_time = AV_NOPTS_VALUE; - s->ic = s1; - s->st = st; - s->rtp_payload_data = rtp_payload_data; - rtp_init_statistics(&s->statistics, 0); // do we know the initial sequence from sdp? - if (!strcmp(AVRtpPayloadTypes[payload_type].enc_name, "MP2T")) { - s->ts = mpegts_parse_open(s->ic); - if (s->ts == NULL) { - av_free(s); - return NULL; - } - } else { - switch(st->codec->codec_id) { - case CODEC_ID_MPEG1VIDEO: - case CODEC_ID_MPEG2VIDEO: - case CODEC_ID_MP2: - case CODEC_ID_MP3: - case CODEC_ID_MPEG4: - case CODEC_ID_H264: - st->need_parsing = 1; - break; - default: - break; - } - } - // needed to send back RTCP RR in RTSP sessions - s->rtp_ctx = rtpc; - gethostname(s->hostname, sizeof(s->hostname)); - return s; -} - -static int rtp_parse_mp4_au(RTPDemuxContext *s, const uint8_t *buf) -{ - int au_headers_length, au_header_size, i; - GetBitContext getbitcontext; - rtp_payload_data_t *infos; - - infos = s->rtp_payload_data; - - if (infos == NULL) - return -1; - - /* decode the first 2 bytes where are stored the AUHeader sections - length in bits */ - au_headers_length = AV_RB16(buf); - - if (au_headers_length > RTP_MAX_PACKET_LENGTH) - return -1; - - infos->au_headers_length_bytes = (au_headers_length + 7) / 8; - - /* skip AU headers length section (2 bytes) */ - buf += 2; - - init_get_bits(&getbitcontext, buf, infos->au_headers_length_bytes * 8); - - /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */ - au_header_size = infos->sizelength + infos->indexlength; - if (au_header_size <= 0 || (au_headers_length % au_header_size != 0)) - return -1; - - infos->nb_au_headers = au_headers_length / au_header_size; - infos->au_headers = av_malloc(sizeof(struct AUHeaders) * infos->nb_au_headers); - - /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving) - In my test, the faad decoder doesnt behave correctly when sending each AU one by one - but does when sending the whole as one big packet... */ - infos->au_headers[0].size = 0; - infos->au_headers[0].index = 0; - for (i = 0; i < infos->nb_au_headers; ++i) { - infos->au_headers[0].size += get_bits_long(&getbitcontext, infos->sizelength); - infos->au_headers[0].index = get_bits_long(&getbitcontext, infos->indexlength); - } - - infos->nb_au_headers = 1; - - return 0; -} - -/** - * This was the second switch in rtp_parse packet. Normalizes time, if required, sets stream_index, etc. - */ -static void finalize_packet(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestamp) -{ - switch(s->st->codec->codec_id) { - case CODEC_ID_MP2: - case CODEC_ID_MPEG1VIDEO: - if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) { - int64_t addend; - - int delta_timestamp; - /* XXX: is it really necessary to unify the timestamp base ? */ - /* compute pts from timestamp with received ntp_time */ - delta_timestamp = timestamp - s->last_rtcp_timestamp; - /* convert to 90 kHz without overflow */ - addend = (s->last_rtcp_ntp_time - s->first_rtcp_ntp_time) >> 14; - addend = (addend * 5625) >> 14; - pkt->pts = addend + delta_timestamp; - } - break; - case CODEC_ID_AAC: - case CODEC_ID_H264: - case CODEC_ID_MPEG4: - pkt->pts = timestamp; - break; - default: - /* no timestamp info yet */ - break; - } - pkt->stream_index = s->st->index; -} - -/** - * Parse an RTP or RTCP packet directly sent as a buffer. - * @param s RTP parse context. - * @param pkt returned packet - * @param buf input buffer or NULL to read the next packets - * @param len buffer len - * @return 0 if a packet is returned, 1 if a packet is returned and more can follow - * (use buf as NULL to read the next). -1 if no packet (error or no more packet). - */ -int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, - const uint8_t *buf, int len) -{ - unsigned int ssrc, h; - int payload_type, seq, ret; - AVStream *st; - uint32_t timestamp; - int rv= 0; - - if (!buf) { - /* return the next packets, if any */ - if(s->st && s->parse_packet) { - timestamp= 0; ///< Should not be used if buf is NULL, but should be set to the timestamp of the packet returned.... - rv= s->parse_packet(s, pkt, ×tamp, NULL, 0); - finalize_packet(s, pkt, timestamp); - return rv; - } else { - // TODO: Move to a dynamic packet handler (like above) - if (s->read_buf_index >= s->read_buf_size) - return -1; - ret = mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index, - s->read_buf_size - s->read_buf_index); - if (ret < 0) - return -1; - s->read_buf_index += ret; - if (s->read_buf_index < s->read_buf_size) - return 1; - else - return 0; - } - } - - if (len < 12) - return -1; - - if ((buf[0] & 0xc0) != (RTP_VERSION << 6)) - return -1; - if (buf[1] >= 200 && buf[1] <= 204) { - rtcp_parse_packet(s, buf, len); - return -1; - } - payload_type = buf[1] & 0x7f; - seq = (buf[2] << 8) | buf[3]; - timestamp = decode_be32(buf + 4); - ssrc = decode_be32(buf + 8); - /* store the ssrc in the RTPDemuxContext */ - s->ssrc = ssrc; - - /* NOTE: we can handle only one payload type */ - if (s->payload_type != payload_type) - return -1; - - st = s->st; - // only do something with this if all the rtp checks pass... - if(!rtp_valid_packet_in_sequence(&s->statistics, seq)) - { - av_log(st?st->codec:NULL, AV_LOG_ERROR, "RTP: PT=%02x: bad cseq %04x expected=%04x\n", - payload_type, seq, ((s->seq + 1) & 0xffff)); - return -1; - } - - s->seq = seq; - len -= 12; - buf += 12; - - if (!st) { - /* specific MPEG2TS demux support */ - ret = mpegts_parse_packet(s->ts, pkt, buf, len); - if (ret < 0) - return -1; - if (ret < len) { - s->read_buf_size = len - ret; - memcpy(s->buf, buf + ret, s->read_buf_size); - s->read_buf_index = 0; - return 1; - } - } else { - // at this point, the RTP header has been stripped; This is ASSUMING that there is only 1 CSRC, which in't wise. - switch(st->codec->codec_id) { - case CODEC_ID_MP2: - /* better than nothing: skip mpeg audio RTP header */ - if (len <= 4) - return -1; - h = decode_be32(buf); - len -= 4; - buf += 4; - av_new_packet(pkt, len); - memcpy(pkt->data, buf, len); - break; - case CODEC_ID_MPEG1VIDEO: - /* better than nothing: skip mpeg video RTP header */ - if (len <= 4) - return -1; - h = decode_be32(buf); - buf += 4; - len -= 4; - if (h & (1 << 26)) { - /* mpeg2 */ - if (len <= 4) - return -1; - buf += 4; - len -= 4; - } - av_new_packet(pkt, len); - memcpy(pkt->data, buf, len); - break; - // moved from below, verbatim. this is because this section handles packets, and the lower switch handles - // timestamps. - // TODO: Put this into a dynamic packet handler... - case CODEC_ID_AAC: - if (rtp_parse_mp4_au(s, buf)) - return -1; - { - rtp_payload_data_t *infos = s->rtp_payload_data; - if (infos == NULL) - return -1; - buf += infos->au_headers_length_bytes + 2; - len -= infos->au_headers_length_bytes + 2; - - /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define - one au_header */ - av_new_packet(pkt, infos->au_headers[0].size); - memcpy(pkt->data, buf, infos->au_headers[0].size); - buf += infos->au_headers[0].size; - len -= infos->au_headers[0].size; - } - s->read_buf_size = len; - s->buf_ptr = buf; - rv= 0; - break; - default: - if(s->parse_packet) { - rv= s->parse_packet(s, pkt, ×tamp, buf, len); - } else { - av_new_packet(pkt, len); - memcpy(pkt->data, buf, len); - } - break; - } - - // now perform timestamp things.... - finalize_packet(s, pkt, timestamp); - } - return rv; -} - -void rtp_parse_close(RTPDemuxContext *s) -{ - // TODO: fold this into the protocol specific data fields. - if (!strcmp(AVRtpPayloadTypes[s->payload_type].enc_name, "MP2T")) { - mpegts_parse_close(s->ts); - } - av_free(s); -} - -/* rtp output */ - -static int rtp_write_header(AVFormatContext *s1) -{ - RTPDemuxContext *s = s1->priv_data; - int payload_type, max_packet_size, n; - AVStream *st; - - if (s1->nb_streams != 1) - return -1; - st = s1->streams[0]; - - payload_type = rtp_get_payload_type(st->codec); - if (payload_type < 0) - payload_type = RTP_PT_PRIVATE; /* private payload type */ - s->payload_type = payload_type; - -// following 2 FIXMies could be set based on the current time, theres normaly no info leak, as rtp will likely be transmitted immedeatly - s->base_timestamp = 0; /* FIXME: was random(), what should this be? */ - s->timestamp = s->base_timestamp; - s->ssrc = 0; /* FIXME: was random(), what should this be? */ - s->first_packet = 1; - - max_packet_size = url_fget_max_packet_size(&s1->pb); - if (max_packet_size <= 12) - return AVERROR_IO; - s->max_payload_size = max_packet_size - 12; - - switch(st->codec->codec_id) { - case CODEC_ID_MP2: - case CODEC_ID_MP3: - s->buf_ptr = s->buf + 4; - s->cur_timestamp = 0; - break; - case CODEC_ID_MPEG1VIDEO: - s->cur_timestamp = 0; - break; - case CODEC_ID_MPEG2TS: - n = s->max_payload_size / TS_PACKET_SIZE; - if (n < 1) - n = 1; - s->max_payload_size = n * TS_PACKET_SIZE; - s->buf_ptr = s->buf; - break; - default: - s->buf_ptr = s->buf; - break; - } - - return 0; -} - -/* send an rtcp sender report packet */ -static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time) -{ - RTPDemuxContext *s = s1->priv_data; -#if defined(DEBUG) - printf("RTCP: %02x %"PRIx64" %x\n", s->payload_type, ntp_time, s->timestamp); -#endif - put_byte(&s1->pb, (RTP_VERSION << 6)); - put_byte(&s1->pb, 200); - put_be16(&s1->pb, 6); /* length in words - 1 */ - put_be32(&s1->pb, s->ssrc); - put_be64(&s1->pb, ntp_time); - put_be32(&s1->pb, s->timestamp); - put_be32(&s1->pb, s->packet_count); - put_be32(&s1->pb, s->octet_count); - put_flush_packet(&s1->pb); -} - -/* send an rtp packet. sequence number is incremented, but the caller - must update the timestamp itself */ -static void rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m) -{ - RTPDemuxContext *s = s1->priv_data; - -#ifdef DEBUG - printf("rtp_send_data size=%d\n", len); -#endif - - /* build the RTP header */ - put_byte(&s1->pb, (RTP_VERSION << 6)); - put_byte(&s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7)); - put_be16(&s1->pb, s->seq); - put_be32(&s1->pb, s->timestamp); - put_be32(&s1->pb, s->ssrc); - - put_buffer(&s1->pb, buf1, len); - put_flush_packet(&s1->pb); - - s->seq++; - s->octet_count += len; - s->packet_count++; -} - -/* send an integer number of samples and compute time stamp and fill - the rtp send buffer before sending. */ -static void rtp_send_samples(AVFormatContext *s1, - const uint8_t *buf1, int size, int sample_size) +const char *ff_rtp_enc_name(int payload_type) { - RTPDemuxContext *s = s1->priv_data; - int len, max_packet_size, n; + int i; - max_packet_size = (s->max_payload_size / sample_size) * sample_size; - /* not needed, but who nows */ - if ((size % sample_size) != 0) - av_abort(); - while (size > 0) { - len = (max_packet_size - (s->buf_ptr - s->buf)); - if (len > size) - len = size; - - /* copy data */ - memcpy(s->buf_ptr, buf1, len); - s->buf_ptr += len; - buf1 += len; - size -= len; - n = (s->buf_ptr - s->buf); - /* if buffer full, then send it */ - if (n >= max_packet_size) { - rtp_send_data(s1, s->buf, n, 0); - s->buf_ptr = s->buf; - /* update timestamp */ - s->timestamp += n / sample_size; + for (i = 0; AVRtpPayloadTypes[i].pt >= 0; i++) + if (AVRtpPayloadTypes[i].pt == payload_type) { + return AVRtpPayloadTypes[i].enc_name; } - } -} -/* NOTE: we suppose that exactly one frame is given as argument here */ -/* XXX: test it */ -static void rtp_send_mpegaudio(AVFormatContext *s1, - const uint8_t *buf1, int size) -{ - RTPDemuxContext *s = s1->priv_data; - AVStream *st = s1->streams[0]; - int len, count, max_packet_size; - - max_packet_size = s->max_payload_size; - - /* test if we must flush because not enough space */ - len = (s->buf_ptr - s->buf); - if ((len + size) > max_packet_size) { - if (len > 4) { - rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 0); - s->buf_ptr = s->buf + 4; - /* 90 KHz time stamp */ - s->timestamp = s->base_timestamp + - (s->cur_timestamp * 90000LL) / st->codec->sample_rate; - } - } - - /* add the packet */ - if (size > max_packet_size) { - /* big packet: fragment */ - count = 0; - while (size > 0) { - len = max_packet_size - 4; - if (len > size) - len = size; - /* build fragmented packet */ - s->buf[0] = 0; - s->buf[1] = 0; - s->buf[2] = count >> 8; - s->buf[3] = count; - memcpy(s->buf + 4, buf1, len); - rtp_send_data(s1, s->buf, len + 4, 0); - size -= len; - buf1 += len; - count += len; - } - } else { - if (s->buf_ptr == s->buf + 4) { - /* no fragmentation possible */ - s->buf[0] = 0; - s->buf[1] = 0; - s->buf[2] = 0; - s->buf[3] = 0; - } - memcpy(s->buf_ptr, buf1, size); - s->buf_ptr += size; - } - s->cur_timestamp += st->codec->frame_size; + return ""; } -/* NOTE: a single frame must be passed with sequence header if - needed. XXX: use slices. */ -static void rtp_send_mpegvideo(AVFormatContext *s1, - const uint8_t *buf1, int size) +enum CodecID ff_rtp_codec_id(const char *buf, enum CodecType codec_type) { - RTPDemuxContext *s = s1->priv_data; - AVStream *st = s1->streams[0]; - int len, h, max_packet_size; - uint8_t *q; - - max_packet_size = s->max_payload_size; - - while (size > 0) { - /* XXX: more correct headers */ - h = 0; - if (st->codec->sub_id == 2) - h |= 1 << 26; /* mpeg 2 indicator */ - q = s->buf; - *q++ = h >> 24; - *q++ = h >> 16; - *q++ = h >> 8; - *q++ = h; + int i; - if (st->codec->sub_id == 2) { - h = 0; - *q++ = h >> 24; - *q++ = h >> 16; - *q++ = h >> 8; - *q++ = h; + for (i = 0; AVRtpPayloadTypes[i].pt >= 0; i++) + if (!strcmp(buf, AVRtpPayloadTypes[i].enc_name) && (codec_type == AVRtpPayloadTypes[i].codec_type)){ + return AVRtpPayloadTypes[i].codec_id; } - len = max_packet_size - (q - s->buf); - if (len > size) - len = size; - - memcpy(q, buf1, len); - q += len; - - /* 90 KHz time stamp */ - s->timestamp = s->base_timestamp + - av_rescale((int64_t)s->cur_timestamp * st->codec->time_base.num, 90000, st->codec->time_base.den); //FIXME pass timestamps - rtp_send_data(s1, s->buf, q - s->buf, (len == size)); - - buf1 += len; - size -= len; - } - s->cur_timestamp++; + return CODEC_ID_NONE; } - -static void rtp_send_raw(AVFormatContext *s1, - const uint8_t *buf1, int size) -{ - RTPDemuxContext *s = s1->priv_data; - AVStream *st = s1->streams[0]; - int len, max_packet_size; - - max_packet_size = s->max_payload_size; - - while (size > 0) { - len = max_packet_size; - if (len > size) - len = size; - - /* 90 KHz time stamp */ - s->timestamp = s->base_timestamp + - av_rescale((int64_t)s->cur_timestamp * st->codec->time_base.num, 90000, st->codec->time_base.den); //FIXME pass timestamps - rtp_send_data(s1, buf1, len, (len == size)); - - buf1 += len; - size -= len; - } - s->cur_timestamp++; -} - -/* NOTE: size is assumed to be an integer multiple of TS_PACKET_SIZE */ -static void rtp_send_mpegts_raw(AVFormatContext *s1, - const uint8_t *buf1, int size) -{ - RTPDemuxContext *s = s1->priv_data; - int len, out_len; - - while (size >= TS_PACKET_SIZE) { - len = s->max_payload_size - (s->buf_ptr - s->buf); - if (len > size) - len = size; - memcpy(s->buf_ptr, buf1, len); - buf1 += len; - size -= len; - s->buf_ptr += len; - - out_len = s->buf_ptr - s->buf; - if (out_len >= s->max_payload_size) { - rtp_send_data(s1, s->buf, out_len, 0); - s->buf_ptr = s->buf; - } - } -} - -/* write an RTP packet. 'buf1' must contain a single specific frame. */ -static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) -{ - RTPDemuxContext *s = s1->priv_data; - AVStream *st = s1->streams[0]; - int rtcp_bytes; - int64_t ntp_time; - int size= pkt->size; - uint8_t *buf1= pkt->data; - -#ifdef DEBUG - printf("%d: write len=%d\n", pkt->stream_index, size); -#endif - - /* XXX: mpeg pts hardcoded. RTCP send every 0.5 seconds */ - rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) / - RTCP_TX_RATIO_DEN; - if (s->first_packet || rtcp_bytes >= 28) { - /* compute NTP time */ - /* XXX: 90 kHz timestamp hardcoded */ - ntp_time = (pkt->pts << 28) / 5625; - rtcp_send_sr(s1, ntp_time); - s->last_octet_count = s->octet_count; - s->first_packet = 0; - } - - switch(st->codec->codec_id) { - case CODEC_ID_PCM_MULAW: - case CODEC_ID_PCM_ALAW: - case CODEC_ID_PCM_U8: - case CODEC_ID_PCM_S8: - rtp_send_samples(s1, buf1, size, 1 * st->codec->channels); - break; - case CODEC_ID_PCM_U16BE: - case CODEC_ID_PCM_U16LE: - case CODEC_ID_PCM_S16BE: - case CODEC_ID_PCM_S16LE: - rtp_send_samples(s1, buf1, size, 2 * st->codec->channels); - break; - case CODEC_ID_MP2: - case CODEC_ID_MP3: - rtp_send_mpegaudio(s1, buf1, size); - break; - case CODEC_ID_MPEG1VIDEO: - rtp_send_mpegvideo(s1, buf1, size); - break; - case CODEC_ID_MPEG2TS: - rtp_send_mpegts_raw(s1, buf1, size); - break; - default: - /* better than nothing : send the codec raw data */ - rtp_send_raw(s1, buf1, size); - break; - } - return 0; -} - -static int rtp_write_trailer(AVFormatContext *s1) -{ - // RTPDemuxContext *s = s1->priv_data; - return 0; -} - -AVOutputFormat rtp_muxer = { - "rtp", - "RTP output format", - NULL, - NULL, - sizeof(RTPDemuxContext), - CODEC_ID_PCM_MULAW, - CODEC_ID_NONE, - rtp_write_header, - rtp_write_packet, - rtp_write_trailer, -}; diff --git a/contrib/ffmpeg/libavformat/rtp.h b/contrib/ffmpeg/libavformat/rtp.h index fec763051..21cfdb4cf 100644 --- a/contrib/ffmpeg/libavformat/rtp.h +++ b/contrib/ffmpeg/libavformat/rtp.h @@ -18,13 +18,15 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef RTP_H -#define RTP_H +#ifndef FFMPEG_RTP_H +#define FFMPEG_RTP_H + +#include "avcodec.h" +#include "avformat.h" #define RTP_MIN_PACKET_LENGTH 12 #define RTP_MAX_PACKET_LENGTH 1500 /* XXX: suppress this define */ -int rtp_init(void); int rtp_get_codec_info(AVCodecContext *codec, int payload_type); /** return < 0 if unknown payload type */ @@ -37,9 +39,6 @@ int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, const uint8_t *buf, int len); void rtp_parse_close(RTPDemuxContext *s); -extern AVOutputFormat rtp_muxer; -extern AVInputFormat rtp_demuxer; - int rtp_get_local_port(URLContext *h); int rtp_set_remote_url(URLContext *h, const char *uri); void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd); @@ -51,8 +50,6 @@ void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd); */ int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count); -extern URLProtocol rtp_protocol; - #define RTP_PT_PRIVATE 96 #define RTP_VERSION 2 #define RTP_MAX_SDES 256 /**< maximum text length for SDES */ @@ -88,16 +85,6 @@ typedef struct rtp_payload_data_s int cur_au_index; } rtp_payload_data_t; -typedef struct AVRtpPayloadType_s -{ - int pt; - const char enc_name[50]; /* XXX: why 50 ? */ - enum CodecType codec_type; - enum CodecID codec_id; - int clock_rate; - int audio_channels; -} AVRtpPayloadType_t; - #if 0 typedef enum { RTCP_SR = 200, @@ -123,5 +110,4 @@ typedef enum { } rtcp_sdes_type_t; #endif -extern AVRtpPayloadType_t AVRtpPayloadTypes[]; -#endif /* RTP_H */ +#endif /* FFMPEG_RTP_H */ diff --git a/contrib/ffmpeg/libavformat/rtp_aac.c b/contrib/ffmpeg/libavformat/rtp_aac.c new file mode 100644 index 000000000..4cd8e129d --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtp_aac.c @@ -0,0 +1,88 @@ +/* + * copyright (c) 2007 Luca Abeni + * + * 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 "rtp_aac.h" +#include "rtp_internal.h" + +#define MAX_FRAMES_PER_PACKET (s->max_frames_per_packet ? s->max_frames_per_packet : 5) +#define MAX_AU_HEADERS_SIZE (2 + 2 * MAX_FRAMES_PER_PACKET) + +void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size) +{ + RTPDemuxContext *s = s1->priv_data; + int len, max_packet_size; + uint8_t *p; + + /* skip ADTS header, if present */ + if ((s1->streams[0]->codec->extradata_size) == 0) { + size -= 7; + buff += 7; + } + max_packet_size = s->max_payload_size - MAX_AU_HEADERS_SIZE; + + /* test if the packet must be sent */ + len = (s->buf_ptr - s->buf); + if ((s->read_buf_index == MAX_FRAMES_PER_PACKET) || (len && (len + size) > max_packet_size)) { + int au_size = s->read_buf_index * 2; + + p = s->buf + MAX_AU_HEADERS_SIZE - au_size - 2; + if (p != s->buf) { + memmove(p + 2, s->buf + 2, au_size); + } + /* Write the AU header size */ + p[0] = ((au_size * 8) & 0xFF) >> 8; + p[1] = (au_size * 8) & 0xFF; + + ff_rtp_send_data(s1, p, s->buf_ptr - p, 1); + + s->read_buf_index = 0; + } + if (s->read_buf_index == 0) { + s->buf_ptr = s->buf + MAX_AU_HEADERS_SIZE; + s->timestamp = s->cur_timestamp; + } + + if (size < max_packet_size) { + p = s->buf + s->read_buf_index++ * 2 + 2; + *p++ = size >> 5; + *p = (size & 0x1F) << 3; + memcpy(s->buf_ptr, buff, size); + s->buf_ptr += size; + } else { + if (s->buf_ptr != s->buf + MAX_AU_HEADERS_SIZE) { + av_log(s1, AV_LOG_ERROR, "Strange...\n"); + av_abort(); + } + max_packet_size = s->max_payload_size - 4; + p = s->buf; + p[0] = 0; + p[1] = 16; + while (size > 0) { + len = FFMIN(size, max_packet_size); + p[2] = len >> 5; + p[3] = (size & 0x1F) << 3; + memcpy(p + 4, buff, len); + ff_rtp_send_data(s1, p, len + 4, len == size); + size -= len; + buff += len; + } + } +} diff --git a/contrib/ffmpeg/libavformat/rtp_aac.h b/contrib/ffmpeg/libavformat/rtp_aac.h new file mode 100644 index 000000000..24b41cc42 --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtp_aac.h @@ -0,0 +1,27 @@ +/* + * RTP definitions + * + * 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 FFMPEG_RTP_AAC_H +#define FFMPEG_RTP_AAC_H + +#include "avformat.h" + +void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size); + +#endif /* FFMPEG_RTP_AAC_H */ diff --git a/contrib/ffmpeg/libavformat/rtp_h264.c b/contrib/ffmpeg/libavformat/rtp_h264.c index d38e8780d..3e0fc3add 100644 --- a/contrib/ffmpeg/libavformat/rtp_h264.c +++ b/contrib/ffmpeg/libavformat/rtp_h264.c @@ -47,6 +47,7 @@ #include "rtp_internal.h" #include "rtp_h264.h" #include "base64.h" +#include "avstring.h" /** RTP/H264 specific private data. @@ -77,8 +78,8 @@ static void sdp_parse_fmtp_config_h264(AVStream * stream, assert(h264_data != NULL); if (!strcmp(attr, "packetization-mode")) { - av_log(NULL, AV_LOG_DEBUG, "H.264/RTP Packetization Mode: %d\n", atoi(attr)); - h264_data->packetization_mode = atoi(attr); + av_log(NULL, AV_LOG_DEBUG, "H.264/RTP Packetization Mode: %d\n", atoi(value)); + h264_data->packetization_mode = atoi(value); /* Packetization Mode: 0 or not present: Single NAL mode (Only nals from 1-23 are allowed) @@ -162,7 +163,7 @@ static int h264_handle_packet(RTPDemuxContext * s, AVPacket * pkt, uint32_t * timestamp, const uint8_t * buf, - int len) + int len, int flags) { #ifdef DEBUG h264_rtp_extra_data *data = s->dynamic_protocol_context; @@ -270,14 +271,14 @@ static int h264_handle_packet(RTPDemuxContext * s, // these are the same as above, we just redo them here for clarity... uint8_t fu_indicator = nal; uint8_t fu_header = *buf; // read the fu_header. - uint8_t start_bit = (fu_header & 0x80) >> 7; + uint8_t start_bit = fu_header >> 7; // uint8_t end_bit = (fu_header & 0x40) >> 6; uint8_t nal_type = (fu_header & 0x1f); uint8_t reconstructed_nal; // reconstruct this packet's true nal; only the data follows.. reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal; - reconstructed_nal |= (nal_type & 0x1f); + reconstructed_nal |= nal_type; // skip the fu_header... buf++; @@ -285,7 +286,7 @@ static int h264_handle_packet(RTPDemuxContext * s, #ifdef DEBUG if (start_bit) - data->packet_types_received[nal_type & 0x1f]++; + data->packet_types_received[nal_type]++; #endif if(start_bit) { // copy in the start sequence, and the reconstructed nal.... @@ -312,7 +313,7 @@ static int h264_handle_packet(RTPDemuxContext * s, } /* ---------------- public code */ -static void *h264_new_extradata() +static void *h264_new_extradata(void) { h264_rtp_extra_data *data = av_mallocz(sizeof(h264_rtp_extra_data) + @@ -357,7 +358,7 @@ static int parse_h264_sdp_line(AVStream * stream, void *data, assert(h264_data->cookie == MAGIC_COOKIE); - if (strstart(p, "framesize:", &p)) { + if (av_strstart(p, "framesize:", &p)) { char buf1[50]; char *dst = buf1; @@ -375,7 +376,7 @@ static int parse_h264_sdp_line(AVStream * stream, void *data, codec->width = atoi(buf1); codec->height = atoi(p + 1); // skip the - codec->pix_fmt = PIX_FMT_YUV420P; - } else if (strstart(p, "fmtp:", &p)) { + } else if (av_strstart(p, "fmtp:", &p)) { char attr[256]; char value[4096]; @@ -390,7 +391,7 @@ static int parse_h264_sdp_line(AVStream * stream, void *data, /* grab the codec extra_data from the config parameter of the fmtp line */ sdp_parse_fmtp_config_h264(stream, h264_data, attr, value); } - } else if (strstart(p, "cliprect:", &p)) { + } else if (av_strstart(p, "cliprect:", &p)) { // could use this if we wanted. } diff --git a/contrib/ffmpeg/libavformat/rtp_h264.h b/contrib/ffmpeg/libavformat/rtp_h264.h index 19508574d..0f23e525c 100644 --- a/contrib/ffmpeg/libavformat/rtp_h264.h +++ b/contrib/ffmpeg/libavformat/rtp_h264.h @@ -19,8 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef RTP_H264_H -#define RTP_H264_H +#ifndef FFMPEG_RTP_H264_H +#define FFMPEG_RTP_H264_H + +#include "rtp_internal.h" extern RTPDynamicProtocolHandler ff_h264_dynamic_handler; -#endif /* RTP_H264_H */ +void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size); + +#endif /* FFMPEG_RTP_H264_H */ diff --git a/contrib/ffmpeg/libavformat/rtp_internal.h b/contrib/ffmpeg/libavformat/rtp_internal.h index 3edcf49c8..e9d6cb390 100644 --- a/contrib/ffmpeg/libavformat/rtp_internal.h +++ b/contrib/ffmpeg/libavformat/rtp_internal.h @@ -20,8 +20,12 @@ */ // this is a bit of a misnomer, because rtp & rtsp internal structures and prototypes are in here. -#ifndef RTP_INTERNAL_H -#define RTP_INTERNAL_H +#ifndef FFMPEG_RTP_INTERNAL_H +#define FFMPEG_RTP_INTERNAL_H + +#include <stdint.h> +#include "avcodec.h" +#include "rtp.h" // these statistics are used for rtcp receiver reports... typedef struct { @@ -37,12 +41,21 @@ typedef struct { uint32_t jitter; ///< estimated jitter. } RTPStatistics; - +/** + * Packet parsing for "private" payloads in the RTP specs. + * + * @param s stream context + * @param pkt packet in which to write the parsed data + * @param timestamp pointer in which to write the timestamp of this RTP packet + * @param buf pointer to raw RTP packet data + * @param len length of buf + * @param flags flags from the RTP packet header (PKT_FLAG_*) + */ typedef int (*DynamicPayloadPacketHandlerProc) (struct RTPDemuxContext * s, AVPacket * pkt, uint32_t *timestamp, const uint8_t * buf, - int len); + int len, int flags); typedef struct RTPDynamicProtocolHandler_s { // fields from AVRtpDynamicPayloadType_s @@ -101,10 +114,18 @@ struct RTPDemuxContext { /* dynamic payload stuff */ DynamicPayloadPacketHandlerProc parse_packet; ///< This is also copied from the dynamic protocol handler structure void *dynamic_protocol_context; ///< This is a copy from the values setup from the sdp parsing, in rtsp.c don't free me. + int max_frames_per_packet; }; extern RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler; int rtsp_next_attr_and_value(const char **p, char *attr, int attr_size, char *value, int value_size); ///< from rtsp.c, but used by rtp dynamic protocol handlers. -#endif /* RTP_INTERNAL_H */ + +void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); +const char *ff_rtp_enc_name(int payload_type); +enum CodecID ff_rtp_codec_id(const char *buf, enum CodecType codec_type); + +void av_register_rtp_dynamic_payload_handlers(void); + +#endif /* FFMPEG_RTP_INTERNAL_H */ diff --git a/contrib/ffmpeg/libavformat/rtp_mpv.c b/contrib/ffmpeg/libavformat/rtp_mpv.c new file mode 100644 index 000000000..c8bf81f9a --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtp_mpv.c @@ -0,0 +1,118 @@ +/* + * RTP packetization for MPEG video + * Copyright (c) 2002 Fabrice Bellard. + * Copyright (c) 2007 Luca Abeni. + * + * 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 "rtp_internal.h" + +#include "mpegvideo.h" + +/* NOTE: a single frame must be passed with sequence header if + needed. XXX: use slices. */ +void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size) +{ + RTPDemuxContext *s = s1->priv_data; + int len, h, max_packet_size; + uint8_t *q; + int begin_of_slice, end_of_slice, frame_type, temporal_reference; + + max_packet_size = s->max_payload_size; + begin_of_slice = 1; + end_of_slice = 0; + frame_type = 0; + temporal_reference = 0; + + while (size > 0) { + int begin_of_sequence; + + begin_of_sequence = 0; + len = max_packet_size - 4; + + if (len >= size) { + len = size; + end_of_slice = 1; + } else { + const uint8_t *r, *r1; + int start_code; + + r1 = buf1; + while (1) { + start_code = -1; + r = ff_find_start_code(r1, buf1 + size, &start_code); + if((start_code & 0xFFFFFF00) == 0x100) { + /* New start code found */ + if (start_code == 0x100) { + frame_type = (r[1] & 0x38) >> 3; + temporal_reference = (int)r[0] << 2 | r[1] >> 6; + } + if (start_code == 0x1B8) { + begin_of_sequence = 1; + } + + if (r - buf1 < len) { + /* The current slice fits in the packet */ + if (begin_of_slice == 0) { + /* no slice at the beginning of the packet... */ + end_of_slice = 1; + len = r - buf1 - 4; + break; + } + r1 = r; + } else { + if (r - r1 < max_packet_size) { + len = r1 - buf1 - 4; + end_of_slice = 1; + } + break; + } + } else { + break; + } + } + } + + h = 0; + h |= temporal_reference << 16; + h |= begin_of_sequence << 13; + h |= begin_of_slice << 12; + h |= end_of_slice << 11; + h |= frame_type << 8; + + q = s->buf; + *q++ = h >> 24; + *q++ = h >> 16; + *q++ = h >> 8; + *q++ = h; + + memcpy(q, buf1, len); + q += len; + + /* 90 KHz time stamp */ + s->timestamp = s->cur_timestamp; + ff_rtp_send_data(s1, s->buf, q - s->buf, (len == size)); + + buf1 += len; + size -= len; + begin_of_slice = end_of_slice; + end_of_slice = 0; + } +} + + diff --git a/contrib/ffmpeg/libavformat/rtp_mpv.h b/contrib/ffmpeg/libavformat/rtp_mpv.h new file mode 100644 index 000000000..36e649a89 --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtp_mpv.h @@ -0,0 +1,27 @@ +/* + * RTP definitions + * + * 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 FFMPEG_RTP_MPV_H +#define FFMPEG_RTP_MPV_H + +#include "avformat.h" + +void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size); + +#endif /* FFMPEG_RTP_MPV_H */ diff --git a/contrib/ffmpeg/libavformat/rtpdec.c b/contrib/ffmpeg/libavformat/rtpdec.c new file mode 100644 index 000000000..7bdfca30a --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtpdec.c @@ -0,0 +1,552 @@ +/* + * RTP input format + * Copyright (c) 2002 Fabrice Bellard. + * + * 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 "mpegts.h" +#include "bitstream.h" + +#include <unistd.h> +#include "network.h" + +#include "rtp_internal.h" +#include "rtp_h264.h" + +//#define DEBUG + +/* TODO: - add RTCP statistics reporting (should be optional). + + - add support for h263/mpeg4 packetized output : IDEA: send a + buffer to 'rtp_write_packet' contains all the packets for ONE + frame. Each packet should have a four byte header containing + the length in big endian format (same trick as + 'url_open_dyn_packet_buf') +*/ + +/* statistics functions */ +RTPDynamicProtocolHandler *RTPFirstDynamicPayloadHandler= NULL; + +static RTPDynamicProtocolHandler mp4v_es_handler= {"MP4V-ES", CODEC_TYPE_VIDEO, CODEC_ID_MPEG4}; +static RTPDynamicProtocolHandler mpeg4_generic_handler= {"mpeg4-generic", CODEC_TYPE_AUDIO, CODEC_ID_AAC}; + +static void register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) +{ + handler->next= RTPFirstDynamicPayloadHandler; + RTPFirstDynamicPayloadHandler= handler; +} + +void av_register_rtp_dynamic_payload_handlers(void) +{ + register_dynamic_payload_handler(&mp4v_es_handler); + register_dynamic_payload_handler(&mpeg4_generic_handler); + register_dynamic_payload_handler(&ff_h264_dynamic_handler); +} + +static int rtcp_parse_packet(RTPDemuxContext *s, const unsigned char *buf, int len) +{ + if (buf[1] != 200) + return -1; + s->last_rtcp_ntp_time = AV_RB64(buf + 8); + if (s->first_rtcp_ntp_time == AV_NOPTS_VALUE) + s->first_rtcp_ntp_time = s->last_rtcp_ntp_time; + s->last_rtcp_timestamp = AV_RB32(buf + 16); + return 0; +} + +#define RTP_SEQ_MOD (1<<16) + +/** +* called on parse open packet +*/ +static void rtp_init_statistics(RTPStatistics *s, uint16_t base_sequence) // called on parse open packet. +{ + memset(s, 0, sizeof(RTPStatistics)); + s->max_seq= base_sequence; + s->probation= 1; +} + +/** +* called whenever there is a large jump in sequence numbers, or when they get out of probation... +*/ +static void rtp_init_sequence(RTPStatistics *s, uint16_t seq) +{ + s->max_seq= seq; + s->cycles= 0; + s->base_seq= seq -1; + s->bad_seq= RTP_SEQ_MOD + 1; + s->received= 0; + s->expected_prior= 0; + s->received_prior= 0; + s->jitter= 0; + s->transit= 0; +} + +/** +* returns 1 if we should handle this packet. +*/ +static int rtp_valid_packet_in_sequence(RTPStatistics *s, uint16_t seq) +{ + uint16_t udelta= seq - s->max_seq; + const int MAX_DROPOUT= 3000; + const int MAX_MISORDER = 100; + const int MIN_SEQUENTIAL = 2; + + /* source not valid until MIN_SEQUENTIAL packets with sequence seq. numbers have been received */ + if(s->probation) + { + if(seq==s->max_seq + 1) { + s->probation--; + s->max_seq= seq; + if(s->probation==0) { + rtp_init_sequence(s, seq); + s->received++; + return 1; + } + } else { + s->probation= MIN_SEQUENTIAL - 1; + s->max_seq = seq; + } + } else if (udelta < MAX_DROPOUT) { + // in order, with permissible gap + if(seq < s->max_seq) { + //sequence number wrapped; count antother 64k cycles + s->cycles += RTP_SEQ_MOD; + } + s->max_seq= seq; + } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { + // sequence made a large jump... + if(seq==s->bad_seq) { + // two sequential packets-- assume that the other side restarted without telling us; just resync. + rtp_init_sequence(s, seq); + } else { + s->bad_seq= (seq + 1) & (RTP_SEQ_MOD-1); + return 0; + } + } else { + // duplicate or reordered packet... + } + s->received++; + return 1; +} + +#if 0 +/** +* This function is currently unused; without a valid local ntp time, I don't see how we could calculate the +* difference between the arrival and sent timestamp. As a result, the jitter and transit statistics values +* never change. I left this in in case someone else can see a way. (rdm) +*/ +static void rtcp_update_jitter(RTPStatistics *s, uint32_t sent_timestamp, uint32_t arrival_timestamp) +{ + uint32_t transit= arrival_timestamp - sent_timestamp; + int d; + s->transit= transit; + d= FFABS(transit - s->transit); + s->jitter += d - ((s->jitter + 8)>>4); +} +#endif + +int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count) +{ + ByteIOContext *pb; + uint8_t *buf; + int len; + int rtcp_bytes; + RTPStatistics *stats= &s->statistics; + uint32_t lost; + uint32_t extended_max; + uint32_t expected_interval; + uint32_t received_interval; + uint32_t lost_interval; + uint32_t expected; + uint32_t fraction; + uint64_t ntp_time= s->last_rtcp_ntp_time; // TODO: Get local ntp time? + + if (!s->rtp_ctx || (count < 1)) + return -1; + + /* TODO: I think this is way too often; RFC 1889 has algorithm for this */ + /* XXX: mpeg pts hardcoded. RTCP send every 0.5 seconds */ + s->octet_count += count; + rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) / + RTCP_TX_RATIO_DEN; + rtcp_bytes /= 50; // mmu_man: that's enough for me... VLC sends much less btw !? + if (rtcp_bytes < 28) + return -1; + s->last_octet_count = s->octet_count; + + if (url_open_dyn_buf(&pb) < 0) + return -1; + + // Receiver Report + put_byte(pb, (RTP_VERSION << 6) + 1); /* 1 report block */ + put_byte(pb, 201); + put_be16(pb, 7); /* length in words - 1 */ + put_be32(pb, s->ssrc); // our own SSRC + put_be32(pb, s->ssrc); // XXX: should be the server's here! + // some placeholders we should really fill... + // RFC 1889/p64 + extended_max= stats->cycles + stats->max_seq; + expected= extended_max - stats->base_seq + 1; + lost= expected - stats->received; + lost= FFMIN(lost, 0xffffff); // clamp it since it's only 24 bits... + expected_interval= expected - stats->expected_prior; + stats->expected_prior= expected; + received_interval= stats->received - stats->received_prior; + stats->received_prior= stats->received; + lost_interval= expected_interval - received_interval; + if (expected_interval==0 || lost_interval<=0) fraction= 0; + else fraction = (lost_interval<<8)/expected_interval; + + fraction= (fraction<<24) | lost; + + put_be32(pb, fraction); /* 8 bits of fraction, 24 bits of total packets lost */ + put_be32(pb, extended_max); /* max sequence received */ + put_be32(pb, stats->jitter>>4); /* jitter */ + + if(s->last_rtcp_ntp_time==AV_NOPTS_VALUE) + { + put_be32(pb, 0); /* last SR timestamp */ + put_be32(pb, 0); /* delay since last SR */ + } else { + uint32_t middle_32_bits= s->last_rtcp_ntp_time>>16; // this is valid, right? do we need to handle 64 bit values special? + uint32_t delay_since_last= ntp_time - s->last_rtcp_ntp_time; + + put_be32(pb, middle_32_bits); /* last SR timestamp */ + put_be32(pb, delay_since_last); /* delay since last SR */ + } + + // CNAME + put_byte(pb, (RTP_VERSION << 6) + 1); /* 1 report block */ + put_byte(pb, 202); + len = strlen(s->hostname); + put_be16(pb, (6 + len + 3) / 4); /* length in words - 1 */ + put_be32(pb, s->ssrc); + put_byte(pb, 0x01); + put_byte(pb, len); + put_buffer(pb, s->hostname, len); + // padding + for (len = (6 + len) % 4; len % 4; len++) { + put_byte(pb, 0); + } + + put_flush_packet(pb); + len = url_close_dyn_buf(pb, &buf); + if ((len > 0) && buf) { + int result; +#if defined(DEBUG) + printf("sending %d bytes of RR\n", len); +#endif + result= url_write(s->rtp_ctx, buf, len); +#if defined(DEBUG) + printf("result from url_write: %d\n", result); +#endif + av_free(buf); + } + return 0; +} + +/** + * open a new RTP parse context for stream 'st'. 'st' can be NULL for + * MPEG2TS streams to indicate that they should be demuxed inside the + * rtp demux (otherwise CODEC_ID_MPEG2TS packets are returned) + * TODO: change this to not take rtp_payload data, and use the new dynamic payload system. + */ +RTPDemuxContext *rtp_parse_open(AVFormatContext *s1, AVStream *st, URLContext *rtpc, int payload_type, rtp_payload_data_t *rtp_payload_data) +{ + RTPDemuxContext *s; + + s = av_mallocz(sizeof(RTPDemuxContext)); + if (!s) + return NULL; + s->payload_type = payload_type; + s->last_rtcp_ntp_time = AV_NOPTS_VALUE; + s->first_rtcp_ntp_time = AV_NOPTS_VALUE; + s->ic = s1; + s->st = st; + s->rtp_payload_data = rtp_payload_data; + rtp_init_statistics(&s->statistics, 0); // do we know the initial sequence from sdp? + if (!strcmp(ff_rtp_enc_name(payload_type), "MP2T")) { + s->ts = mpegts_parse_open(s->ic); + if (s->ts == NULL) { + av_free(s); + return NULL; + } + } else { + switch(st->codec->codec_id) { + case CODEC_ID_MPEG1VIDEO: + case CODEC_ID_MPEG2VIDEO: + case CODEC_ID_MP2: + case CODEC_ID_MP3: + case CODEC_ID_MPEG4: + case CODEC_ID_H264: + st->need_parsing = AVSTREAM_PARSE_FULL; + break; + default: + break; + } + } + // needed to send back RTCP RR in RTSP sessions + s->rtp_ctx = rtpc; + gethostname(s->hostname, sizeof(s->hostname)); + return s; +} + +static int rtp_parse_mp4_au(RTPDemuxContext *s, const uint8_t *buf) +{ + int au_headers_length, au_header_size, i; + GetBitContext getbitcontext; + rtp_payload_data_t *infos; + + infos = s->rtp_payload_data; + + if (infos == NULL) + return -1; + + /* decode the first 2 bytes where are stored the AUHeader sections + length in bits */ + au_headers_length = AV_RB16(buf); + + if (au_headers_length > RTP_MAX_PACKET_LENGTH) + return -1; + + infos->au_headers_length_bytes = (au_headers_length + 7) / 8; + + /* skip AU headers length section (2 bytes) */ + buf += 2; + + init_get_bits(&getbitcontext, buf, infos->au_headers_length_bytes * 8); + + /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */ + au_header_size = infos->sizelength + infos->indexlength; + if (au_header_size <= 0 || (au_headers_length % au_header_size != 0)) + return -1; + + infos->nb_au_headers = au_headers_length / au_header_size; + infos->au_headers = av_malloc(sizeof(struct AUHeaders) * infos->nb_au_headers); + + /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving) + In my test, the FAAD decoder does not behave correctly when sending each AU one by one + but does when sending the whole as one big packet... */ + infos->au_headers[0].size = 0; + infos->au_headers[0].index = 0; + for (i = 0; i < infos->nb_au_headers; ++i) { + infos->au_headers[0].size += get_bits_long(&getbitcontext, infos->sizelength); + infos->au_headers[0].index = get_bits_long(&getbitcontext, infos->indexlength); + } + + infos->nb_au_headers = 1; + + return 0; +} + +/** + * This was the second switch in rtp_parse packet. Normalizes time, if required, sets stream_index, etc. + */ +static void finalize_packet(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestamp) +{ + switch(s->st->codec->codec_id) { + case CODEC_ID_MP2: + case CODEC_ID_MPEG1VIDEO: + case CODEC_ID_MPEG2VIDEO: + if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) { + int64_t addend; + + int delta_timestamp; + /* XXX: is it really necessary to unify the timestamp base ? */ + /* compute pts from timestamp with received ntp_time */ + delta_timestamp = timestamp - s->last_rtcp_timestamp; + /* convert to 90 kHz without overflow */ + addend = (s->last_rtcp_ntp_time - s->first_rtcp_ntp_time) >> 14; + addend = (addend * 5625) >> 14; + pkt->pts = addend + delta_timestamp; + } + break; + case CODEC_ID_AAC: + case CODEC_ID_H264: + case CODEC_ID_MPEG4: + pkt->pts = timestamp; + break; + default: + /* no timestamp info yet */ + break; + } + pkt->stream_index = s->st->index; +} + +/** + * Parse an RTP or RTCP packet directly sent as a buffer. + * @param s RTP parse context. + * @param pkt returned packet + * @param buf input buffer or NULL to read the next packets + * @param len buffer len + * @return 0 if a packet is returned, 1 if a packet is returned and more can follow + * (use buf as NULL to read the next). -1 if no packet (error or no more packet). + */ +int rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, + const uint8_t *buf, int len) +{ + unsigned int ssrc, h; + int payload_type, seq, ret, flags = 0; + AVStream *st; + uint32_t timestamp; + int rv= 0; + + if (!buf) { + /* return the next packets, if any */ + if(s->st && s->parse_packet) { + timestamp= 0; ///< Should not be used if buf is NULL, but should be set to the timestamp of the packet returned.... + rv= s->parse_packet(s, pkt, ×tamp, NULL, 0, flags); + finalize_packet(s, pkt, timestamp); + return rv; + } else { + // TODO: Move to a dynamic packet handler (like above) + if (s->read_buf_index >= s->read_buf_size) + return -1; + ret = mpegts_parse_packet(s->ts, pkt, s->buf + s->read_buf_index, + s->read_buf_size - s->read_buf_index); + if (ret < 0) + return -1; + s->read_buf_index += ret; + if (s->read_buf_index < s->read_buf_size) + return 1; + else + return 0; + } + } + + if (len < 12) + return -1; + + if ((buf[0] & 0xc0) != (RTP_VERSION << 6)) + return -1; + if (buf[1] >= 200 && buf[1] <= 204) { + rtcp_parse_packet(s, buf, len); + return -1; + } + payload_type = buf[1] & 0x7f; + seq = AV_RB16(buf + 2); + timestamp = AV_RB32(buf + 4); + ssrc = AV_RB32(buf + 8); + /* store the ssrc in the RTPDemuxContext */ + s->ssrc = ssrc; + + /* NOTE: we can handle only one payload type */ + if (s->payload_type != payload_type) + return -1; + + st = s->st; + // only do something with this if all the rtp checks pass... + if(!rtp_valid_packet_in_sequence(&s->statistics, seq)) + { + av_log(st?st->codec:NULL, AV_LOG_ERROR, "RTP: PT=%02x: bad cseq %04x expected=%04x\n", + payload_type, seq, ((s->seq + 1) & 0xffff)); + return -1; + } + + s->seq = seq; + len -= 12; + buf += 12; + + if (!st) { + /* specific MPEG2TS demux support */ + ret = mpegts_parse_packet(s->ts, pkt, buf, len); + if (ret < 0) + return -1; + if (ret < len) { + s->read_buf_size = len - ret; + memcpy(s->buf, buf + ret, s->read_buf_size); + s->read_buf_index = 0; + return 1; + } + } else if (s->parse_packet) { + rv = s->parse_packet(s, pkt, ×tamp, buf, len, flags); + } else { + // at this point, the RTP header has been stripped; This is ASSUMING that there is only 1 CSRC, which in't wise. + switch(st->codec->codec_id) { + case CODEC_ID_MP2: + /* better than nothing: skip mpeg audio RTP header */ + if (len <= 4) + return -1; + h = AV_RB32(buf); + len -= 4; + buf += 4; + av_new_packet(pkt, len); + memcpy(pkt->data, buf, len); + break; + case CODEC_ID_MPEG1VIDEO: + case CODEC_ID_MPEG2VIDEO: + /* better than nothing: skip mpeg video RTP header */ + if (len <= 4) + return -1; + h = AV_RB32(buf); + buf += 4; + len -= 4; + if (h & (1 << 26)) { + /* mpeg2 */ + if (len <= 4) + return -1; + buf += 4; + len -= 4; + } + av_new_packet(pkt, len); + memcpy(pkt->data, buf, len); + break; + // moved from below, verbatim. this is because this section handles packets, and the lower switch handles + // timestamps. + // TODO: Put this into a dynamic packet handler... + case CODEC_ID_AAC: + if (rtp_parse_mp4_au(s, buf)) + return -1; + { + rtp_payload_data_t *infos = s->rtp_payload_data; + if (infos == NULL) + return -1; + buf += infos->au_headers_length_bytes + 2; + len -= infos->au_headers_length_bytes + 2; + + /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define + one au_header */ + av_new_packet(pkt, infos->au_headers[0].size); + memcpy(pkt->data, buf, infos->au_headers[0].size); + buf += infos->au_headers[0].size; + len -= infos->au_headers[0].size; + } + s->read_buf_size = len; + rv= 0; + break; + default: + av_new_packet(pkt, len); + memcpy(pkt->data, buf, len); + break; + } + + // now perform timestamp things.... + finalize_packet(s, pkt, timestamp); + } + return rv; +} + +void rtp_parse_close(RTPDemuxContext *s) +{ + // TODO: fold this into the protocol specific data fields. + if (!strcmp(ff_rtp_enc_name(s->payload_type), "MP2T")) { + mpegts_parse_close(s->ts); + } + av_free(s); +} diff --git a/contrib/ffmpeg/libavformat/rtpenc.c b/contrib/ffmpeg/libavformat/rtpenc.c new file mode 100644 index 000000000..19e4f19fe --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtpenc.c @@ -0,0 +1,366 @@ +/* + * RTP output format + * Copyright (c) 2002 Fabrice Bellard. + * + * 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 "mpegts.h" +#include "bitstream.h" + +#include <unistd.h> +#include "network.h" + +#include "rtp_internal.h" +#include "rtp_mpv.h" +#include "rtp_aac.h" +#include "rtp_h264.h" + +//#define DEBUG + +#define RTCP_SR_SIZE 28 +#define NTP_OFFSET 2208988800ULL +#define NTP_OFFSET_US (NTP_OFFSET * 1000000ULL) + +static uint64_t ntp_time(void) +{ + return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; +} + +static int rtp_write_header(AVFormatContext *s1) +{ + RTPDemuxContext *s = s1->priv_data; + int payload_type, max_packet_size, n; + AVStream *st; + + if (s1->nb_streams != 1) + return -1; + st = s1->streams[0]; + + payload_type = rtp_get_payload_type(st->codec); + if (payload_type < 0) + payload_type = RTP_PT_PRIVATE; /* private payload type */ + s->payload_type = payload_type; + +// following 2 FIXMEs could be set based on the current time, there is normally no info leak, as RTP will likely be transmitted immediately + s->base_timestamp = 0; /* FIXME: was random(), what should this be? */ + s->timestamp = s->base_timestamp; + s->cur_timestamp = 0; + s->ssrc = 0; /* FIXME: was random(), what should this be? */ + s->first_packet = 1; + s->first_rtcp_ntp_time = AV_NOPTS_VALUE; + + max_packet_size = url_fget_max_packet_size(s1->pb); + if (max_packet_size <= 12) + return AVERROR(EIO); + s->max_payload_size = max_packet_size - 12; + + s->max_frames_per_packet = 0; + if (s1->max_delay) { + if (st->codec->codec_type == CODEC_TYPE_AUDIO) { + if (st->codec->frame_size == 0) { + av_log(s1, AV_LOG_ERROR, "Cannot respect max delay: frame size = 0\n"); + } else { + s->max_frames_per_packet = av_rescale_rnd(s1->max_delay, st->codec->sample_rate, AV_TIME_BASE * st->codec->frame_size, AV_ROUND_DOWN); + } + } + if (st->codec->codec_type == CODEC_TYPE_VIDEO) { + /* FIXME: We should round down here... */ + s->max_frames_per_packet = av_rescale_q(s1->max_delay, AV_TIME_BASE_Q, st->codec->time_base); + } + } + + av_set_pts_info(st, 32, 1, 90000); + switch(st->codec->codec_id) { + case CODEC_ID_MP2: + case CODEC_ID_MP3: + s->buf_ptr = s->buf + 4; + break; + case CODEC_ID_MPEG1VIDEO: + case CODEC_ID_MPEG2VIDEO: + break; + case CODEC_ID_MPEG2TS: + n = s->max_payload_size / TS_PACKET_SIZE; + if (n < 1) + n = 1; + s->max_payload_size = n * TS_PACKET_SIZE; + s->buf_ptr = s->buf; + break; + case CODEC_ID_AAC: + s->read_buf_index = 0; + default: + if (st->codec->codec_type == CODEC_TYPE_AUDIO) { + av_set_pts_info(st, 32, 1, st->codec->sample_rate); + } + s->buf_ptr = s->buf; + break; + } + + return 0; +} + +/* send an rtcp sender report packet */ +static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time) +{ + RTPDemuxContext *s = s1->priv_data; + uint32_t rtp_ts; + +#if defined(DEBUG) + printf("RTCP: %02x %"PRIx64" %x\n", s->payload_type, ntp_time, s->timestamp); +#endif + + if (s->first_rtcp_ntp_time == AV_NOPTS_VALUE) s->first_rtcp_ntp_time = ntp_time; + s->last_rtcp_ntp_time = ntp_time; + rtp_ts = av_rescale_q(ntp_time - s->first_rtcp_ntp_time, AV_TIME_BASE_Q, + s1->streams[0]->time_base) + s->base_timestamp; + put_byte(s1->pb, (RTP_VERSION << 6)); + put_byte(s1->pb, 200); + put_be16(s1->pb, 6); /* length in words - 1 */ + put_be32(s1->pb, s->ssrc); + put_be32(s1->pb, ntp_time / 1000000); + put_be32(s1->pb, ((ntp_time % 1000000) << 32) / 1000000); + put_be32(s1->pb, rtp_ts); + put_be32(s1->pb, s->packet_count); + put_be32(s1->pb, s->octet_count); + put_flush_packet(s1->pb); +} + +/* send an rtp packet. sequence number is incremented, but the caller + must update the timestamp itself */ +void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m) +{ + RTPDemuxContext *s = s1->priv_data; + +#ifdef DEBUG + printf("rtp_send_data size=%d\n", len); +#endif + + /* build the RTP header */ + put_byte(s1->pb, (RTP_VERSION << 6)); + put_byte(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7)); + put_be16(s1->pb, s->seq); + put_be32(s1->pb, s->timestamp); + put_be32(s1->pb, s->ssrc); + + put_buffer(s1->pb, buf1, len); + put_flush_packet(s1->pb); + + s->seq++; + s->octet_count += len; + s->packet_count++; +} + +/* send an integer number of samples and compute time stamp and fill + the rtp send buffer before sending. */ +static void rtp_send_samples(AVFormatContext *s1, + const uint8_t *buf1, int size, int sample_size) +{ + RTPDemuxContext *s = s1->priv_data; + int len, max_packet_size, n; + + max_packet_size = (s->max_payload_size / sample_size) * sample_size; + /* not needed, but who nows */ + if ((size % sample_size) != 0) + av_abort(); + n = 0; + while (size > 0) { + s->buf_ptr = s->buf; + len = FFMIN(max_packet_size, size); + + /* copy data */ + memcpy(s->buf_ptr, buf1, len); + s->buf_ptr += len; + buf1 += len; + size -= len; + s->timestamp = s->cur_timestamp + n / sample_size; + ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 0); + n += (s->buf_ptr - s->buf); + } +} + +/* NOTE: we suppose that exactly one frame is given as argument here */ +/* XXX: test it */ +static void rtp_send_mpegaudio(AVFormatContext *s1, + const uint8_t *buf1, int size) +{ + RTPDemuxContext *s = s1->priv_data; + int len, count, max_packet_size; + + max_packet_size = s->max_payload_size; + + /* test if we must flush because not enough space */ + len = (s->buf_ptr - s->buf); + if ((len + size) > max_packet_size) { + if (len > 4) { + ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 0); + s->buf_ptr = s->buf + 4; + } + } + if (s->buf_ptr == s->buf + 4) { + s->timestamp = s->cur_timestamp; + } + + /* add the packet */ + if (size > max_packet_size) { + /* big packet: fragment */ + count = 0; + while (size > 0) { + len = max_packet_size - 4; + if (len > size) + len = size; + /* build fragmented packet */ + s->buf[0] = 0; + s->buf[1] = 0; + s->buf[2] = count >> 8; + s->buf[3] = count; + memcpy(s->buf + 4, buf1, len); + ff_rtp_send_data(s1, s->buf, len + 4, 0); + size -= len; + buf1 += len; + count += len; + } + } else { + if (s->buf_ptr == s->buf + 4) { + /* no fragmentation possible */ + s->buf[0] = 0; + s->buf[1] = 0; + s->buf[2] = 0; + s->buf[3] = 0; + } + memcpy(s->buf_ptr, buf1, size); + s->buf_ptr += size; + } +} + +static void rtp_send_raw(AVFormatContext *s1, + const uint8_t *buf1, int size) +{ + RTPDemuxContext *s = s1->priv_data; + int len, max_packet_size; + + max_packet_size = s->max_payload_size; + + while (size > 0) { + len = max_packet_size; + if (len > size) + len = size; + + s->timestamp = s->cur_timestamp; + ff_rtp_send_data(s1, buf1, len, (len == size)); + + buf1 += len; + size -= len; + } +} + +/* NOTE: size is assumed to be an integer multiple of TS_PACKET_SIZE */ +static void rtp_send_mpegts_raw(AVFormatContext *s1, + const uint8_t *buf1, int size) +{ + RTPDemuxContext *s = s1->priv_data; + int len, out_len; + + while (size >= TS_PACKET_SIZE) { + len = s->max_payload_size - (s->buf_ptr - s->buf); + if (len > size) + len = size; + memcpy(s->buf_ptr, buf1, len); + buf1 += len; + size -= len; + s->buf_ptr += len; + + out_len = s->buf_ptr - s->buf; + if (out_len >= s->max_payload_size) { + ff_rtp_send_data(s1, s->buf, out_len, 0); + s->buf_ptr = s->buf; + } + } +} + +/* write an RTP packet. 'buf1' must contain a single specific frame. */ +static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) +{ + RTPDemuxContext *s = s1->priv_data; + AVStream *st = s1->streams[0]; + int rtcp_bytes; + int size= pkt->size; + uint8_t *buf1= pkt->data; + +#ifdef DEBUG + printf("%d: write len=%d\n", pkt->stream_index, size); +#endif + + /* XXX: mpeg pts hardcoded. RTCP send every 0.5 seconds */ + rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) / + RTCP_TX_RATIO_DEN; + if (s->first_packet || ((rtcp_bytes >= RTCP_SR_SIZE) && + (ntp_time() - s->last_rtcp_ntp_time > 5000000))) { + rtcp_send_sr(s1, ntp_time()); + s->last_octet_count = s->octet_count; + s->first_packet = 0; + } + s->cur_timestamp = s->base_timestamp + pkt->pts; + + switch(st->codec->codec_id) { + case CODEC_ID_PCM_MULAW: + case CODEC_ID_PCM_ALAW: + case CODEC_ID_PCM_U8: + case CODEC_ID_PCM_S8: + rtp_send_samples(s1, buf1, size, 1 * st->codec->channels); + break; + case CODEC_ID_PCM_U16BE: + case CODEC_ID_PCM_U16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_S16LE: + rtp_send_samples(s1, buf1, size, 2 * st->codec->channels); + break; + case CODEC_ID_MP2: + case CODEC_ID_MP3: + rtp_send_mpegaudio(s1, buf1, size); + break; + case CODEC_ID_MPEG1VIDEO: + case CODEC_ID_MPEG2VIDEO: + ff_rtp_send_mpegvideo(s1, buf1, size); + break; + case CODEC_ID_AAC: + ff_rtp_send_aac(s1, buf1, size); + break; + case CODEC_ID_MPEG2TS: + rtp_send_mpegts_raw(s1, buf1, size); + break; + case CODEC_ID_H264: + ff_rtp_send_h264(s1, buf1, size); + break; + default: + /* better than nothing : send the codec raw data */ + rtp_send_raw(s1, buf1, size); + break; + } + return 0; +} + +AVOutputFormat rtp_muxer = { + "rtp", + "RTP output format", + NULL, + NULL, + sizeof(RTPDemuxContext), + CODEC_ID_PCM_MULAW, + CODEC_ID_NONE, + rtp_write_header, + rtp_write_packet, +}; diff --git a/contrib/ffmpeg/libavformat/rtpenc_h264.c b/contrib/ffmpeg/libavformat/rtpenc_h264.c new file mode 100644 index 000000000..95d5fff81 --- /dev/null +++ b/contrib/ffmpeg/libavformat/rtpenc_h264.c @@ -0,0 +1,78 @@ +/* + * RTP packetization for H.264 (RFC3984) + * Copyright (c) 2008 Luca Abeni. + * + * 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 rtpenc_h264.c + * @brief H.264 packetization + * @author Luca Abeni <lucabe72@email.it> + */ + +#include "avformat.h" +#include "avc.h" +#include "rtp_h264.h" + +static void nal_send(AVFormatContext *s1, const uint8_t *buf, int size, int last) +{ + RTPDemuxContext *s = s1->priv_data; + + av_log(s1, AV_LOG_DEBUG, "Sending NAL %x of len %d M=%d\n", buf[0] & 0x1F, size, last); + if (size <= s->max_payload_size) { + ff_rtp_send_data(s1, buf, size, last); + } else { + uint8_t type = buf[0] & 0x1F; + uint8_t nri = buf[0] & 0x60; + + av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d\n", size, s->max_payload_size); + s->buf[0] = 28; /* FU Indicator; Type = 28 ---> FU-A */ + s->buf[0] |= nri; + s->buf[1] = type; + s->buf[1] |= 1 << 7; + buf += 1; + size -= 1; + while (size + 2 > s->max_payload_size) { + memcpy(&s->buf[2], buf, s->max_payload_size - 2); + ff_rtp_send_data(s1, s->buf, s->max_payload_size, 0); + buf += s->max_payload_size - 2; + size -= s->max_payload_size - 2; + s->buf[1] &= ~(1 << 7); + } + s->buf[1] |= 1 << 6; + memcpy(&s->buf[2], buf, size); + ff_rtp_send_data(s1, s->buf, size + 2, 1); + } +} + +void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size) +{ + const uint8_t *r; + RTPDemuxContext *s = s1->priv_data; + + s->timestamp = s->cur_timestamp; + r = ff_avc_find_startcode(buf1, buf1 + size); + while (r < buf1 + size) { + const uint8_t *r1; + + while(!*(r++)); + r1 = ff_avc_find_startcode(r, buf1 + size); + nal_send(s1, r, r1 - r, (r1 == buf1 + size)); + r = r1; + } +} diff --git a/contrib/ffmpeg/libavformat/rtpproto.c b/contrib/ffmpeg/libavformat/rtpproto.c index 4d32e667d..d1d5a9247 100644 --- a/contrib/ffmpeg/libavformat/rtpproto.c +++ b/contrib/ffmpeg/libavformat/rtpproto.c @@ -19,10 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" +#include "avstring.h" #include <unistd.h> #include <stdarg.h> #include "network.h" +#include "os_support.h" #include <fcntl.h> #define RTP_TX_BUF_SIZE (64 * 1024) @@ -72,11 +74,11 @@ static void url_add_option(char *buf, int buf_size, const char *fmt, ...) va_start(ap, fmt); if (strchr(buf, '?')) - pstrcat(buf, buf_size, "&"); + av_strlcat(buf, "&", buf_size); else - pstrcat(buf, buf_size, "?"); + av_strlcat(buf, "?", buf_size); vsnprintf(buf1, sizeof(buf1), fmt, ap); - pstrcat(buf, buf_size, buf1); + av_strlcat(buf, buf1, buf_size); va_end(ap); } @@ -138,7 +140,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (url_open(&s->rtp_hd, buf, flags) < 0) goto fail; local_port = udp_get_local_port(s->rtp_hd); - /* XXX: need to open another connexion if the port is not even */ + /* XXX: need to open another connection if the port is not even */ /* well, should suppress localport in path */ @@ -162,7 +164,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (s->rtcp_hd) url_close(s->rtcp_hd); av_free(s); - return AVERROR_IO; + return AVERROR(EIO); } static int rtp_read(URLContext *h, uint8_t *buf, int size) @@ -178,9 +180,10 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) len = recvfrom (s->rtp_fd, buf, size, 0, (struct sockaddr *)&from, &from_len); if (len < 0) { - if (errno == EAGAIN || errno == EINTR) + if (ff_neterrno() == FF_NETERROR(EAGAIN) || + ff_neterrno() == FF_NETERROR(EINTR)) continue; - return AVERROR_IO; + return AVERROR(EIO); } break; } @@ -201,9 +204,10 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) len = recvfrom (s->rtcp_fd, buf, size, 0, (struct sockaddr *)&from, &from_len); if (len < 0) { - if (errno == EAGAIN || errno == EINTR) + if (ff_neterrno() == FF_NETERROR(EAGAIN) || + ff_neterrno() == FF_NETERROR(EINTR)) continue; - return AVERROR_IO; + return AVERROR(EIO); } break; } @@ -213,9 +217,10 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) len = recvfrom (s->rtp_fd, buf, size, 0, (struct sockaddr *)&from, &from_len); if (len < 0) { - if (errno == EAGAIN || errno == EINTR) + if (ff_neterrno() == FF_NETERROR(EAGAIN) || + ff_neterrno() == FF_NETERROR(EINTR)) continue; - return AVERROR_IO; + return AVERROR(EIO); } break; } @@ -262,7 +267,7 @@ static int rtp_close(URLContext *h) } /** - * Return the local port used by the RTP connexion + * Return the local port used by the RTP connection * @param s1 media file context * @return the local port number */ diff --git a/contrib/ffmpeg/libavformat/rtsp.c b/contrib/ffmpeg/libavformat/rtsp.c index 7d4c6bf78..14f0a5ce4 100644 --- a/contrib/ffmpeg/libavformat/rtsp.c +++ b/contrib/ffmpeg/libavformat/rtsp.c @@ -23,6 +23,8 @@ #include <sys/time.h> #include <unistd.h> /* for select() prototype */ #include "network.h" +#include "avstring.h" +#include "rtsp.h" #include "rtp_internal.h" @@ -75,13 +77,13 @@ static int rtsp_read_play(AVFormatContext *s); /* XXX: currently, the only way to change the protocols consists in changing this variable */ +#if LIBAVFORMAT_VERSION_INT < (53 << 16) int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_UDP); - -FFRTSPCallback *ff_rtsp_callback = NULL; +#endif static int rtsp_probe(AVProbeData *p) { - if (strstart(p->filename, "rtsp:", NULL)) + if (av_strstart(p->filename, "rtsp:", NULL)) return AVPROBE_SCORE_MAX; return 0; } @@ -167,11 +169,7 @@ static int sdp_parse_rtpmap(AVCodecContext *codec, RTSPStream *rtsp_st, int payl } else { /* We are in a standard case ( from http://www.iana.org/assignments/rtp-parameters) */ /* search into AVRtpPayloadTypes[] */ - for (i = 0; AVRtpPayloadTypes[i].pt >= 0; ++i) - if (!strcmp(buf, AVRtpPayloadTypes[i].enc_name) && (codec->codec_type == AVRtpPayloadTypes[i].codec_type)){ - codec->codec_id = AVRtpPayloadTypes[i].codec_id; - break; - } + codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type); } c = avcodec_find_decoder(codec->codec_id); @@ -339,7 +337,7 @@ static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) char buf[256]; skip_spaces(&p); - if (!stristart(p, "npt=", &p)) + if (!av_stristart(p, "npt=", &p)) return; *start = AV_NOPTS_VALUE; @@ -407,11 +405,11 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, } break; case 's': - pstrcpy(s->title, sizeof(s->title), p); + av_strlcpy(s->title, p, sizeof(s->title)); break; case 'i': if (s->nb_streams == 0) { - pstrcpy(s->comment, sizeof(s->comment), p); + av_strlcpy(s->comment, p, sizeof(s->comment)); break; } break; @@ -443,7 +441,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, get_word(buf1, sizeof(buf1), &p); /* format list */ rtsp_st->sdp_payload_type = atoi(buf1); - if (!strcmp(AVRtpPayloadTypes[rtsp_st->sdp_payload_type].enc_name, "MP2T")) { + if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { /* no corresponding stream */ } else { st = av_new_stream(s, 0); @@ -458,10 +456,10 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, } } /* put a default control url */ - pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename); + av_strlcpy(rtsp_st->control_url, s->filename, sizeof(rtsp_st->control_url)); break; case 'a': - if (strstart(p, "control:", &p) && s->nb_streams > 0) { + if (av_strstart(p, "control:", &p) && s->nb_streams > 0) { char proto[32]; /* get the control url */ st = s->streams[s->nb_streams - 1]; @@ -471,12 +469,12 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p); if (proto[0] == '\0') { /* relative control URL */ - pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/"); - pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), p); + av_strlcat(rtsp_st->control_url, "/", sizeof(rtsp_st->control_url)); + av_strlcat(rtsp_st->control_url, p, sizeof(rtsp_st->control_url)); } else { - pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), p); + av_strlcpy(rtsp_st->control_url, p, sizeof(rtsp_st->control_url)); } - } else if (strstart(p, "rtpmap:", &p)) { + } else if (av_strstart(p, "rtpmap:", &p)) { /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); @@ -487,7 +485,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p); } } - } else if (strstart(p, "fmtp:", &p)) { + } else if (av_strstart(p, "fmtp:", &p)) { /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); @@ -504,7 +502,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, } } } - } else if(strstart(p, "framesize:", &p)) { + } else if(av_strstart(p, "framesize:", &p)) { // let dynamic protocol handlers have a stab at the line. get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); @@ -517,7 +515,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, } } } - } else if(strstart(p, "range:", &p)) { + } else if(av_strstart(p, "range:", &p)) { int64_t start, end; // this is so that seeking on a streamed file can work. @@ -608,12 +606,19 @@ static void rtsp_parse_transport(RTSPHeader *reply, const char *p) "/", &p); if (*p == '/') p++; - get_word_sep(profile, sizeof(profile), "/;,", &p); - lower_transport[0] = '\0'; - if (*p == '/') { - p++; - get_word_sep(lower_transport, sizeof(lower_transport), - ";,", &p); + if (!strcasecmp (transport_protocol, "rtp")) { + get_word_sep(profile, sizeof(profile), "/;,", &p); + lower_transport[0] = '\0'; + /* rtp/avp/<protocol> */ + if (*p == '/') { + p++; + get_word_sep(lower_transport, sizeof(lower_transport), + ";,", &p); + } + } else if (!strcasecmp (transport_protocol, "x-pn-tng")) { + /* x-pn-tng/<protocol> */ + get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p); + profile[0] = '\0'; } if (!strcasecmp(lower_transport, "TCP")) th->protocol = RTSP_PROTOCOL_RTP_TCP; @@ -684,15 +689,15 @@ void rtsp_parse_line(RTSPHeader *reply, const char *buf) /* NOTE: we do case independent match for broken servers */ p = buf; - if (stristart(p, "Session:", &p)) { + if (av_stristart(p, "Session:", &p)) { get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); - } else if (stristart(p, "Content-Length:", &p)) { + } else if (av_stristart(p, "Content-Length:", &p)) { reply->content_length = strtol(p, NULL, 10); - } else if (stristart(p, "Transport:", &p)) { + } else if (av_stristart(p, "Transport:", &p)) { rtsp_parse_transport(reply, p); - } else if (stristart(p, "CSeq:", &p)) { + } else if (av_stristart(p, "CSeq:", &p)) { reply->seq = strtol(p, NULL, 10); - } else if (stristart(p, "Range:", &p)) { + } else if (av_stristart(p, "Range:", &p)) { rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end); } } @@ -721,7 +726,7 @@ static void rtsp_skip_packet(AVFormatContext *s) ret = url_readbuf(rt->rtsp_hd, buf, 3); if (ret != 3) return; - len = (buf[1] << 8) | buf[2]; + len = AV_RB16(buf + 1); #ifdef DEBUG printf("skipping RTP packet len=%d\n", len); #endif @@ -751,14 +756,14 @@ static void rtsp_send_cmd(AVFormatContext *s, memset(reply, 0, sizeof(RTSPHeader)); rt->seq++; - pstrcpy(buf, sizeof(buf), cmd); + av_strlcpy(buf, cmd, sizeof(buf)); snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq); - pstrcat(buf, sizeof(buf), buf1); + av_strlcat(buf, buf1, sizeof(buf)); if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) { snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id); - pstrcat(buf, sizeof(buf), buf1); + av_strlcat(buf, buf1, sizeof(buf)); } - pstrcat(buf, sizeof(buf), "\r\n"); + av_strlcat(buf, "\r\n", sizeof(buf)); #ifdef DEBUG printf("Sending:\n%s--\n", buf); #endif @@ -797,14 +802,14 @@ static void rtsp_send_cmd(AVFormatContext *s, reply->status_code = atoi(buf1); } else { rtsp_parse_line(reply, p); - pstrcat(rt->last_reply, sizeof(rt->last_reply), p); - pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n"); + av_strlcat(rt->last_reply, p, sizeof(rt->last_reply)); + av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply)); } line_count++; } if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') - pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id); + av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id)); content_length = reply->content_length; if (content_length > 0) { @@ -815,12 +820,8 @@ static void rtsp_send_cmd(AVFormatContext *s, } if (content_ptr) *content_ptr = content; -} - - -void rtsp_set_callback(FFRTSPCallback *rtsp_cb) -{ - ff_rtsp_callback = rtsp_cb; + else + av_free(content); } @@ -849,13 +850,13 @@ static int rtsp_read_header(AVFormatContext *s, AVFormatParameters *ap) { RTSPState *rt = s->priv_data; - char host[1024], path[1024], tcpname[1024], cmd[2048]; + char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option; URLContext *rtsp_hd; int port, i, j, ret, err; RTSPHeader reply1, *reply = &reply1; unsigned char *content = NULL; RTSPStream *rtsp_st; - int protocol_mask; + int protocol_mask = 0; AVStream *st; /* extract hostname and port */ @@ -864,10 +865,34 @@ static int rtsp_read_header(AVFormatContext *s, if (port < 0) port = RTSP_DEFAULT_PORT; + /* search for options */ + option_list = strchr(path, '?'); + if (option_list) { + /* remove the options from the path */ + *option_list++ = 0; + while(option_list) { + /* move the option pointer */ + option = option_list; + option_list = strchr(option_list, '&'); + if (option_list) + *(option_list++) = 0; + /* handle the options */ + if (strcmp(option, "udp") == 0) + protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP); + else if (strcmp(option, "multicast") == 0) + protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP_MULTICAST); + else if (strcmp(option, "tcp") == 0) + protocol_mask = (1<< RTSP_PROTOCOL_RTP_TCP); + } + } + + if (!protocol_mask) + protocol_mask = rtsp_default_protocols; + /* open the tcp connexion */ snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port); if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) - return AVERROR_IO; + return AVERROR(EIO); rt->rtsp_hd = rtsp_hd; rt->seq = 0; @@ -894,8 +919,6 @@ static int rtsp_read_header(AVFormatContext *s, goto fail; } - protocol_mask = rtsp_default_protocols; - /* for each stream, make the setup request */ /* XXX: we assume the same server is used for the control of each RTSP stream */ @@ -915,9 +938,9 @@ static int rtsp_read_header(AVFormatContext *s, /* first try in specified port range */ if (RTSP_RTP_PORT_MIN != 0) { while(j <= RTSP_RTP_PORT_MAX) { - snprintf(buf, sizeof(buf), "rtp://?localport=%d", j); + snprintf(buf, sizeof(buf), "rtp://%s?localport=%d", host, j); + j += 2; /* we will use two port by rtp stream (rtp and rtcp) */ if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) { - j += 2; /* we will use two port by rtp stream (rtp and rtcp) */ goto rtp_opened; } } @@ -933,7 +956,7 @@ static int rtsp_read_header(AVFormatContext *s, rtp_opened: port = rtp_get_local_port(rtsp_st->rtp_handle); if (transport[0] != '\0') - pstrcat(transport, sizeof(transport), ","); + av_strlcat(transport, ",", sizeof(transport)); snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, "RTP/AVP/UDP;unicast;client_port=%d-%d", port, port + 1); @@ -942,14 +965,14 @@ static int rtsp_read_header(AVFormatContext *s, /* RTP/TCP */ else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) { if (transport[0] != '\0') - pstrcat(transport, sizeof(transport), ","); + av_strlcat(transport, ",", sizeof(transport)); snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, "RTP/AVP/TCP"); } else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) { if (transport[0] != '\0') - pstrcat(transport, sizeof(transport), ","); + av_strlcat(transport, ",", sizeof(transport)); snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, "RTP/AVP/UDP;multicast"); @@ -1004,15 +1027,13 @@ static int rtsp_read_header(AVFormatContext *s, case RTSP_PROTOCOL_RTP_UDP_MULTICAST: { char url[1024]; - int ttl; + struct in_addr in; - ttl = reply->transports[0].ttl; - if (!ttl) - ttl = 16; + in.s_addr = htonl(reply->transports[0].destination); snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", - host, - reply->transports[0].server_port_min, - ttl); + inet_ntoa(in), + reply->transports[0].port_min, + reply->transports[0].ttl); if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) { err = AVERROR_INVALIDDATA; goto fail; @@ -1029,7 +1050,7 @@ static int rtsp_read_header(AVFormatContext *s, rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data); if (!rtsp_st->rtp_ctx) { - err = AVERROR_NOMEM; + err = AVERROR(ENOMEM); goto fail; } else { if(rtsp_st->dynamic_handler) { @@ -1039,16 +1060,6 @@ static int rtsp_read_header(AVFormatContext *s, } } - /* use callback if available to extend setup */ - if (ff_rtsp_callback) { - if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, - NULL, 0, rt->last_reply) < 0) { - err = AVERROR_INVALIDDATA; - goto fail; - } - } - - rt->state = RTSP_STATE_IDLE; rt->seek_timestamp = 0; /* default is to start stream at position zero */ @@ -1093,7 +1104,7 @@ static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, if (ret != 3) return -1; id = buf[0]; - len = (buf[1] << 8) | buf[2]; + len = AV_RB16(buf + 1); #ifdef DEBUG_RTP_TCP printf("id=%d len=%d\n", id, len); #endif @@ -1128,7 +1139,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, for(;;) { if (url_interrupt_cb()) - return -1; + return AVERROR(EINTR); FD_ZERO(&rfds); fd_max = -1; for(i = 0; i < rt->nb_rtsp_streams; i++) { @@ -1189,12 +1200,12 @@ static int rtsp_read_packet(AVFormatContext *s, case RTSP_PROTOCOL_RTP_UDP: case RTSP_PROTOCOL_RTP_UDP_MULTICAST: len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf)); - if (rtsp_st->rtp_ctx) + if (len >=0 && rtsp_st->rtp_ctx) rtp_check_and_send_back_rr(rtsp_st->rtp_ctx, len); break; } if (len < 0) - return AVERROR_IO; + return len; ret = rtp_parse_packet(rtsp_st->rtp_ctx, pkt, buf, len); if (ret < 0) goto redo; @@ -1262,7 +1273,7 @@ static int rtsp_read_seek(AVFormatContext *s, int stream_index, { RTSPState *rt = s->priv_data; - rt->seek_timestamp = timestamp; + rt->seek_timestamp = av_rescale_q(timestamp, s->streams[stream_index]->time_base, AV_TIME_BASE_Q); switch(rt->state) { default: case RTSP_STATE_IDLE: @@ -1295,16 +1306,12 @@ static int rtsp_read_close(AVFormatContext *s) s->filename); rtsp_send_cmd(s, cmd, reply, NULL); - if (ff_rtsp_callback) { - ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id, - NULL, 0, NULL); - } - rtsp_close_streams(rt); url_close(rt->rtsp_hd); return 0; } +#ifdef CONFIG_RTSP_DEMUXER AVInputFormat rtsp_demuxer = { "rtsp", "RTSP input format", @@ -1318,6 +1325,7 @@ AVInputFormat rtsp_demuxer = { .read_play = rtsp_read_play, .read_pause = rtsp_read_pause, }; +#endif static int sdp_probe(AVProbeData *p1) { @@ -1325,7 +1333,7 @@ static int sdp_probe(AVProbeData *p1) /* we look for a line beginning "c=IN IP4" */ while (p < p_end && *p != '\0') { - if (p + sizeof("c=IN IP4") - 1 < p_end && strstart(p, "c=IN IP4", NULL)) + if (p + sizeof("c=IN IP4") - 1 < p_end && av_strstart(p, "c=IN IP4", NULL)) return AVPROBE_SCORE_MAX / 2; while(p < p_end - 1 && *p != '\n') p++; @@ -1352,7 +1360,7 @@ static int sdp_read_header(AVFormatContext *s, /* read the whole sdp file */ /* XXX: better loading */ content = av_malloc(SDP_MAX_SIZE); - size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1); + size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1); if (size <= 0) { av_free(content); return AVERROR_INVALIDDATA; @@ -1382,7 +1390,7 @@ static int sdp_read_header(AVFormatContext *s, s->ctx_flags |= AVFMTCTX_NOHEADER; rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data); if (!rtsp_st->rtp_ctx) { - err = AVERROR_NOMEM; + err = AVERROR(ENOMEM); goto fail; } else { if(rtsp_st->dynamic_handler) { @@ -1422,6 +1430,7 @@ AVInputFormat sdp_demuxer = { }; #endif +#ifdef CONFIG_REDIR_DEMUXER /* dummy redirector format (used directly in av_open_input_file now) */ static int redir_probe(AVProbeData *pd) { @@ -1429,18 +1438,18 @@ static int redir_probe(AVProbeData *pd) p = pd->buf; while (redir_isspace(*p)) p++; - if (strstart(p, "http://", NULL) || - strstart(p, "rtsp://", NULL)) + if (av_strstart(p, "http://", NULL) || + av_strstart(p, "rtsp://", NULL)) return AVPROBE_SCORE_MAX; return 0; } -/* called from utils.c */ -int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f) +static int redir_read_header(AVFormatContext *s, AVFormatParameters *ap) { char buf[4096], *q; int c; AVFormatContext *ic = NULL; + ByteIOContext *f = s->pb; /* parse each URL and try to open it */ c = url_fgetc(f); @@ -1468,11 +1477,13 @@ int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f) if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0) break; } - *ic_ptr = ic; if (!ic) - return AVERROR_IO; - else - return 0; + return AVERROR(EIO); + + *s = *ic; + url_fclose(f); + + return 0; } AVInputFormat redir_demuxer = { @@ -1480,7 +1491,8 @@ AVInputFormat redir_demuxer = { "Redirector format", 0, redir_probe, - NULL, + redir_read_header, NULL, NULL, }; +#endif diff --git a/contrib/ffmpeg/libavformat/rtsp.h b/contrib/ffmpeg/libavformat/rtsp.h index 481e2ba49..6adadbc81 100644 --- a/contrib/ffmpeg/libavformat/rtsp.h +++ b/contrib/ffmpeg/libavformat/rtsp.h @@ -18,9 +18,11 @@ * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef RTSP_H -#define RTSP_H +#ifndef FFMPEG_RTSP_H +#define FFMPEG_RTSP_H +#include <stdint.h> +#include "avformat.h" #include "rtspcodes.h" enum RTSPProtocol { @@ -76,19 +78,16 @@ typedef int FFRTSPCallback(enum RTSPCallbackAction action, char *buf, int buf_size, void *arg); -/** useful for modules: set RTSP callback function */ -void rtsp_set_callback(FFRTSPCallback *rtsp_cb); - int rtsp_init(void); void rtsp_parse_line(RTSPHeader *reply, const char *buf); +#if LIBAVFORMAT_VERSION_INT < (53 << 16) extern int rtsp_default_protocols; +#endif extern int rtsp_rtp_port_min; extern int rtsp_rtp_port_max; -extern FFRTSPCallback *ff_rtsp_callback; -extern AVInputFormat rtsp_demuxer; int rtsp_pause(AVFormatContext *s); int rtsp_resume(AVFormatContext *s); -#endif /* RTSP_H */ +#endif /* FFMPEG_RTSP_H */ diff --git a/contrib/ffmpeg/libavformat/rtspcodes.h b/contrib/ffmpeg/libavformat/rtspcodes.h index 74cfb5d5b..d4ad25b76 100644 --- a/contrib/ffmpeg/libavformat/rtspcodes.h +++ b/contrib/ffmpeg/libavformat/rtspcodes.h @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef FFMPEG_RTSPCODES_H +#define FFMPEG_RTSPCODES_H + /** RTSP handling */ enum RTSPStatusCode { RTSP_STATUS_OK =200, /**< OK */ @@ -34,3 +37,4 @@ RTSP_STATUS_SERVICE =503, /**< Service Unavailable */ RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */ }; +#endif /* FFMPEG_RTSPCODES_H */ diff --git a/contrib/ffmpeg/libavformat/sdp.c b/contrib/ffmpeg/libavformat/sdp.c new file mode 100644 index 000000000..3a71afcbe --- /dev/null +++ b/contrib/ffmpeg/libavformat/sdp.c @@ -0,0 +1,320 @@ +/* + * copyright (c) 2007 Luca Abeni + * + * 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 "avstring.h" +#include "avformat.h" +#include "avc.h" +#include "base64.h" +#include "rtp.h" + +#ifdef CONFIG_RTP_MUXER +#define MAX_EXTRADATA_SIZE ((INT_MAX - 10) / 2) + +struct sdp_session_level { + int sdp_version; /**< protocol version (currently 0) */ + int id; /**< session id */ + int version; /**< session version */ + int start_time; /**< session start time (NTP time, in seconds), + or 0 in case of permanent session */ + int end_time; /**< session end time (NTP time, in seconds), + or 0 if the session is not bounded */ + int ttl; /**< TTL, in case of multicast stream */ + const char *user; /**< username of the session's creator */ + const char *src_addr; /**< IP address of the machine from which the session was created */ + const char *dst_addr; /**< destination IP address (can be multicast) */ + const char *name; /**< session name (can be an empty string) */ +}; + +static void dest_write(char *buff, int size, const char *dest_addr, int ttl) +{ + if (dest_addr) { + if (ttl > 0) { + av_strlcatf(buff, size, "c=IN IP4 %s/%d\r\n", dest_addr, ttl); + } else { + av_strlcatf(buff, size, "c=IN IP4 %s\r\n", dest_addr); + } + } +} + +static void sdp_write_header(char *buff, int size, struct sdp_session_level *s) +{ + av_strlcatf(buff, size, "v=%d\r\n" + "o=- %d %d IN IPV4 %s\r\n" + "t=%d %d\r\n" + "s=%s\r\n" + "a=tool:libavformat\r\n", + s->sdp_version, + s->id, s->version, s->src_addr, + s->start_time, s->end_time, + s->name[0] ? s->name : "No Name"); + dest_write(buff, size, s->dst_addr, s->ttl); +} + +static int get_address(char *dest_addr, int size, int *ttl, const char *url) +{ + int port; + const char *p; + + url_split(NULL, 0, NULL, 0, dest_addr, size, &port, NULL, 0, url); + + *ttl = 0; + p = strchr(url, '?'); + if (p) { + char buff[64]; + int is_multicast = find_info_tag(buff, sizeof(buff), "multicast", p); + + if (is_multicast) { + if (find_info_tag(buff, sizeof(buff), "ttl", p)) { + *ttl = strtol(buff, NULL, 10); + } else { + *ttl = 5; + } + } + } + + return port; +} + +#define MAX_PSET_SIZE 1024 +static char *extradata2psets(AVCodecContext *c) +{ + char *psets, *p; + const uint8_t *r; + const char *pset_string = "; sprop-parameter-sets="; + + if (c->extradata_size > MAX_EXTRADATA_SIZE) { + av_log(c, AV_LOG_ERROR, "Too many extra data!\n"); + + return NULL; + } + + psets = av_mallocz(MAX_PSET_SIZE); + if (psets == NULL) { + av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the parameter sets\n"); + return NULL; + } + memcpy(psets, pset_string, strlen(pset_string)); + p = psets + strlen(pset_string); + r = ff_avc_find_startcode(c->extradata, c->extradata + c->extradata_size); + while (r < c->extradata + c->extradata_size) { + const uint8_t *r1; + + while (!*(r++)); + r1 = ff_avc_find_startcode(r, c->extradata + c->extradata_size); + if (p != (psets + strlen(pset_string))) { + *p = ','; + p++; + } + if (av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r) == NULL) { + av_log(c, AV_LOG_ERROR, "Cannot BASE64 encode %d %d!\n", MAX_PSET_SIZE - (p - psets), r1 - r); + av_free(psets); + + return NULL; + } + p += strlen(p); + r = r1; + } + + return psets; +} + +static void digit_to_char(char *dst, uint8_t src) +{ + if (src < 10) { + *dst = '0' + src; + } else { + *dst = 'A' + src - 10; + } +} + +static char *data_to_hex(char *buff, const uint8_t *src, int s) +{ + int i; + + for(i = 0; i < s; i++) { + digit_to_char(buff + 2 * i, src[i] >> 4); + digit_to_char(buff + 2 * i + 1, src[i] & 0xF); + } + + return buff; +} + +static char *extradata2config(AVCodecContext *c) +{ + char *config; + + if (c->extradata_size > MAX_EXTRADATA_SIZE) { + av_log(c, AV_LOG_ERROR, "Too many extra data!\n"); + + return NULL; + } + config = av_malloc(10 + c->extradata_size * 2); + if (config == NULL) { + av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the config info\n"); + return NULL; + } + memcpy(config, "; config=", 9); + data_to_hex(config + 9, c->extradata, c->extradata_size); + config[9 + c->extradata_size * 2] = 0; + + return config; +} + +static char *sdp_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type) +{ + char *config = NULL; + + switch (c->codec_id) { + case CODEC_ID_H264: + if (c->extradata_size) { + config = extradata2psets(c); + } + av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n" + "a=fmtp:%d packetization-mode=1%s\r\n", + payload_type, + payload_type, config ? config : ""); + break; + case CODEC_ID_MPEG4: + if (c->extradata_size) { + config = extradata2config(c); + } + av_strlcatf(buff, size, "a=rtpmap:%d MP4V-ES/90000\r\n" + "a=fmtp:%d profile-level-id=1%s\r\n", + payload_type, + payload_type, config ? config : ""); + break; + case CODEC_ID_AAC: + if (c->extradata_size) { + config = extradata2config(c); + } else { + /* FIXME: maybe we can forge config information based on the + * codec parameters... + */ + av_log(c, AV_LOG_ERROR, "AAC with no global headers is currently not supported\n"); + return NULL; + } + if (config == NULL) { + return NULL; + } + av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n" + "a=fmtp:%d profile-level-id=1;" + "mode=AAC-hbr;sizelength=13;indexlength=3;" + "indexdeltalength=3%s\r\n", + payload_type, c->sample_rate, c->channels, + payload_type, config); + break; + case CODEC_ID_PCM_S16BE: + if (payload_type >= 96) + av_strlcatf(buff, size, "a=rtpmap:%d L16/%d/%d\r\n", + payload_type, + c->sample_rate, c->channels); + break; + case CODEC_ID_PCM_MULAW: + if (payload_type >= 96) + av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n", + payload_type, + c->sample_rate, c->channels); + break; + case CODEC_ID_PCM_ALAW: + if (payload_type >= 96) + av_strlcatf(buff, size, "a=rtpmap:%d PCMA/%d/%d\r\n", + payload_type, + c->sample_rate, c->channels); + break; + default: + /* Nothing special to do, here... */ + break; + } + + av_free(config); + + return buff; +} + +static void sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, int port, int ttl) +{ + const char *type; + int payload_type; + + payload_type = rtp_get_payload_type(c); + if (payload_type < 0) { + payload_type = 96; /* FIXME: how to assign a private pt? rtp.c is broken too */ + } + + switch (c->codec_type) { + case CODEC_TYPE_VIDEO : type = "video" ; break; + case CODEC_TYPE_AUDIO : type = "audio" ; break; + case CODEC_TYPE_SUBTITLE: type = "text" ; break; + default : type = "application"; break; + } + + av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type); + dest_write(buff, size, dest_addr, ttl); + + sdp_media_attributes(buff, size, c, payload_type); +} + +int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) +{ + struct sdp_session_level s; + int i, j, port, ttl; + char dst[32]; + + memset(buff, 0, size); + memset(&s, 0, sizeof(struct sdp_session_level)); + s.user = "-"; + s.src_addr = "127.0.0.1"; /* FIXME: Properly set this */ + s.name = ac[0]->title; + + port = 0; + ttl = 0; + if (n_files == 1) { + port = get_address(dst, sizeof(dst), &ttl, ac[0]->filename); + if (port > 0) { + s.dst_addr = dst; + s.ttl = ttl; + } + } + sdp_write_header(buff, size, &s); + + dst[0] = 0; + for (i = 0; i < n_files; i++) { + if (n_files != 1) { + port = get_address(dst, sizeof(dst), &ttl, ac[i]->filename); + } + for (j = 0; j < ac[i]->nb_streams; j++) { + sdp_write_media(buff, size, + ac[i]->streams[j]->codec, dst[0] ? dst : NULL, + (port > 0) ? port + j * 2 : 0, ttl); + if (port <= 0) { + av_strlcatf(buff, size, + "a=control:streamid=%d\r\n", i + j); + } + } + } + + return 0; +} +#else +int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) +{ + return AVERROR(ENOSYS); +} +#endif diff --git a/contrib/ffmpeg/libavformat/segafilm.c b/contrib/ffmpeg/libavformat/segafilm.c index b5375ccf7..5b149a7ca 100644 --- a/contrib/ffmpeg/libavformat/segafilm.c +++ b/contrib/ffmpeg/libavformat/segafilm.c @@ -66,9 +66,6 @@ typedef struct FilmDemuxContext { static int film_probe(AVProbeData *p) { - if (p->buf_size < 4) - return 0; - if (AV_RB32(&p->buf[0]) != FILM_TAG) return 0; @@ -78,8 +75,8 @@ static int film_probe(AVProbeData *p) static int film_read_header(AVFormatContext *s, AVFormatParameters *ap) { - FilmDemuxContext *film = (FilmDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + FilmDemuxContext *film = s->priv_data; + ByteIOContext *pb = s->pb; AVStream *st; unsigned char scratch[256]; int i; @@ -92,7 +89,7 @@ static int film_read_header(AVFormatContext *s, /* load the main FILM header */ if (get_buffer(pb, scratch, 16) != 16) - return AVERROR_IO; + return AVERROR(EIO); data_offset = AV_RB32(&scratch[4]); film->version = AV_RB32(&scratch[8]); @@ -100,7 +97,7 @@ static int film_read_header(AVFormatContext *s, if (film->version == 0) { /* special case for Lemmings .film files; 20-byte header */ if (get_buffer(pb, scratch, 20) != 20) - return AVERROR_IO; + return AVERROR(EIO); /* make some assumptions about the audio parameters */ film->audio_type = CODEC_ID_PCM_S8; film->audio_samplerate = 22050; @@ -109,8 +106,8 @@ static int film_read_header(AVFormatContext *s, } else { /* normal Saturn .cpk files; 32-byte header */ if (get_buffer(pb, scratch, 32) != 32) - return AVERROR_IO; - film->audio_samplerate = AV_RB16(&scratch[24]);; + return AVERROR(EIO); + film->audio_samplerate = AV_RB16(&scratch[24]); film->audio_channels = scratch[21]; film->audio_bits = scratch[22]; if (film->audio_bits == 8) @@ -133,7 +130,7 @@ static int film_read_header(AVFormatContext *s, if (film->video_type) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); film->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->codec_id = film->video_type; @@ -145,7 +142,7 @@ static int film_read_header(AVFormatContext *s, if (film->audio_type) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); film->audio_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = film->audio_type; @@ -161,7 +158,7 @@ static int film_read_header(AVFormatContext *s, /* load the sample table */ if (get_buffer(pb, scratch, 16) != 16) - return AVERROR_IO; + return AVERROR(EIO); if (AV_RB32(&scratch[0]) != STAB_TAG) return AVERROR_INVALIDDATA; film->base_clock = AV_RB32(&scratch[8]); @@ -178,7 +175,7 @@ static int film_read_header(AVFormatContext *s, /* load the next sample record and transfer it to an internal struct */ if (get_buffer(pb, scratch, 16) != 16) { av_free(film->sample_table); - return AVERROR_IO; + return AVERROR(EIO); } film->sample_table[i].sample_offset = data_offset + AV_RB32(&scratch[0]); @@ -206,15 +203,15 @@ static int film_read_header(AVFormatContext *s, static int film_read_packet(AVFormatContext *s, AVPacket *pkt) { - FilmDemuxContext *film = (FilmDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + FilmDemuxContext *film = s->priv_data; + ByteIOContext *pb = s->pb; film_sample_t *sample; int ret = 0; int i; int left, right; if (film->current_sample >= film->sample_count) - return AVERROR_IO; + return AVERROR(EIO); sample = &film->sample_table[film->current_sample]; @@ -226,14 +223,14 @@ static int film_read_packet(AVFormatContext *s, (film->video_type == CODEC_ID_CINEPAK)) { pkt->pos= url_ftell(pb); if (av_new_packet(pkt, sample->sample_size)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); get_buffer(pb, pkt->data, sample->sample_size); } else if ((sample->stream == film->audio_stream_index) && (film->audio_channels == 2)) { /* stereo PCM needs to be interleaved */ if (av_new_packet(pkt, sample->sample_size)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); /* make sure the interleave buffer is large enough */ if (sample->sample_size > film->stereo_buffer_size) { @@ -245,7 +242,7 @@ static int film_read_packet(AVFormatContext *s, pkt->pos= url_ftell(pb); ret = get_buffer(pb, film->stereo_buffer, sample->sample_size); if (ret != sample->sample_size) - ret = AVERROR_IO; + ret = AVERROR(EIO); left = 0; right = sample->sample_size / 2; @@ -263,7 +260,7 @@ static int film_read_packet(AVFormatContext *s, } else { ret= av_get_packet(pb, pkt, sample->sample_size); if (ret != sample->sample_size) - ret = AVERROR_IO; + ret = AVERROR(EIO); } pkt->stream_index = sample->stream; @@ -276,7 +273,7 @@ static int film_read_packet(AVFormatContext *s, static int film_read_close(AVFormatContext *s) { - FilmDemuxContext *film = (FilmDemuxContext *)s->priv_data; + FilmDemuxContext *film = s->priv_data; av_free(film->sample_table); av_free(film->stereo_buffer); diff --git a/contrib/ffmpeg/libavformat/sierravmd.c b/contrib/ffmpeg/libavformat/sierravmd.c index 3e1c8597d..5e68a81c4 100644 --- a/contrib/ffmpeg/libavformat/sierravmd.c +++ b/contrib/ffmpeg/libavformat/sierravmd.c @@ -59,9 +59,6 @@ typedef struct VmdDemuxContext { static int vmd_probe(AVProbeData *p) { - if (p->buf_size < 2) - return 0; - /* check if the first 2 bytes of the file contain the appropriate size * of a VMD header chunk */ if (AV_RL16(&p->buf[0]) != VMD_HEADER_SIZE - 2) @@ -74,9 +71,9 @@ static int vmd_probe(AVProbeData *p) static int vmd_read_header(AVFormatContext *s, AVFormatParameters *ap) { - VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; - AVStream *st, *vst; + VmdDemuxContext *vmd = s->priv_data; + ByteIOContext *pb = s->pb; + AVStream *st = NULL, *vst; unsigned int toc_offset; unsigned char *raw_frame_table; int raw_frame_table_size; @@ -92,12 +89,12 @@ static int vmd_read_header(AVFormatContext *s, /* fetch the main header, including the 2 header length bytes */ url_fseek(pb, 0, SEEK_SET); if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE) - return AVERROR_IO; + return AVERROR(EIO); /* start up the decoders */ vst = av_new_stream(s, 0); if (!vst) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(vst, 33, 1, 10); vmd->video_stream_index = vst->index; vst->codec->codec_type = CODEC_TYPE_VIDEO; @@ -114,7 +111,7 @@ static int vmd_read_header(AVFormatContext *s, if (vmd->sample_rate) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); vmd->audio_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_VMDAUDIO; @@ -158,13 +155,13 @@ static int vmd_read_header(AVFormatContext *s, if (!raw_frame_table || !vmd->frame_table) { av_free(raw_frame_table); av_free(vmd->frame_table); - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } if (get_buffer(pb, raw_frame_table, raw_frame_table_size) != raw_frame_table_size) { av_free(raw_frame_table); av_free(vmd->frame_table); - return AVERROR_IO; + return AVERROR(EIO); } total_frames = 0; @@ -184,6 +181,7 @@ static int vmd_read_header(AVFormatContext *s, continue; switch(type) { case 1: /* Audio Chunk */ + if (!st) break; /* first audio chunk contains several audio buffers */ if(current_audio_pts){ vmd->frame_table[total_frames].frame_offset = current_offset; @@ -247,20 +245,20 @@ static int vmd_read_header(AVFormatContext *s, static int vmd_read_packet(AVFormatContext *s, AVPacket *pkt) { - VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + VmdDemuxContext *vmd = s->priv_data; + ByteIOContext *pb = s->pb; int ret = 0; vmd_frame_t *frame; if (vmd->current_frame >= vmd->frame_count) - return AVERROR_IO; + return AVERROR(EIO); frame = &vmd->frame_table[vmd->current_frame]; /* position the stream (will probably be there already) */ url_fseek(pb, frame->frame_offset, SEEK_SET); if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); pkt->pos= url_ftell(pb); memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD); ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD, @@ -268,11 +266,11 @@ static int vmd_read_packet(AVFormatContext *s, if (ret != frame->frame_size) { av_free_packet(pkt); - ret = AVERROR_IO; + ret = AVERROR(EIO); } pkt->stream_index = frame->stream_index; pkt->pts = frame->pts; - av_log(NULL, AV_LOG_INFO, " dispatching %s frame with %d bytes and pts %"PRId64"\n", + av_log(NULL, AV_LOG_DEBUG, " dispatching %s frame with %d bytes and pts %"PRId64"\n", (frame->frame_record[0] == 0x02) ? "video" : "audio", frame->frame_size + BYTES_PER_FRAME_RECORD, pkt->pts); @@ -284,7 +282,7 @@ static int vmd_read_packet(AVFormatContext *s, static int vmd_read_close(AVFormatContext *s) { - VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data; + VmdDemuxContext *vmd = s->priv_data; av_free(vmd->frame_table); diff --git a/contrib/ffmpeg/libavformat/siff.c b/contrib/ffmpeg/libavformat/siff.c new file mode 100644 index 000000000..00b4eaa9d --- /dev/null +++ b/contrib/ffmpeg/libavformat/siff.c @@ -0,0 +1,237 @@ +/* + * Beam Software SIFF demuxer + * Copyright (c) 2007 Konstantin Shishkov. + * + * 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" + +enum SIFFTags{ + TAG_SIFF = MKTAG('S', 'I', 'F', 'F'), + TAG_BODY = MKTAG('B', 'O', 'D', 'Y'), + TAG_VBHD = MKTAG('V', 'B', 'H', 'D'), + TAG_SHDR = MKTAG('S', 'H', 'D', 'R'), + TAG_VBV1 = MKTAG('V', 'B', 'V', '1'), + TAG_SOUN = MKTAG('S', 'O', 'U', 'N'), +}; + +enum VBFlags{ + VB_HAS_GMC = 0x01, + VB_HAS_AUDIO = 0x04, + VB_HAS_VIDEO = 0x08, + VB_HAS_PALETTE = 0x10, + VB_HAS_LENGTH = 0x20 +}; + +typedef struct SIFFContext{ + int frames; + int cur_frame; + int rate; + int bits; + int block_align; + + int has_video; + int has_audio; + + int curstrm; + int pktsize; + int gmcsize; + int sndsize; + + int flags; + uint8_t gmc[4]; +}SIFFContext; + +static int siff_probe(AVProbeData *p) +{ + /* check file header */ + if (AV_RL32(p->buf) == TAG_SIFF) + return AVPROBE_SCORE_MAX; + else + return 0; +} + +static int create_audio_stream(AVFormatContext *s, SIFFContext *c) +{ + AVStream *ast; + ast = av_new_stream(s, 0); + if (!ast) + return -1; + ast->codec->codec_type = CODEC_TYPE_AUDIO; + ast->codec->codec_id = CODEC_ID_PCM_U8; + ast->codec->channels = 1; + ast->codec->bits_per_sample = c->bits; + ast->codec->sample_rate = c->rate; + ast->codec->frame_size = c->block_align; + av_set_pts_info(ast, 16, 1, c->rate); + return 0; +} + +static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb) +{ + AVStream *st; + int width, height; + + if (get_le32(pb) != TAG_VBHD){ + av_log(s, AV_LOG_ERROR, "Header chunk is missing\n"); + return -1; + } + if(get_be32(pb) != 32){ + av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n"); + return -1; + } + if(get_le16(pb) != 1){ + av_log(s, AV_LOG_ERROR, "Incorrect header version\n"); + return -1; + } + width = get_le16(pb); + height = get_le16(pb); + url_fskip(pb, 4); + c->frames = get_le16(pb); + if(!c->frames){ + av_log(s, AV_LOG_ERROR, "File contains no frames ???\n"); + return -1; + } + c->bits = get_le16(pb); + c->rate = get_le16(pb); + c->block_align = c->rate * (c->bits >> 3); + + url_fskip(pb, 16); //zeroes + + st = av_new_stream(s, 0); + if (!st) + return -1; + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_VB; + st->codec->codec_tag = MKTAG('V', 'B', 'V', '1'); + st->codec->width = width; + st->codec->height = height; + st->codec->pix_fmt = PIX_FMT_PAL8; + av_set_pts_info(st, 16, 1, 12); + + c->cur_frame = 0; + c->has_video = 1; + c->has_audio = !!c->rate; + c->curstrm = -1; + if (c->has_audio && create_audio_stream(s, c) < 0) + return -1; + return 0; +} + +static int siff_parse_soun(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb) +{ + if (get_le32(pb) != TAG_SHDR){ + av_log(s, AV_LOG_ERROR, "Header chunk is missing\n"); + return -1; + } + if(get_be32(pb) != 8){ + av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n"); + return -1; + } + url_fskip(pb, 4); //unknown value + c->rate = get_le16(pb); + c->bits = get_le16(pb); + c->block_align = c->rate * (c->bits >> 3); + return create_audio_stream(s, c); +} + +static int siff_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + ByteIOContext *pb = s->pb; + SIFFContext *c = s->priv_data; + uint32_t tag; + + if (get_le32(pb) != TAG_SIFF) + return -1; + url_fskip(pb, 4); //ignore size + tag = get_le32(pb); + + if (tag != TAG_VBV1 && tag != TAG_SOUN){ + av_log(s, AV_LOG_ERROR, "Not a VBV file\n"); + return -1; + } + + if (tag == TAG_VBV1 && siff_parse_vbv1(s, c, pb) < 0) + return -1; + if (tag == TAG_SOUN && siff_parse_soun(s, c, pb) < 0) + return -1; + if (get_le32(pb) != MKTAG('B', 'O', 'D', 'Y')){ + av_log(s, AV_LOG_ERROR, "'BODY' chunk is missing\n"); + return -1; + } + url_fskip(pb, 4); //ignore size + + return 0; +} + +static int siff_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + SIFFContext *c = s->priv_data; + int size; + + if (c->has_video){ + if (c->cur_frame >= c->frames) + return AVERROR(EIO); + if (c->curstrm == -1){ + c->pktsize = get_le32(s->pb) - 4; + c->flags = get_le16(s->pb); + c->gmcsize = (c->flags & VB_HAS_GMC) ? 4 : 0; + if (c->gmcsize) + get_buffer(s->pb, c->gmc, c->gmcsize); + c->sndsize = (c->flags & VB_HAS_AUDIO) ? get_le32(s->pb): 0; + c->curstrm = !!(c->flags & VB_HAS_AUDIO); + } + + if (!c->curstrm){ + size = c->pktsize - c->sndsize; + if (av_new_packet(pkt, size) < 0) + return AVERROR(ENOMEM); + AV_WL16(pkt->data, c->flags); + if (c->gmcsize) + memcpy(pkt->data + 2, c->gmc, c->gmcsize); + get_buffer(s->pb, pkt->data + 2 + c->gmcsize, size - c->gmcsize - 2); + pkt->stream_index = 0; + c->curstrm = -1; + }else{ + if (av_get_packet(s->pb, pkt, c->sndsize - 4) < 0) + return AVERROR(EIO); + pkt->stream_index = 1; + c->curstrm = 0; + } + if(!c->cur_frame || c->curstrm) + pkt->flags |= PKT_FLAG_KEY; + if (c->curstrm == -1) + c->cur_frame++; + }else{ + size = av_get_packet(s->pb, pkt, c->block_align); + if(size <= 0) + return AVERROR(EIO); + } + return pkt->size; +} + +AVInputFormat siff_demuxer = { + "siff", + "Beam Software SIFF", + sizeof(SIFFContext), + siff_probe, + siff_read_header, + siff_read_packet, + .extensions = "vb,son" +}; diff --git a/contrib/ffmpeg/libavformat/smacker.c b/contrib/ffmpeg/libavformat/smacker.c index 04fde3d03..562a41616 100644 --- a/contrib/ffmpeg/libavformat/smacker.c +++ b/contrib/ffmpeg/libavformat/smacker.c @@ -28,6 +28,7 @@ #include "bswap.h" #define SMACKER_PAL 0x01 +#define SMACKER_FLAG_RING_FRAME 0x01 enum SAudFlags { SMK_AUD_PACKED = 0x80000000, @@ -88,8 +89,6 @@ static const uint8_t smk_pal[64] = { static int smacker_probe(AVProbeData *p) { - if (p->buf_size < 4) - return 0; if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K' && (p->buf[3] == '2' || p->buf[3] == '4')) return AVPROBE_SCORE_MAX; @@ -99,8 +98,8 @@ static int smacker_probe(AVProbeData *p) static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; - SmackerContext *smk = (SmackerContext *)s->priv_data; + ByteIOContext *pb = s->pb; + SmackerContext *smk = s->priv_data; AVStream *st, *ast[7]; int i, ret; int tbase; @@ -114,6 +113,8 @@ static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) smk->frames = get_le32(pb); smk->pts_inc = (int32_t)get_le32(pb); smk->flags = get_le32(pb); + if(smk->flags & SMACKER_FLAG_RING_FRAME) + smk->frames++; for(i = 0; i < 7; i++) smk->audio[i] = get_le32(pb); smk->treesize = get_le32(pb); @@ -201,7 +202,7 @@ static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) if(ret != st->codec->extradata_size - 16){ av_free(smk->frm_size); av_free(smk->frm_flags); - return AVERROR_IO; + return AVERROR(EIO); } ((int32_t*)st->codec->extradata)[0] = le2me_32(smk->mmap_size); ((int32_t*)st->codec->extradata)[1] = le2me_32(smk->mclr_size); @@ -217,7 +218,7 @@ static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) { - SmackerContext *smk = (SmackerContext *)s->priv_data; + SmackerContext *smk = s->priv_data; int flags; int ret; int i; @@ -225,35 +226,35 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) int palchange = 0; int pos; - if (url_feof(&s->pb) || smk->cur_frame >= smk->frames) + if (url_feof(s->pb) || smk->cur_frame >= smk->frames) return AVERROR(EIO); /* if we demuxed all streams, pass another frame */ if(smk->curstream < 0) { - url_fseek(&s->pb, smk->nextpos, 0); + url_fseek(s->pb, smk->nextpos, 0); frame_size = smk->frm_size[smk->cur_frame] & (~3); flags = smk->frm_flags[smk->cur_frame]; /* handle palette change event */ - pos = url_ftell(&s->pb); + pos = url_ftell(s->pb); if(flags & SMACKER_PAL){ int size, sz, t, off, j, pos; uint8_t *pal = smk->pal; uint8_t oldpal[768]; memcpy(oldpal, pal, 768); - size = get_byte(&s->pb); + size = get_byte(s->pb); size = size * 4 - 1; frame_size -= size; frame_size--; sz = 0; - pos = url_ftell(&s->pb) + size; + pos = url_ftell(s->pb) + size; while(sz < 256){ - t = get_byte(&s->pb); + t = get_byte(s->pb); if(t & 0x80){ /* skip palette entries */ sz += (t & 0x7F) + 1; pal += ((t & 0x7F) + 1) * 3; } else if(t & 0x40){ /* copy with offset */ - off = get_byte(&s->pb) * 3; + off = get_byte(s->pb) * 3; j = (t & 0x3F) + 1; while(j-- && sz < 256) { *pal++ = oldpal[off + 0]; @@ -264,12 +265,12 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) } } else { /* new entries */ *pal++ = smk_pal[t]; - *pal++ = smk_pal[get_byte(&s->pb) & 0x3F]; - *pal++ = smk_pal[get_byte(&s->pb) & 0x3F]; + *pal++ = smk_pal[get_byte(s->pb) & 0x3F]; + *pal++ = smk_pal[get_byte(s->pb) & 0x3F]; sz++; } } - url_fseek(&s->pb, pos, 0); + url_fseek(s->pb, pos, 0); palchange |= 1; } flags >>= 1; @@ -278,35 +279,35 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) for(i = 0; i < 7; i++) { if(flags & 1) { int size; - size = get_le32(&s->pb) - 4; + size = get_le32(s->pb) - 4; frame_size -= size; frame_size -= 4; smk->curstream++; smk->bufs[smk->curstream] = av_realloc(smk->bufs[smk->curstream], size); smk->buf_sizes[smk->curstream] = size; - ret = get_buffer(&s->pb, smk->bufs[smk->curstream], size); + ret = get_buffer(s->pb, smk->bufs[smk->curstream], size); if(ret != size) - return AVERROR_IO; + return AVERROR(EIO); smk->stream_id[smk->curstream] = smk->indexes[i]; } flags >>= 1; } if (av_new_packet(pkt, frame_size + 768)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); if(smk->frm_size[smk->cur_frame] & 1) palchange |= 2; pkt->data[0] = palchange; memcpy(pkt->data + 1, smk->pal, 768); - ret = get_buffer(&s->pb, pkt->data + 769, frame_size); + ret = get_buffer(s->pb, pkt->data + 769, frame_size); if(ret != frame_size) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = smk->videoindex; pkt->size = ret + 769; smk->cur_frame++; - smk->nextpos = url_ftell(&s->pb); + smk->nextpos = url_ftell(s->pb); } else { if (av_new_packet(pkt, smk->buf_sizes[smk->curstream])) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); pkt->size = smk->buf_sizes[smk->curstream]; pkt->stream_index = smk->stream_id[smk->curstream]; @@ -320,7 +321,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) static int smacker_read_close(AVFormatContext *s) { - SmackerContext *smk = (SmackerContext *)s->priv_data; + SmackerContext *smk = s->priv_data; int i; for(i = 0; i < 7; i++) diff --git a/contrib/ffmpeg/libavformat/sol.c b/contrib/ffmpeg/libavformat/sol.c index 951ec6eb9..97ebfdb5e 100644 --- a/contrib/ffmpeg/libavformat/sol.c +++ b/contrib/ffmpeg/libavformat/sol.c @@ -24,7 +24,7 @@ */ #include "avformat.h" -#include "allformats.h" +#include "raw.h" #include "riff.h" #include "bswap.h" @@ -35,8 +35,6 @@ static int sol_probe(AVProbeData *p) { /* check file header */ uint16_t magic; - if (p->buf_size <= 14) - return 0; magic=le2me_16(*((uint16_t*)p->buf)); if ((magic == 0x0B8D || magic == 0x0C0D || magic == 0x0C8D) && p->buf[2] == 'S' && p->buf[3] == 'O' && @@ -90,7 +88,7 @@ static int sol_read_header(AVFormatContext *s, { int size; unsigned int magic,tag; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; unsigned int id, codec, channels, rate, type; AVStream *st; @@ -132,9 +130,9 @@ static int sol_read_packet(AVFormatContext *s, { int ret; - if (url_feof(&s->pb)) + if (url_feof(s->pb)) return AVERROR(EIO); - ret= av_get_packet(&s->pb, pkt, MAX_SIZE); + ret= av_get_packet(s->pb, pkt, MAX_SIZE); pkt->stream_index = 0; /* note: we need to modify the packet size here to handle the last diff --git a/contrib/ffmpeg/libavformat/swf.c b/contrib/ffmpeg/libavformat/swf.c index 7d889af7d..387a96c5f 100644 --- a/contrib/ffmpeg/libavformat/swf.c +++ b/contrib/ffmpeg/libavformat/swf.c @@ -40,6 +40,7 @@ #define TAG_STREAMHEAD2 45 #define TAG_VIDEOSTREAM 60 #define TAG_VIDEOFRAME 61 +#define TAG_FILEATTRIBUTES 69 #define TAG_LONG 0x100 @@ -96,7 +97,7 @@ static const AVCodecTag swf_audio_codec_tags[] = { static void put_swf_tag(AVFormatContext *s, int tag) { SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; swf->tag_pos = url_ftell(pb); swf->tag = tag; @@ -112,7 +113,7 @@ static void put_swf_tag(AVFormatContext *s, int tag) static void put_swf_end_tag(AVFormatContext *s) { SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; offset_t pos; int tag_len, tag; @@ -187,17 +188,17 @@ static void put_swf_line_edge(PutBitContext *pb, int dx, int dy) mask = (1 << nbits) - 1; put_bits(pb, 4, nbits - 2); /* 16 bits precision */ if (dx == 0) { - put_bits(pb, 1, 0); - put_bits(pb, 1, 1); - put_bits(pb, nbits, dy & mask); + put_bits(pb, 1, 0); + put_bits(pb, 1, 1); + put_bits(pb, nbits, dy & mask); } else if (dy == 0) { - put_bits(pb, 1, 0); - put_bits(pb, 1, 0); - put_bits(pb, nbits, dx & mask); + put_bits(pb, 1, 0); + put_bits(pb, 1, 0); + put_bits(pb, nbits, dx & mask); } else { - put_bits(pb, 1, 1); - put_bits(pb, nbits, dx & mask); - put_bits(pb, nbits, dy & mask); + put_bits(pb, 1, 1); + put_bits(pb, nbits, dx & mask); + put_bits(pb, nbits, dy & mask); } } @@ -244,11 +245,12 @@ static void put_swf_matrix(ByteIOContext *pb, static int swf_write_header(AVFormatContext *s) { SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *enc, *audio_enc, *video_enc; PutBitContext p; uint8_t buf1[256]; int i, width, height, rate, rate_base; + int is_avm2; swf->audio_in_pos = 0; swf->sound_samples = 0; @@ -271,9 +273,9 @@ static int swf_write_header(AVFormatContext *s) return -1; } } else { - if ( enc->codec_id == CODEC_ID_VP6F || - enc->codec_id == CODEC_ID_FLV1 || - enc->codec_id == CODEC_ID_MJPEG ) { + if (enc->codec_id == CODEC_ID_VP6F || + enc->codec_id == CODEC_ID_FLV1 || + enc->codec_id == CODEC_ID_MJPEG) { video_enc = enc; } else { av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n"); @@ -283,7 +285,7 @@ static int swf_write_header(AVFormatContext *s) } if (!video_enc) { - /* currenty, cannot work correctly if audio only */ + /* currently, cannot work correctly if audio only */ swf->video_type = 0; width = 320; height = 200; @@ -297,18 +299,22 @@ static int swf_write_header(AVFormatContext *s) rate_base = video_enc->time_base.num; } - if (!audio_enc ) { + if (!audio_enc) { swf->audio_type = 0; - swf->samples_per_frame = ( 44100. * rate_base ) / rate; + swf->samples_per_frame = (44100. * rate_base) / rate; } else { swf->audio_type = audio_enc->codec_id; - swf->samples_per_frame = ( ( audio_enc->sample_rate ) * rate_base ) / rate; + swf->samples_per_frame = (audio_enc->sample_rate * rate_base) / rate; } + is_avm2 = !strcmp("avm2", s->oformat->name); + put_tag(pb, "FWS"); - if ( video_enc && video_enc->codec_id == CODEC_ID_VP6F ) { + if (is_avm2) { + put_byte(pb, 9); + } else if (video_enc && video_enc->codec_id == CODEC_ID_VP6F) { put_byte(pb, 8); /* version (version 8 and above support VP6 codec) */ - } else if ( video_enc && video_enc->codec_id == CODEC_ID_FLV1 ) { + } else if (video_enc && video_enc->codec_id == CODEC_ID_FLV1) { put_byte(pb, 6); /* version (version 6 and above support FLV1 codec) */ } else { put_byte(pb, 4); /* version (should use 4 for mpeg audio support) */ @@ -321,10 +327,17 @@ static int swf_write_header(AVFormatContext *s) swf->duration_pos = url_ftell(pb); put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */ + /* avm2/swf v9 (also v8?) files require a file attribute tag */ + if (is_avm2) { + put_swf_tag(s, TAG_FILEATTRIBUTES); + put_le32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */ + put_swf_end_tag(s); + } + /* define a shape with the jpeg inside */ - if ( video_enc && (video_enc->codec_id == CODEC_ID_VP6F || - video_enc->codec_id == CODEC_ID_FLV1 )) { - } else if ( video_enc && video_enc->codec_id == CODEC_ID_MJPEG ) { + if (video_enc && (video_enc->codec_id == CODEC_ID_VP6F || + video_enc->codec_id == CODEC_ID_FLV1)) { + } else if (video_enc && video_enc->codec_id == CODEC_ID_MJPEG) { put_swf_tag(s, TAG_DEFINESHAPE); put_le16(pb, SHAPE_ID); /* ID of shape */ @@ -336,7 +349,7 @@ static int swf_write_header(AVFormatContext *s) put_le16(pb, BITMAP_ID); /* bitmap ID */ /* position of the bitmap */ put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0, - 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0); + 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0); put_byte(pb, 0); /* no line style */ /* shape drawing */ @@ -367,7 +380,7 @@ static int swf_write_header(AVFormatContext *s) put_swf_end_tag(s); } - if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3 ) { + if (audio_enc && audio_enc->codec_id == CODEC_ID_MP3) { int v; /* start sound */ @@ -386,22 +399,22 @@ static int swf_write_header(AVFormatContext *s) break; default: /* not supported */ - av_log(s, AV_LOG_ERROR, "swf doesnt support that sample rate, choose from (44100, 22050, 11025)\n"); + av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n"); return -1; } v |= 0x02; /* 16 bit playback */ if (audio_enc->channels == 2) v |= 0x01; /* stereo playback */ - put_byte(&s->pb, v); + put_byte(s->pb, v); v |= 0x20; /* mp3 compressed */ - put_byte(&s->pb, v); - put_le16(&s->pb, swf->samples_per_frame); /* avg samples per frame */ - put_le16(&s->pb, 0); + put_byte(s->pb, v); + put_le16(s->pb, swf->samples_per_frame); /* avg samples per frame */ + put_le16(s->pb, 0); put_swf_end_tag(s); } - put_flush_packet(&s->pb); + put_flush_packet(s->pb); return 0; } @@ -409,95 +422,95 @@ static int swf_write_video(AVFormatContext *s, AVCodecContext *enc, const uint8_t *buf, int size) { SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; /* Flash Player limit */ - if ( swf->swf_frame_number == 16000 ) { + if (swf->swf_frame_number == 16000) { av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); } - if ( swf->video_type == CODEC_ID_VP6F || - swf->video_type == CODEC_ID_FLV1 ) { - if ( swf->video_frame_number == 0 ) { - /* create a new video object */ - put_swf_tag(s, TAG_VIDEOSTREAM); - put_le16(pb, VIDEO_ID); - put_le16(pb, 15000 ); /* hard flash player limit */ - put_le16(pb, enc->width); - put_le16(pb, enc->height); - put_byte(pb, 0); - put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type)); - put_swf_end_tag(s); - - /* place the video object for the first time */ - put_swf_tag(s, TAG_PLACEOBJECT2); - put_byte(pb, 0x36); - put_le16(pb, 1); - put_le16(pb, VIDEO_ID); - put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0); - put_le16(pb, swf->video_frame_number ); - put_byte(pb, 'v'); - put_byte(pb, 'i'); - put_byte(pb, 'd'); - put_byte(pb, 'e'); - put_byte(pb, 'o'); - put_byte(pb, 0x00); - put_swf_end_tag(s); - } else { - /* mark the character for update */ - put_swf_tag(s, TAG_PLACEOBJECT2); - put_byte(pb, 0x11); - put_le16(pb, 1); - put_le16(pb, swf->video_frame_number ); - put_swf_end_tag(s); - } + if (swf->video_type == CODEC_ID_VP6F || + swf->video_type == CODEC_ID_FLV1) { + if (swf->video_frame_number == 0) { + /* create a new video object */ + put_swf_tag(s, TAG_VIDEOSTREAM); + put_le16(pb, VIDEO_ID); + put_le16(pb, 15000); /* hard flash player limit */ + put_le16(pb, enc->width); + put_le16(pb, enc->height); + put_byte(pb, 0); + put_byte(pb,codec_get_tag(swf_codec_tags,swf->video_type)); + put_swf_end_tag(s); + + /* place the video object for the first time */ + put_swf_tag(s, TAG_PLACEOBJECT2); + put_byte(pb, 0x36); + put_le16(pb, 1); + put_le16(pb, VIDEO_ID); + put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0); + put_le16(pb, swf->video_frame_number); + put_byte(pb, 'v'); + put_byte(pb, 'i'); + put_byte(pb, 'd'); + put_byte(pb, 'e'); + put_byte(pb, 'o'); + put_byte(pb, 0x00); + put_swf_end_tag(s); + } else { + /* mark the character for update */ + put_swf_tag(s, TAG_PLACEOBJECT2); + put_byte(pb, 0x11); + put_le16(pb, 1); + put_le16(pb, swf->video_frame_number); + put_swf_end_tag(s); + } - /* set video frame data */ - put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG); - put_le16(pb, VIDEO_ID); - put_le16(pb, swf->video_frame_number++ ); - put_buffer(pb, buf, size); - put_swf_end_tag(s); - } else if ( swf->video_type == CODEC_ID_MJPEG ) { - if (swf->swf_frame_number > 0) { - /* remove the shape */ - put_swf_tag(s, TAG_REMOVEOBJECT); - put_le16(pb, SHAPE_ID); /* shape ID */ - put_le16(pb, 1); /* depth */ - put_swf_end_tag(s); - - /* free the bitmap */ - put_swf_tag(s, TAG_FREECHARACTER); - put_le16(pb, BITMAP_ID); - put_swf_end_tag(s); - } + /* set video frame data */ + put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG); + put_le16(pb, VIDEO_ID); + put_le16(pb, swf->video_frame_number++); + put_buffer(pb, buf, size); + put_swf_end_tag(s); + } else if (swf->video_type == CODEC_ID_MJPEG) { + if (swf->swf_frame_number > 0) { + /* remove the shape */ + put_swf_tag(s, TAG_REMOVEOBJECT); + put_le16(pb, SHAPE_ID); /* shape ID */ + put_le16(pb, 1); /* depth */ + put_swf_end_tag(s); + + /* free the bitmap */ + put_swf_tag(s, TAG_FREECHARACTER); + put_le16(pb, BITMAP_ID); + put_swf_end_tag(s); + } - put_swf_tag(s, TAG_JPEG2 | TAG_LONG); + put_swf_tag(s, TAG_JPEG2 | TAG_LONG); - put_le16(pb, BITMAP_ID); /* ID of the image */ + put_le16(pb, BITMAP_ID); /* ID of the image */ - /* a dummy jpeg header seems to be required */ - put_byte(pb, 0xff); - put_byte(pb, 0xd8); - put_byte(pb, 0xff); - put_byte(pb, 0xd9); - /* write the jpeg image */ - put_buffer(pb, buf, size); + /* a dummy jpeg header seems to be required */ + put_byte(pb, 0xff); + put_byte(pb, 0xd8); + put_byte(pb, 0xff); + put_byte(pb, 0xd9); + /* write the jpeg image */ + put_buffer(pb, buf, size); - put_swf_end_tag(s); + put_swf_end_tag(s); - /* draw the shape */ + /* draw the shape */ - put_swf_tag(s, TAG_PLACEOBJECT); - put_le16(pb, SHAPE_ID); /* shape ID */ - put_le16(pb, 1); /* depth */ - put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0); - put_swf_end_tag(s); - } else { - /* invalid codec */ - } + put_swf_tag(s, TAG_PLACEOBJECT); + put_le16(pb, SHAPE_ID); /* shape ID */ + put_le16(pb, 1); /* depth */ + put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0); + put_swf_end_tag(s); + } else { + /* invalid codec */ + } - swf->swf_frame_number ++; + swf->swf_frame_number ++; /* streaming sound always should be placed just before showframe tags */ if (swf->audio_type && swf->audio_in_pos) { @@ -516,7 +529,7 @@ static int swf_write_video(AVFormatContext *s, put_swf_tag(s, TAG_SHOWFRAME); put_swf_end_tag(s); - put_flush_packet(&s->pb); + put_flush_packet(s->pb); return 0; } @@ -527,7 +540,7 @@ static int swf_write_audio(AVFormatContext *s, SWFContext *swf = s->priv_data; /* Flash Player limit */ - if ( swf->swf_frame_number == 16000 ) { + if (swf->swf_frame_number == 16000) { av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); } @@ -541,7 +554,7 @@ static int swf_write_audio(AVFormatContext *s, swf->sound_samples += enc->frame_size; /* if audio only stream make sure we add swf frames */ - if ( swf->video_type == 0 ) { + if (swf->video_type == 0) { swf_write_video(s, enc, 0, 0); } @@ -560,7 +573,7 @@ static int swf_write_packet(AVFormatContext *s, AVPacket *pkt) static int swf_write_trailer(AVFormatContext *s) { SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVCodecContext *enc, *video_enc; int file_size, i; @@ -574,10 +587,10 @@ static int swf_write_trailer(AVFormatContext *s) put_swf_tag(s, TAG_END); put_swf_end_tag(s); - put_flush_packet(&s->pb); + put_flush_packet(s->pb); /* patch file size and number of frames if not streamed */ - if (!url_is_streamed(&s->pb) && video_enc) { + if (!url_is_streamed(s->pb) && video_enc) { file_size = url_ftell(pb); url_fseek(pb, 4, SEEK_SET); put_le32(pb, file_size); @@ -618,8 +631,6 @@ static int get_swf_tag(ByteIOContext *pb, int *len_ptr) static int swf_probe(AVProbeData *p) { /* check file header */ - if (p->buf_size <= 16) - return 0; if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' && p->buf[2] == 'S') return AVPROBE_SCORE_MAX; @@ -630,21 +641,17 @@ static int swf_probe(AVProbeData *p) static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap) { SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; - int nbits, len, tag, v; - offset_t frame_offset = -1; - AVStream *ast = 0; - AVStream *vst = 0; + ByteIOContext *pb = s->pb; + int nbits, len, tag; tag = get_be32(pb) & 0xffffff00; - if (tag == MKBETAG('C', 'W', 'S', 0)) - { + if (tag == MKBETAG('C', 'W', 'S', 0)) { av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n"); - return AVERROR_IO; + return AVERROR(EIO); } if (tag != MKBETAG('F', 'W', 'S', 0)) - return AVERROR_IO; + return AVERROR(EIO); get_le32(pb); /* skip rectangle size */ nbits = get_byte(pb) >> 3; @@ -654,15 +661,22 @@ static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_le16(pb); /* frame count */ swf->samples_per_frame = 0; + s->ctx_flags |= AVFMTCTX_NOHEADER; + return 0; +} + +static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + SWFContext *swf = s->priv_data; + ByteIOContext *pb = s->pb; + AVStream *vst = NULL, *ast = NULL, *st = 0; + int tag, len, i, frame, v; for(;;) { - offset_t tag_offset = url_ftell(pb); tag = get_swf_tag(pb, &len); - if (tag < 0 || tag == TAG_VIDEOFRAME || tag == TAG_STREAMBLOCK) { - url_fseek(pb, frame_offset == -1 ? tag_offset : frame_offset, SEEK_SET); - break; - } - if ( tag == TAG_VIDEOSTREAM && !vst) { + if (tag < 0) + return AVERROR(EIO); + if (tag == TAG_VIDEOSTREAM && !vst) { int ch_id = get_le16(pb); get_le16(pb); get_le16(pb); @@ -670,58 +684,37 @@ static int swf_read_header(AVFormatContext *s, AVFormatParameters *ap) get_byte(pb); /* Check for FLV1 */ vst = av_new_stream(s, ch_id); + if (!vst) + return -1; vst->codec->codec_type = CODEC_TYPE_VIDEO; vst->codec->codec_id = codec_get_id(swf_codec_tags, get_byte(pb)); - } else if ( ( tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2 ) && !ast) { + av_set_pts_info(vst, 64, 256, swf->frame_rate); + vst->codec->time_base = (AVRational){ 256, swf->frame_rate }; + len -= 10; + } else if ((tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) && !ast) { /* streaming found */ int sample_rate_code; get_byte(pb); v = get_byte(pb); swf->samples_per_frame = get_le16(pb); ast = av_new_stream(s, -1); /* -1 to avoid clash with video stream ch_id */ + if (!ast) + return -1; swf->audio_stream_index = ast->index; ast->codec->channels = 1 + (v&1); ast->codec->codec_type = CODEC_TYPE_AUDIO; ast->codec->codec_id = codec_get_id(swf_audio_codec_tags, (v>>4) & 15); - ast->need_parsing = 1; + ast->need_parsing = AVSTREAM_PARSE_FULL; sample_rate_code= (v>>2) & 3; if (!sample_rate_code) - return AVERROR_IO; + return AVERROR(EIO); ast->codec->sample_rate = 11025 << (sample_rate_code-1); av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); - if (len > 4) - url_fskip(pb,len-4); - - } else if (tag == TAG_JPEG2 && !vst) { - vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */ - vst->codec->codec_type = CODEC_TYPE_VIDEO; - vst->codec->codec_id = CODEC_ID_MJPEG; - url_fskip(pb, len); - frame_offset = tag_offset; - } else { - url_fskip(pb, len); - } - } - if (vst) - av_set_pts_info(vst, 64, 256, swf->frame_rate); - return 0; -} - -static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - SWFContext *swf = s->priv_data; - ByteIOContext *pb = &s->pb; - AVStream *st = 0; - int tag, len, i, frame; - - for(;;) { - tag = get_swf_tag(pb, &len); - if (tag < 0) - return AVERROR_IO; - if (tag == TAG_VIDEOFRAME) { + len -= 4; + } else if (tag == TAG_VIDEOFRAME) { int ch_id = get_le16(pb); len -= 2; - for( i=0; i<s->nb_streams; i++ ) { + for(i=0; i<s->nb_streams; i++) { st = s->streams[i]; if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->id == ch_id) { frame = get_le16(pb); @@ -744,21 +737,33 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) } else if (tag == TAG_JPEG2) { for (i=0; i<s->nb_streams; i++) { st = s->streams[i]; - if (st->id == -2) { - get_le16(pb); /* BITMAP_ID */ - av_new_packet(pkt, len-2); - get_buffer(pb, pkt->data, 4); - if (AV_RB32(pkt->data) == 0xffd8ffd9) { - /* old SWF files containing SOI/EOI as data start */ - pkt->size -= 4; - get_buffer(pb, pkt->data, pkt->size); - } else { - get_buffer(pb, pkt->data + 4, pkt->size - 4); - } - pkt->stream_index = st->index; - return pkt->size; - } + if (st->id == -2) + break; } + if (i == s->nb_streams) { + vst = av_new_stream(s, -2); /* -2 to avoid clash with video stream and audio stream */ + if (!vst) + return -1; + vst->codec->codec_type = CODEC_TYPE_VIDEO; + vst->codec->codec_id = CODEC_ID_MJPEG; + av_set_pts_info(vst, 64, 256, swf->frame_rate); + vst->codec->time_base = (AVRational){ 256, swf->frame_rate }; + st = vst; + } + get_le16(pb); /* BITMAP_ID */ + av_new_packet(pkt, len-2); + get_buffer(pb, pkt->data, 4); + if (AV_RB32(pkt->data) == 0xffd8ffd9 || + AV_RB32(pkt->data) == 0xffd9ffd8) { + /* old SWF files containing SOI/EOI as data start */ + /* files created by swink have reversed tag */ + pkt->size -= 4; + get_buffer(pb, pkt->data, pkt->size); + } else { + get_buffer(pb, pkt->data + 4, pkt->size - 4); + } + pkt->stream_index = st->index; + return pkt->size; } url_fskip(pb, len); } @@ -767,7 +772,7 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) static int swf_read_close(AVFormatContext *s) { - return 0; + return 0; } #ifdef CONFIG_SWF_DEMUXER @@ -795,3 +800,17 @@ AVOutputFormat swf_muxer = { swf_write_trailer, }; #endif +#ifdef CONFIG_AVM2_MUXER +AVOutputFormat avm2_muxer = { + "avm2", + "Flash 9 (AVM2) format", + "application/x-shockwave-flash", + NULL, + sizeof(SWFContext), + CODEC_ID_MP3, + CODEC_ID_FLV1, + swf_write_header, + swf_write_packet, + swf_write_trailer, +}; +#endif diff --git a/contrib/ffmpeg/libavformat/tcp.c b/contrib/ffmpeg/libavformat/tcp.c index a5539be4c..bea0fb909 100644 --- a/contrib/ffmpeg/libavformat/tcp.c +++ b/contrib/ffmpeg/libavformat/tcp.c @@ -21,27 +21,13 @@ #include "avformat.h" #include <unistd.h> #include "network.h" +#include "os_support.h" #include <sys/time.h> -#include <fcntl.h> typedef struct TCPContext { int fd; } TCPContext; -/* resolve host with also IP address parsing */ -int resolve_host(struct in_addr *sin_addr, const char *hostname) -{ - struct hostent *hp; - - if ((inet_aton(hostname, sin_addr)) == 0) { - hp = gethostbyname(hostname); - if (!hp) - return -1; - memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr)); - } - return 0; -} - /* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { @@ -68,6 +54,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (port <= 0 || port >= 65536) goto fail; + if(!ff_network_init()) + return AVERROR(EIO); + dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port); if (resolve_host(&dest_addr.sin_addr, hostname) < 0) @@ -76,15 +65,16 @@ static int tcp_open(URLContext *h, const char *uri, int flags) fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) goto fail; - fcntl(fd, F_SETFL, O_NONBLOCK); + ff_socket_nonblock(fd, 1); redo: ret = connect(fd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); if (ret < 0) { - if (errno == EINTR) + if (ff_neterrno() == FF_NETERROR(EINTR)) goto redo; - if (errno != EINPROGRESS) + if (ff_neterrno() != FF_NETERROR(EINPROGRESS) && + ff_neterrno() != FF_NETERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ @@ -113,7 +103,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) return 0; fail: - ret = AVERROR_IO; + ret = AVERROR(EIO); fail1: if (fd >= 0) closesocket(fd); @@ -140,7 +130,8 @@ static int tcp_read(URLContext *h, uint8_t *buf, int size) if (ret > 0 && FD_ISSET(s->fd, &rfds)) { len = recv(s->fd, buf, size, 0); if (len < 0) { - if (errno != EINTR && errno != EAGAIN) + if (ff_neterrno() != FF_NETERROR(EINTR) && + ff_neterrno() != FF_NETERROR(EAGAIN)) return AVERROR(errno); } else return len; } else if (ret < 0) { @@ -169,7 +160,8 @@ static int tcp_write(URLContext *h, uint8_t *buf, int size) if (ret > 0 && FD_ISSET(s->fd, &wfds)) { len = send(s->fd, buf, size, 0); if (len < 0) { - if (errno != EINTR && errno != EAGAIN) + if (ff_neterrno() != FF_NETERROR(EINTR) && + ff_neterrno() != FF_NETERROR(EAGAIN)) return AVERROR(errno); continue; } @@ -186,6 +178,7 @@ static int tcp_close(URLContext *h) { TCPContext *s = h->priv_data; closesocket(s->fd); + ff_network_close(); av_free(s); return 0; } diff --git a/contrib/ffmpeg/libavformat/thp.c b/contrib/ffmpeg/libavformat/thp.c index d0d80428c..a0747ecad 100644 --- a/contrib/ffmpeg/libavformat/thp.c +++ b/contrib/ffmpeg/libavformat/thp.c @@ -21,7 +21,6 @@ #include "avformat.h" -#include "allformats.h" typedef struct ThpDemuxContext { int version; @@ -35,19 +34,18 @@ typedef struct ThpDemuxContext { int next_frame; int next_framesz; int video_stream_index; + int audio_stream_index; int compcount; unsigned char components[16]; AVStream* vst; int has_audio; + int audiosize; } ThpDemuxContext; static int thp_probe(AVProbeData *p) { /* check file header */ - if (p->buf_size < 4) - return 0; - if (AV_RL32(p->buf) == MKTAG('T', 'H', 'P', '\0')) return AVPROBE_SCORE_MAX; else @@ -57,106 +55,135 @@ static int thp_probe(AVProbeData *p) static int thp_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ThpDemuxContext *thp = s->priv_data; - AVStream *st; - ByteIOContext *pb = &s->pb; - int i; - - /* Read the file header. */ - - get_be32(pb); /* Skip Magic. */ - thp->version = get_be32(pb); - - get_be32(pb); /* Max buf size. */ - get_be32(pb); /* Max samples. */ - - thp->fps = av_d2q(av_int2flt(get_be32(pb)), INT_MAX); - thp->framecnt = get_be32(pb); - thp->first_framesz = get_be32(pb); - get_be32(pb); /* Data size. */ - - thp->compoff = get_be32(pb); - get_be32(pb); /* offsetDataOffset. */ - thp->first_frame = get_be32(pb); - thp->last_frame = get_be32(pb); - - thp->next_framesz = thp->first_framesz; - thp->next_frame = thp->first_frame; - - /* Read the component structure. */ - url_fseek (pb, thp->compoff, SEEK_SET); - thp->compcount = get_be32(pb); - - /* Read the list of component types. */ - get_buffer(pb, thp->components, 16); - - for (i = 0; i < thp->compcount; i++) { - if (thp->components[i] == 0) { - if (thp->vst != 0) - break; - - /* Video component. */ - st = av_new_stream(s, 0); - if (!st) - return AVERROR_NOMEM; - - /* The denominator and numerator are switched because 1/fps - is required. */ - av_set_pts_info(st, 64, thp->fps.den, thp->fps.num); - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = CODEC_ID_THP; - st->codec->codec_tag = 0; /* no fourcc */ - st->codec->width = get_be32(pb); - st->codec->height = get_be32(pb); - st->codec->sample_rate = av_q2d(thp->fps); - thp->vst = st; - thp->video_stream_index = st->index; - - if (thp->version == 0x11000) - get_be32(pb); /* Unknown. */ + ThpDemuxContext *thp = s->priv_data; + AVStream *st; + ByteIOContext *pb = s->pb; + int i; + + /* Read the file header. */ + get_be32(pb); /* Skip Magic. */ + thp->version = get_be32(pb); + + get_be32(pb); /* Max buf size. */ + get_be32(pb); /* Max samples. */ + + thp->fps = av_d2q(av_int2flt(get_be32(pb)), INT_MAX); + thp->framecnt = get_be32(pb); + thp->first_framesz = get_be32(pb); + get_be32(pb); /* Data size. */ + + thp->compoff = get_be32(pb); + get_be32(pb); /* offsetDataOffset. */ + thp->first_frame = get_be32(pb); + thp->last_frame = get_be32(pb); + + thp->next_framesz = thp->first_framesz; + thp->next_frame = thp->first_frame; + + /* Read the component structure. */ + url_fseek (pb, thp->compoff, SEEK_SET); + thp->compcount = get_be32(pb); + + /* Read the list of component types. */ + get_buffer(pb, thp->components, 16); + + for (i = 0; i < thp->compcount; i++) { + if (thp->components[i] == 0) { + if (thp->vst != 0) + break; + + /* Video component. */ + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + + /* The denominator and numerator are switched because 1/fps + is required. */ + av_set_pts_info(st, 64, thp->fps.den, thp->fps.num); + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_THP; + st->codec->codec_tag = 0; /* no fourcc */ + st->codec->width = get_be32(pb); + st->codec->height = get_be32(pb); + st->codec->sample_rate = av_q2d(thp->fps); + thp->vst = st; + thp->video_stream_index = st->index; + + if (thp->version == 0x11000) + get_be32(pb); /* Unknown. */ + } else if (thp->components[i] == 1) { + if (thp->has_audio != 0) + break; + + /* Audio component. */ + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_ADPCM_THP; + st->codec->codec_tag = 0; /* no fourcc */ + st->codec->channels = get_be32(pb); /* numChannels. */ + st->codec->sample_rate = get_be32(pb); /* Frequency. */ + + av_set_pts_info(st, 64, 1, st->codec->sample_rate); + + thp->audio_stream_index = st->index; + thp->has_audio = 1; } - else if (thp->components[i] == 1) { - /* XXX: Required for audio playback. */ - thp->has_audio = 1; - } } - return 0; + return 0; } static int thp_read_packet(AVFormatContext *s, AVPacket *pkt) { ThpDemuxContext *thp = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int size; int ret; - /* Terminate when last frame is reached. */ - if (thp->frame >= thp->framecnt) - return AVERROR_IO; + if (thp->audiosize == 0) { + /* Terminate when last frame is reached. */ + if (thp->frame >= thp->framecnt) + return AVERROR(EIO); - url_fseek(pb, thp->next_frame, SEEK_SET); + url_fseek(pb, thp->next_frame, SEEK_SET); - /* Locate the next frame and read out its size. */ - thp->next_frame += thp->next_framesz; - thp->next_framesz = get_be32(pb); + /* Locate the next frame and read out its size. */ + thp->next_frame += thp->next_framesz; + thp->next_framesz = get_be32(pb); get_be32(pb); /* Previous total size. */ - size = get_be32(pb); /* Total size of this frame. */ + size = get_be32(pb); /* Total size of this frame. */ + + /* Store the audiosize so the next time this function is called, + the audio can be read. */ + if (thp->has_audio) + thp->audiosize = get_be32(pb); /* Audio size. */ + else + thp->frame++; + + ret = av_get_packet(pb, pkt, size); + if (ret != size) { + av_free_packet(pkt); + return AVERROR(EIO); + } - if (thp->has_audio) - get_be32(pb); /* Audio size. */ + pkt->stream_index = thp->video_stream_index; + } else { + ret = av_get_packet(pb, pkt, thp->audiosize); + if (ret != thp->audiosize) { + av_free_packet(pkt); + return AVERROR(EIO); + } - ret = av_get_packet(pb, pkt, size); - if (ret != size) { - av_free_packet(pkt); - return AVERROR_IO; + pkt->stream_index = thp->audio_stream_index; + thp->audiosize = 0; + thp->frame++; } - pkt->stream_index = thp->video_stream_index; - thp->frame++; - return 0; } diff --git a/contrib/ffmpeg/libavformat/tiertexseq.c b/contrib/ffmpeg/libavformat/tiertexseq.c index 8f565824a..457185b63 100644 --- a/contrib/ffmpeg/libavformat/tiertexseq.c +++ b/contrib/ffmpeg/libavformat/tiertexseq.c @@ -95,7 +95,7 @@ static int seq_init_frame_buffers(SeqDemuxContext *seq, ByteIOContext *pb) seq_buffer->data_size = sz; seq_buffer->data = av_malloc(sz); if (!seq_buffer->data) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } } seq->frame_buffers_count = i; @@ -115,7 +115,7 @@ static int seq_fill_buffer(SeqDemuxContext *seq, ByteIOContext *pb, int buffer_n url_fseek(pb, seq->current_frame_offs + data_offs, SEEK_SET); if (get_buffer(pb, seq_buffer->data + seq_buffer->fill_size, data_size) != data_size) - return AVERROR_IO; + return AVERROR(EIO); seq_buffer->fill_size += data_size; return 0; @@ -183,8 +183,8 @@ static int seq_parse_frame_data(SeqDemuxContext *seq, ByteIOContext *pb) static int seq_read_header(AVFormatContext *s, AVFormatParameters *ap) { int i, rc; - SeqDemuxContext *seq = (SeqDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + SeqDemuxContext *seq = s->priv_data; + ByteIOContext *pb = s->pb; AVStream *st; /* init internal buffers */ @@ -208,7 +208,7 @@ static int seq_read_header(AVFormatContext *s, AVFormatParameters *ap) /* initialize the video decoder stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 32, 1, SEQ_FRAME_RATE); seq->video_stream_index = st->index; @@ -221,7 +221,7 @@ static int seq_read_header(AVFormatContext *s, AVFormatParameters *ap) /* initialize the audio decoder stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 32, 1, SEQ_SAMPLE_RATE); seq->audio_stream_index = st->index; @@ -240,8 +240,8 @@ static int seq_read_header(AVFormatContext *s, AVFormatParameters *ap) static int seq_read_packet(AVFormatContext *s, AVPacket *pkt) { int rc; - SeqDemuxContext *seq = (SeqDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + SeqDemuxContext *seq = s->priv_data; + ByteIOContext *pb = s->pb; if (!seq->audio_buffer_full) { rc = seq_parse_frame_data(seq, pb); @@ -251,14 +251,14 @@ static int seq_read_packet(AVFormatContext *s, AVPacket *pkt) /* video packet */ if (seq->current_pal_data_size + seq->current_video_data_size != 0) { if (av_new_packet(pkt, 1 + seq->current_pal_data_size + seq->current_video_data_size)) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); pkt->data[0] = 0; if (seq->current_pal_data_size != 0) { pkt->data[0] |= 1; url_fseek(pb, seq->current_frame_offs + seq->current_pal_data_offs, SEEK_SET); if (get_buffer(pb, &pkt->data[1], seq->current_pal_data_size) != seq->current_pal_data_size) - return AVERROR_IO; + return AVERROR(EIO); } if (seq->current_video_data_size != 0) { pkt->data[0] |= 2; @@ -277,7 +277,7 @@ static int seq_read_packet(AVFormatContext *s, AVPacket *pkt) /* audio packet */ if (seq->current_audio_data_offs == 0) /* end of data reached */ - return AVERROR_IO; + return AVERROR(EIO); url_fseek(pb, seq->current_frame_offs + seq->current_audio_data_offs, SEEK_SET); rc = av_get_packet(pb, pkt, seq->current_audio_data_size); @@ -294,7 +294,7 @@ static int seq_read_packet(AVFormatContext *s, AVPacket *pkt) static int seq_read_close(AVFormatContext *s) { int i; - SeqDemuxContext *seq = (SeqDemuxContext *)s->priv_data; + SeqDemuxContext *seq = s->priv_data; for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) av_free(seq->frame_buffers[i].data); diff --git a/contrib/ffmpeg/libavformat/tta.c b/contrib/ffmpeg/libavformat/tta.c index a3709437e..2cd0101f1 100644 --- a/contrib/ffmpeg/libavformat/tta.c +++ b/contrib/ffmpeg/libavformat/tta.c @@ -16,21 +16,18 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" #include "bitstream.h" typedef struct { int totalframes, currentframe; - uint32_t *seektable; } TTAContext; static int tta_probe(AVProbeData *p) { const uint8_t *d = p->buf; - if (p->buf_size < 4) - return 0; if (d[0] == 'T' && d[1] == 'T' && d[2] == 'A' && d[3] == '1') return 80; return 0; @@ -41,26 +38,27 @@ static int tta_read_header(AVFormatContext *s, AVFormatParameters *ap) TTAContext *c = s->priv_data; AVStream *st; int i, channels, bps, samplerate, datalen, framelen; + uint64_t framepos; - if (get_le32(&s->pb) != ff_get_fourcc("TTA1")) + if (get_le32(s->pb) != ff_get_fourcc("TTA1")) return -1; // not tta file - url_fskip(&s->pb, 2); // FIXME: flags - channels = get_le16(&s->pb); - bps = get_le16(&s->pb); - samplerate = get_le32(&s->pb); + url_fskip(s->pb, 2); // FIXME: flags + channels = get_le16(s->pb); + bps = get_le16(s->pb); + samplerate = get_le32(s->pb); if(samplerate <= 0 || samplerate > 1000000){ av_log(s, AV_LOG_ERROR, "nonsense samplerate\n"); return -1; } - datalen = get_le32(&s->pb); + datalen = get_le32(s->pb); if(datalen < 0){ av_log(s, AV_LOG_ERROR, "nonsense datalen\n"); return -1; } - url_fskip(&s->pb, 4); // header crc + url_fskip(s->pb, 4); // header crc framelen = samplerate*256/245; c->totalframes = datalen / framelen + ((datalen % framelen) ? 1 : 0); @@ -70,33 +68,39 @@ static int tta_read_header(AVFormatContext *s, AVFormatParameters *ap) av_log(s, AV_LOG_ERROR, "totalframes too large\n"); return -1; } - c->seektable = av_mallocz(sizeof(uint32_t)*c->totalframes); - if (!c->seektable) - return AVERROR_NOMEM; - - for (i = 0; i < c->totalframes; i++) - c->seektable[i] = get_le32(&s->pb); - url_fskip(&s->pb, 4); // seektable crc st = av_new_stream(s, 0); -// av_set_pts_info(st, 32, 1, 1000); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); + + av_set_pts_info(st, 64, 1, samplerate); + st->start_time = 0; + st->duration = datalen; + + framepos = url_ftell(s->pb) + 4*c->totalframes + 4; + + for (i = 0; i < c->totalframes; i++) { + uint32_t size = get_le32(s->pb); + av_add_index_entry(st, framepos, i*framelen, size, 0, AVINDEX_KEYFRAME); + framepos += size; + } + url_fskip(s->pb, 4); // seektable crc + st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_TTA; st->codec->channels = channels; st->codec->sample_rate = samplerate; st->codec->bits_per_sample = bps; - st->codec->extradata_size = url_ftell(&s->pb); + st->codec->extradata_size = url_ftell(s->pb); if(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ //this check is redundant as get_buffer should fail av_log(s, AV_LOG_ERROR, "extradata_size too large\n"); return -1; } st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE); - url_fseek(&s->pb, 0, SEEK_SET); - get_buffer(&s->pb, st->codec->extradata, st->codec->extradata_size); + url_fseek(s->pb, 0, SEEK_SET); + get_buffer(s->pb, st->codec->extradata, st->codec->extradata_size); return 0; } @@ -104,37 +108,31 @@ static int tta_read_header(AVFormatContext *s, AVFormatParameters *ap) static int tta_read_packet(AVFormatContext *s, AVPacket *pkt) { TTAContext *c = s->priv_data; - int ret, size; + AVStream *st = s->streams[0]; + int size, ret; // FIXME! if (c->currentframe > c->totalframes) - size = 0; - else - size = c->seektable[c->currentframe]; - - c->currentframe++; + return -1; - if (av_new_packet(pkt, size) < 0) - return AVERROR_IO; + size = st->index_entries[c->currentframe].size; - pkt->pos = url_ftell(&s->pb); - pkt->stream_index = 0; - ret = get_buffer(&s->pb, pkt->data, size); - if (ret <= 0) { - av_free_packet(pkt); - return AVERROR_IO; - } - pkt->size = ret; -// av_log(s, AV_LOG_INFO, "TTA packet #%d desired size: %d read size: %d at pos %d\n", -// c->currentframe, size, ret, pkt->pos); - return 0; //ret; + ret = av_get_packet(s->pb, pkt, size); + pkt->dts = st->index_entries[c->currentframe++].timestamp; + return ret; } -static int tta_read_close(AVFormatContext *s) +static int tta_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { TTAContext *c = s->priv_data; - if (c->seektable) - av_free(c->seektable); + AVStream *st = s->streams[stream_index]; + int index = av_index_search_timestamp(st, timestamp, flags); + if (index < 0) + return -1; + + c->currentframe = index; + url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); + return 0; } @@ -145,6 +143,7 @@ AVInputFormat tta_demuxer = { tta_probe, tta_read_header, tta_read_packet, - tta_read_close, + NULL, + tta_read_seek, .extensions = "tta", }; diff --git a/contrib/ffmpeg/libavformat/txd.c b/contrib/ffmpeg/libavformat/txd.c new file mode 100644 index 000000000..8092a41a4 --- /dev/null +++ b/contrib/ffmpeg/libavformat/txd.c @@ -0,0 +1,103 @@ +/* + * Renderware TeXture Dictionary (.txd) demuxer + * Copyright (c) 2007 Ivo van Poorten + * + * 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" + +#define TXD_FILE 0x16 +#define TXD_INFO 0x01 +#define TXD_EXTRA 0x03 +#define TXD_TEXTURE 0x15 +#define TXD_TEXTURE_DATA 0x01 +#define TXD_MARKER 0x1803ffff +#define TXD_MARKER2 0x1003ffff + +static int txd_probe(AVProbeData * pd) { + if (AV_RL32(pd->buf ) == TXD_FILE && + (AV_RL32(pd->buf+8) == TXD_MARKER || AV_RL32(pd->buf+8) == TXD_MARKER2)) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int txd_read_header(AVFormatContext *s, AVFormatParameters *ap) { + AVStream *st; + + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_TXD; + st->codec->time_base.den = 5; + st->codec->time_base.num = 1; + /* the parameters will be extracted from the compressed bitstream */ + return 0; +} + +static int txd_read_packet(AVFormatContext *s, AVPacket *pkt) { + ByteIOContext *pb = s->pb; + unsigned int id, chunk_size, marker; + int ret; + +next_chunk: + id = get_le32(pb); + chunk_size = get_le32(pb); + marker = get_le32(pb); + + if (url_feof(s->pb)) + return AVERROR(EIO); + if (marker != TXD_MARKER && marker != TXD_MARKER2) { + av_log(NULL, AV_LOG_ERROR, "marker does not match\n"); + return AVERROR(EIO); + } + + switch (id) { + case TXD_INFO: + if (chunk_size > 100) + break; + case TXD_EXTRA: + url_fskip(s->pb, chunk_size); + case TXD_FILE: + case TXD_TEXTURE: + goto next_chunk; + default: + av_log(NULL, AV_LOG_ERROR, "unknown chunk id %i\n", id); + return AVERROR(EIO); + } + + ret = av_get_packet(s->pb, pkt, chunk_size); + pkt->stream_index = 0; + + return ret <= 0 ? AVERROR(EIO) : ret; +} + +static int txd_read_close(AVFormatContext *s) { + return 0; +} + +AVInputFormat txd_demuxer = +{ + "txd", + "txd format", + 0, + txd_probe, + txd_read_header, + txd_read_packet, + txd_read_close, +}; diff --git a/contrib/ffmpeg/libavformat/udp.c b/contrib/ffmpeg/libavformat/udp.c index bbf8ca2ec..da3e25382 100644 --- a/contrib/ffmpeg/libavformat/udp.c +++ b/contrib/ffmpeg/libavformat/udp.c @@ -21,6 +21,7 @@ #include "avformat.h" #include <unistd.h> #include "network.h" +#include "os_support.h" #ifndef IPV6_ADD_MEMBERSHIP #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -34,91 +35,98 @@ typedef struct { int local_port; int reuse_socket; #ifndef CONFIG_IPV6 - struct ip_mreq mreq; struct sockaddr_in dest_addr; #else struct sockaddr_storage dest_addr; - size_t dest_addr_len; #endif + size_t dest_addr_len; } UDPContext; #define UDP_TX_BUF_SIZE 32768 +#define UDP_MAX_PKT_SIZE 65536 -#ifdef CONFIG_IPV6 - -static int udp_ipv6_is_multicast_address(const struct sockaddr *addr) { - if (addr->sa_family == AF_INET) - return IN_MULTICAST(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr)); - if (addr->sa_family == AF_INET6) - return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)addr)->sin6_addr); - return -1; -} - -static int udp_ipv6_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) { +static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) { +#ifdef IP_MULTICAST_TTL if (addr->sa_family == AF_INET) { if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) { - perror("setsockopt(IP_MULTICAST_TTL)"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL): %s\n", strerror(errno)); return -1; } } +#endif +#ifdef CONFIG_IPV6 if (addr->sa_family == AF_INET6) { if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) { - perror("setsockopt(IPV6_MULTICAST_HOPS)"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno)); return -1; } } +#endif return 0; } -static int udp_ipv6_join_multicast_group(int sockfd, struct sockaddr *addr) { - struct ip_mreq mreq; - struct ipv6_mreq mreq6; +static int udp_join_multicast_group(int sockfd, struct sockaddr *addr) { +#ifdef IP_ADD_MEMBERSHIP if (addr->sa_family == AF_INET) { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { - perror("setsockopt(IP_ADD_MEMBERSHIP)"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno)); return -1; } } +#endif +#ifdef CONFIG_IPV6 if (addr->sa_family == AF_INET6) { + struct ipv6_mreq mreq6; + memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); mreq6.ipv6mr_interface= 0; if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { - perror("setsockopt(IPV6_ADD_MEMBERSHIP)"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno)); return -1; } } +#endif return 0; } -static int udp_ipv6_leave_multicast_group(int sockfd, struct sockaddr *addr) { - struct ip_mreq mreq; - struct ipv6_mreq mreq6; +static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr) { +#ifdef IP_DROP_MEMBERSHIP if (addr->sa_family == AF_INET) { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { - perror("setsockopt(IP_DROP_MEMBERSHIP)"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP): %s\n", strerror(errno)); return -1; } } +#endif +#ifdef CONFIG_IPV6 if (addr->sa_family == AF_INET6) { + struct ipv6_mreq mreq6; + memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); mreq6.ipv6mr_interface= 0; if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { - perror("setsockopt(IPV6_DROP_MEMBERSHIP)"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP): %s\n", strerror(errno)); return -1; } } +#endif return 0; } +#ifdef CONFIG_IPV6 static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, int type, int family, int flags) { struct addrinfo hints, *res = 0; int error; char sport[16]; - const char *node = 0, *service = 0; + const char *node = 0, *service = "0"; if (port > 0) { snprintf(sport, sizeof(sport), "%d", port); @@ -127,80 +135,54 @@ static struct addrinfo* udp_ipv6_resolve_host(const char *hostname, int port, in if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) { node = hostname; } - if ((node) || (service)) { - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = type; - hints.ai_family = family; - hints.ai_flags = flags; - if ((error = getaddrinfo(node, service, &hints, &res))) { - av_log(NULL, AV_LOG_ERROR, "udp_ipv6_resolve_host: %s\n", gai_strerror(error)); - } + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = type; + hints.ai_family = family; + hints.ai_flags = flags; + if ((error = getaddrinfo(node, service, &hints, &res))) { + av_log(NULL, AV_LOG_ERROR, "udp_ipv6_resolve_host: %s\n", gai_strerror(error)); } + return res; } -static int udp_ipv6_set_remote_url(URLContext *h, const char *uri) { - UDPContext *s = h->priv_data; - char hostname[256]; - int port; +static int udp_set_url(struct sockaddr_storage *addr, const char *hostname, int port) { struct addrinfo *res0; - url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); + int addr_len; + res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0); - if (res0 == 0) return AVERROR_IO; - memcpy(&s->dest_addr, res0->ai_addr, res0->ai_addrlen); - s->dest_addr_len = res0->ai_addrlen; + if (res0 == 0) return AVERROR(EIO); + memcpy(addr, res0->ai_addr, res0->ai_addrlen); + addr_len = res0->ai_addrlen; freeaddrinfo(res0); - return 0; + + return addr_len; } -static int udp_ipv6_set_local(URLContext *h) { - UDPContext *s = h->priv_data; +static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr, int *addr_len) +{ int udp_fd = -1; - struct sockaddr_storage clientaddr; - socklen_t addrlen; - char sbuf[NI_MAXSERV]; - char hbuf[NI_MAXHOST]; struct addrinfo *res0 = NULL, *res = NULL; + int family = AF_UNSPEC; - if (s->local_port != 0) { - res0 = udp_ipv6_resolve_host(0, s->local_port, SOCK_DGRAM, AF_UNSPEC, AI_PASSIVE); - if (res0 == 0) - goto fail; - for (res = res0; res; res=res->ai_next) { - udp_fd = socket(res->ai_family, SOCK_DGRAM, 0); - if (udp_fd > 0) break; - perror("socket"); - } - } else { - udp_fd = socket(s->dest_addr.ss_family, SOCK_DGRAM, 0); - if (udp_fd < 0) - perror("socket"); - } - - if (udp_fd < 0) + if (((struct sockaddr *) &s->dest_addr)->sa_family) + family = ((struct sockaddr *) &s->dest_addr)->sa_family; + res0 = udp_ipv6_resolve_host(0, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); + if (res0 == 0) goto fail; - - if (s->local_port != 0) { - if (bind(udp_fd, res0->ai_addr, res0->ai_addrlen) < 0) { - perror("bind"); - goto fail; - } - freeaddrinfo(res0); - res0 = NULL; + for (res = res0; res; res=res->ai_next) { + udp_fd = socket(res->ai_family, SOCK_DGRAM, 0); + if (udp_fd > 0) break; + av_log(NULL, AV_LOG_ERROR, "socket: %s\n", strerror(errno)); } - addrlen = sizeof(clientaddr); - if (getsockname(udp_fd, (struct sockaddr *)&clientaddr, &addrlen) < 0) { - perror("getsockname"); + if (udp_fd < 0) goto fail; - } - if (getnameinfo((struct sockaddr *)&clientaddr, addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - perror("getnameinfo"); - goto fail; - } + memcpy(addr, res->ai_addr, res->ai_addrlen); + *addr_len = res->ai_addrlen; - s->local_port = strtol(sbuf, NULL, 10); + freeaddrinfo(res0); return udp_fd; @@ -212,7 +194,52 @@ static int udp_ipv6_set_local(URLContext *h) { return -1; } -#endif +static int udp_port(struct sockaddr_storage *addr, int addr_len) +{ + char sbuf[sizeof(int)*3+1]; + + if (getnameinfo((struct sockaddr *)addr, addr_len, NULL, 0, sbuf, sizeof(sbuf), NI_NUMERICSERV) != 0) { + av_log(NULL, AV_LOG_ERROR, "getnameinfo: %s\n", strerror(errno)); + return -1; + } + + return strtol(sbuf, NULL, 10); +} + +#else + +static int udp_set_url(struct sockaddr_in *addr, const char *hostname, int port) +{ + /* set the destination address */ + if (resolve_host(&addr->sin_addr, hostname) < 0) + return AVERROR(EIO); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + + return sizeof(struct sockaddr_in); +} + +static int udp_socket_create(UDPContext *s, struct sockaddr_in *addr, int *addr_len) +{ + int fd; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return -1; + + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl (INADDR_ANY); + addr->sin_port = htons(s->local_port); + *addr_len = sizeof(struct sockaddr_in); + + return fd; +} + +static int udp_port(struct sockaddr_in *addr, int len) +{ + return ntohs(addr->sin_port); +} +#endif /* CONFIG_IPV6 */ /** @@ -233,9 +260,6 @@ static int udp_ipv6_set_local(URLContext *h) { */ int udp_set_remote_url(URLContext *h, const char *uri) { -#ifdef CONFIG_IPV6 - return udp_ipv6_set_remote_url(h, uri); -#else UDPContext *s = h->priv_data; char hostname[256]; int port; @@ -243,12 +267,12 @@ int udp_set_remote_url(URLContext *h, const char *uri) url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ - if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0) - return AVERROR_IO; - s->dest_addr.sin_family = AF_INET; - s->dest_addr.sin_port = htons(port); + s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); + if (s->dest_addr_len < 0) { + return AVERROR(EIO); + } + return 0; -#endif } /** @@ -284,24 +308,23 @@ static int udp_open(URLContext *h, const char *uri, int flags) const char *p; char buf[256]; #ifndef CONFIG_IPV6 - struct sockaddr_in my_addr, my_addr1; - int len; + struct sockaddr_in my_addr; +#else + struct sockaddr_storage my_addr; #endif + int len; h->is_streamed = 1; h->max_packet_size = 1472; is_output = (flags & URL_WRONLY); - s = av_malloc(sizeof(UDPContext)); + s = av_mallocz(sizeof(UDPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; s->ttl = 16; - s->is_multicast = 0; - s->local_port = 0; - s->reuse_socket = 0; p = strchr(uri, '?'); if (p) { s->is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); @@ -329,78 +352,51 @@ static int udp_open(URLContext *h, const char *uri, int flags) udp_set_remote_url(h, uri); } -#ifndef CONFIG_IPV6 - udp_fd = socket(AF_INET, SOCK_DGRAM, 0); + if(!ff_network_init()) + return AVERROR(EIO); + + if (s->is_multicast && !(h->flags & URL_WRONLY)) + s->local_port = port; + udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; - my_addr.sin_family = AF_INET; - my_addr.sin_addr.s_addr = htonl (INADDR_ANY); - if (s->is_multicast && !(h->flags & URL_WRONLY)) { - /* special case: the bind must be done on the multicast address port */ - my_addr.sin_port = s->dest_addr.sin_port; - } else { - my_addr.sin_port = htons(s->local_port); - } - if (s->reuse_socket) if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; /* the bind is needed to give a port to the socket now */ - if (bind(udp_fd,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) + if (bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) goto fail; - len = sizeof(my_addr1); - getsockname(udp_fd, (struct sockaddr *)&my_addr1, &len); - s->local_port = ntohs(my_addr1.sin_port); + len = sizeof(my_addr); + getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); + s->local_port = udp_port(&my_addr, len); -#ifdef IP_MULTICAST_TTL if (s->is_multicast) { if (h->flags & URL_WRONLY) { /* output */ - if (setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, - &s->ttl, sizeof(s->ttl)) < 0) { - perror("IP_MULTICAST_TTL"); + if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; - } } else { /* input */ - memset(&s->mreq, 0, sizeof(s->mreq)); - s->mreq.imr_multiaddr = s->dest_addr.sin_addr; - s->mreq.imr_interface.s_addr = htonl (INADDR_ANY); - if (setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &s->mreq, sizeof(s->mreq)) < 0) { - perror("rtp: IP_ADD_MEMBERSHIP"); + if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; - } } } -#endif -#else - if (s->is_multicast && !(h->flags & URL_WRONLY)) - s->local_port = port; - udp_fd = udp_ipv6_set_local(h); - if (udp_fd < 0) - goto fail; - if (s->is_multicast) { - if (h->flags & URL_WRONLY) { - if (udp_ipv6_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) - goto fail; - } else { - if (udp_ipv6_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) - goto fail; - } - } -#endif if (is_output) { /* limit the tx buf size to limit latency */ tmp = UDP_TX_BUF_SIZE; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { - perror("setsockopt sndbuf"); + av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } + } else { + /* set udp recv buffer size to the largest possible udp packet size to + * avoid losing data on OSes that set this too low by default. */ + tmp = UDP_MAX_PKT_SIZE; + setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)); } s->udp_fd = udp_fd; @@ -409,27 +405,20 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (udp_fd >= 0) closesocket(udp_fd); av_free(s); - return AVERROR_IO; + return AVERROR(EIO); } static int udp_read(URLContext *h, uint8_t *buf, int size) { UDPContext *s = h->priv_data; -#ifndef CONFIG_IPV6 - struct sockaddr_in from; -#else - struct sockaddr_storage from; -#endif - socklen_t from_len; int len; for(;;) { - from_len = sizeof(from); - len = recvfrom (s->udp_fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); + len = recv(s->udp_fd, buf, size, 0); if (len < 0) { - if (errno != EAGAIN && errno != EINTR) - return AVERROR_IO; + if (ff_neterrno() != FF_NETERROR(EAGAIN) && + ff_neterrno() != FF_NETERROR(EINTR)) + return AVERROR(EIO); } else { break; } @@ -445,14 +434,11 @@ static int udp_write(URLContext *h, uint8_t *buf, int size) for(;;) { ret = sendto (s->udp_fd, buf, size, 0, (struct sockaddr *) &s->dest_addr, -#ifndef CONFIG_IPV6 - sizeof (s->dest_addr)); -#else s->dest_addr_len); -#endif if (ret < 0) { - if (errno != EINTR && errno != EAGAIN) - return AVERROR_IO; + if (ff_neterrno() != FF_NETERROR(EINTR) && + ff_neterrno() != FF_NETERROR(EAGAIN)) + return AVERROR(EIO); } else { break; } @@ -464,20 +450,10 @@ static int udp_close(URLContext *h) { UDPContext *s = h->priv_data; -#ifndef CONFIG_IPV6 -#ifdef IP_DROP_MEMBERSHIP - if (s->is_multicast && !(h->flags & URL_WRONLY)) { - if (setsockopt(s->udp_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, - &s->mreq, sizeof(s->mreq)) < 0) { - perror("IP_DROP_MEMBERSHIP"); - } - } -#endif -#else if (s->is_multicast && !(h->flags & URL_WRONLY)) - udp_ipv6_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); -#endif + udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr); closesocket(s->udp_fd); + ff_network_close(); av_free(s); return 0; } diff --git a/contrib/ffmpeg/libavformat/utils.c b/contrib/ffmpeg/libavformat/utils.c index 36cb269b5..caf8df4eb 100644 --- a/contrib/ffmpeg/libavformat/utils.c +++ b/contrib/ffmpeg/libavformat/utils.c @@ -1,5 +1,5 @@ /* - * Various utilities for ffmpeg system + * various utility functions for use within FFmpeg * Copyright (c) 2000, 2001, 2002 Fabrice Bellard * * This file is part of FFmpeg. @@ -19,25 +19,40 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "allformats.h" #include "opt.h" +#include "avstring.h" +#include "riff.h" +#include <sys/time.h> +#include <time.h> #undef NDEBUG #include <assert.h> /** * @file libavformat/utils.c - * Various utility functions for using ffmpeg library. + * various utility functions for use within FFmpeg */ static void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den); static void av_frac_add(AVFrac *f, int64_t incr); -/** head of registered input format linked list. */ +/** head of registered input format linked list */ AVInputFormat *first_iformat = NULL; -/** head of registered output format linked list. */ +/** head of registered output format linked list */ AVOutputFormat *first_oformat = NULL; +AVInputFormat *av_iformat_next(AVInputFormat *f) +{ + if(f) return f->next; + else return first_iformat; +} + +AVOutputFormat *av_oformat_next(AVOutputFormat *f) +{ + if(f) return f->next; + else return first_oformat; +} + void av_register_input_format(AVInputFormat *format) { AVInputFormat **p; @@ -97,7 +112,7 @@ AVOutputFormat *guess_format(const char *short_name, const char *filename, return guess_format("image2", NULL, NULL); } #endif - /* find the proper file type */ + /* Find the proper file type. */ fmt_found = NULL; score_max = 0; fmt = first_oformat; @@ -176,14 +191,25 @@ void av_destruct_packet(AVPacket *pkt) pkt->data = NULL; pkt->size = 0; } +void av_init_packet(AVPacket *pkt) +{ + pkt->pts = AV_NOPTS_VALUE; + pkt->dts = AV_NOPTS_VALUE; + pkt->pos = -1; + pkt->duration = 0; + pkt->flags = 0; + pkt->stream_index = 0; + pkt->destruct= av_destruct_packet_nofree; +} + int av_new_packet(AVPacket *pkt, int size) { uint8_t *data; if((unsigned)size > (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); if (!data) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); av_init_packet(pkt); @@ -215,13 +241,12 @@ int av_dup_packet(AVPacket *pkt) { if (pkt->destruct != av_destruct_packet) { uint8_t *data; - /* we duplicate the packet and don't forget to put the padding - again */ + /* We duplicate the packet and don't forget to add the padding again. */ if((unsigned)pkt->size > (unsigned)pkt->size + FF_INPUT_BUFFER_PADDING_SIZE) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); data = av_malloc(pkt->size + FF_INPUT_BUFFER_PADDING_SIZE); if (!data) { - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } memcpy(data, pkt->data, pkt->size); memset(data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); @@ -282,7 +307,7 @@ static const char* format_to_name(void* ptr) } #define OFFSET(x) offsetof(AVFormatContext,x) -#define DEFAULT 0 //should be NAN but it doesnt work as its not a constant in glibc as required by ANSI/ISO C +#define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C //these names are too long to be readable #define E AV_OPT_FLAG_ENCODING_PARAM #define D AV_OPT_FLAG_DECODING_PARAM @@ -296,7 +321,9 @@ static const AVOption options[]={ {"genpts", "generate pts", 0, FF_OPT_TYPE_CONST, AVFMT_FLAG_GENPTS, INT_MIN, INT_MAX, D, "fflags"}, {"track", " set the track number", OFFSET(track), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, E}, {"year", "set the year", OFFSET(year), FF_OPT_TYPE_INT, DEFAULT, INT_MIN, INT_MAX, E}, -{"analyzeduration", NULL, OFFSET(max_analyze_duration), FF_OPT_TYPE_INT, 3*AV_TIME_BASE, 0, INT_MAX, D}, +{"analyzeduration", "how many microseconds are analyzed to estimate duration", OFFSET(max_analyze_duration), FF_OPT_TYPE_INT, 3*AV_TIME_BASE, 0, INT_MAX, D}, +{"cryptokey", "decryption key", OFFSET(key), FF_OPT_TYPE_BINARY, 0, 0, 0, D}, +{"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), FF_OPT_TYPE_INT, 1<<20, 0, INT_MAX, D}, {NULL}, }; @@ -343,21 +370,20 @@ int av_open_input_stream(AVFormatContext **ic_ptr, else ic = *ic_ptr; if (!ic) { - err = AVERROR_NOMEM; + err = AVERROR(ENOMEM); goto fail; } ic->iformat = fmt; - if (pb) - ic->pb = *pb; + ic->pb = pb; ic->duration = AV_NOPTS_VALUE; ic->start_time = AV_NOPTS_VALUE; - pstrcpy(ic->filename, sizeof(ic->filename), filename); + av_strlcpy(ic->filename, filename, sizeof(ic->filename)); /* allocate private data */ if (fmt->priv_data_size > 0) { ic->priv_data = av_mallocz(fmt->priv_data_size); if (!ic->priv_data) { - err = AVERROR_NOMEM; + err = AVERROR(ENOMEM); goto fail; } } else { @@ -369,7 +395,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, goto fail; if (pb && !ic->data_offset) - ic->data_offset = url_ftell(&ic->pb); + ic->data_offset = url_ftell(ic->pb); *ic_ptr = ic; return 0; @@ -382,7 +408,7 @@ int av_open_input_stream(AVFormatContext **ic_ptr, return err; } -/** Size of probe buffer, for guessing file type from file contents. */ +/** size of probe buffer, for guessing file type from file contents */ #define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1<<20) @@ -391,11 +417,10 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, int buf_size, AVFormatParameters *ap) { - int err, must_open_file, file_opened, probe_size; + int err, probe_size; AVProbeData probe_data, *pd = &probe_data; - ByteIOContext pb1, *pb = &pb1; + ByteIOContext *pb = NULL; - file_opened = 0; pd->filename = ""; if (filename) pd->filename = filename; @@ -403,25 +428,17 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, pd->buf_size = 0; if (!fmt) { - /* guess format if no file can be opened */ + /* guess format if no file can be opened */ fmt = av_probe_input_format(pd, 0); } - /* do not open file if the format does not need it. XXX: specific + /* Do not open file if the format does not need it. XXX: specific hack needed to handle RTSP/TCP */ - must_open_file = 1; - if (fmt && (fmt->flags & AVFMT_NOFILE)) { - must_open_file = 0; - pb= NULL; //FIXME this or memset(pb, 0, sizeof(ByteIOContext)); otherwise its uninitalized - } - - if (!fmt || must_open_file) { + if (!fmt || !(fmt->flags & AVFMT_NOFILE)) { /* if no file needed do not try to open one */ - if (url_fopen(pb, filename, URL_RDONLY) < 0) { - err = AVERROR_IO; + if ((err=url_fopen(&pb, filename, URL_RDONLY)) < 0) { goto fail; } - file_opened = 1; if (buf_size > 0) { url_setbufsize(pb, buf_size); } @@ -429,13 +446,14 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, for(probe_size= PROBE_BUF_MIN; probe_size<=PROBE_BUF_MAX && !fmt; probe_size<<=1){ int score= probe_size < PROBE_BUF_MAX ? AVPROBE_SCORE_MAX/4 : 0; /* read probe data */ - pd->buf= av_realloc(pd->buf, probe_size); + pd->buf= av_realloc(pd->buf, probe_size + AVPROBE_PADDING_SIZE); pd->buf_size = get_buffer(pb, pd->buf, probe_size); + memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE); if (url_fseek(pb, 0, SEEK_SET) < 0) { url_fclose(pb); - if (url_fopen(pb, filename, URL_RDONLY) < 0) { - file_opened = 0; - err = AVERROR_IO; + if (url_fopen(&pb, filename, URL_RDONLY) < 0) { + pb = NULL; + err = AVERROR(EIO); goto fail; } } @@ -451,16 +469,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, goto fail; } - /* XXX: suppress this hack for redirectors */ -#ifdef CONFIG_NETWORK - if (fmt == &redir_demuxer) { - err = redir_open(ic_ptr, pb); - url_fclose(pb); - return err; - } -#endif - - /* check filename in case of an image number is expected */ + /* check filename in case an image number is expected */ if (fmt->flags & AVFMT_NEEDNUMBER) { if (!av_filename_number_test(filename)) { err = AVERROR_NUMEXPECTED; @@ -473,7 +482,7 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, return 0; fail: av_freep(&pd->buf); - if (file_opened) + if (pb) url_fclose(pb); *ic_ptr = NULL; return err; @@ -484,13 +493,33 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, int av_read_packet(AVFormatContext *s, AVPacket *pkt) { - return s->iformat->read_packet(s, pkt); + int ret; + AVStream *st; + av_init_packet(pkt); + ret= s->iformat->read_packet(s, pkt); + if (ret < 0) + return ret; + st= s->streams[pkt->stream_index]; + + switch(st->codec->codec_type){ + case CODEC_TYPE_VIDEO: + if(s->video_codec_id) st->codec->codec_id= s->video_codec_id; + break; + case CODEC_TYPE_AUDIO: + if(s->audio_codec_id) st->codec->codec_id= s->audio_codec_id; + break; + case CODEC_TYPE_SUBTITLE: + if(s->subtitle_codec_id)st->codec->codec_id= s->subtitle_codec_id; + break; + } + + return ret; } /**********************************************************/ /** - * Get the number of samples of an audio frame. Return (-1) if error. + * Get the number of samples of an audio frame. Return -1 on error. */ static int get_audio_frame_size(AVCodecContext *enc, int size) { @@ -517,7 +546,7 @@ static int get_audio_frame_size(AVCodecContext *enc, int size) /** - * Return the frame duration in seconds, return 0 if not available. + * Return the frame duration in seconds. Return 0 if not available. */ static void compute_frame_duration(int *pnum, int *pden, AVStream *st, AVCodecParserContext *pc, AVPacket *pkt) @@ -574,35 +603,87 @@ static int is_intra_only(AVCodecContext *enc){ return 0; } -static int64_t lsb2full(int64_t lsb, int64_t last_ts, int lsb_bits){ - int64_t mask = lsb_bits < 64 ? (1LL<<lsb_bits)-1 : -1LL; - int64_t delta= last_ts - mask/2; - return ((lsb - delta)&mask) + delta; +static void update_initial_timestamps(AVFormatContext *s, int stream_index, + int64_t dts, int64_t pts) +{ + AVStream *st= s->streams[stream_index]; + AVPacketList *pktl= s->packet_buffer; + + if(st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE) + return; + + st->first_dts= dts - st->cur_dts; + st->cur_dts= dts; + + for(; pktl; pktl= pktl->next){ + if(pktl->pkt.stream_index != stream_index) + continue; + //FIXME think more about this check + if(pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts) + pktl->pkt.pts += st->first_dts; + + if(pktl->pkt.dts != AV_NOPTS_VALUE) + pktl->pkt.dts += st->first_dts; + + if(st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE) + st->start_time= pktl->pkt.pts; + } + if (st->start_time == AV_NOPTS_VALUE) + st->start_time = pts; +} + +static void update_initial_durations(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + AVPacketList *pktl= s->packet_buffer; + + assert(pkt->duration && !st->cur_dts); + + for(; pktl; pktl= pktl->next){ + if(pktl->pkt.stream_index != pkt->stream_index) + continue; + if(pktl->pkt.pts == pktl->pkt.dts && pktl->pkt.dts == AV_NOPTS_VALUE + && !pktl->pkt.duration){ + pktl->pkt.pts= pktl->pkt.dts= st->cur_dts; + st->cur_dts += pkt->duration; + pktl->pkt.duration= pkt->duration; + }else + break; + } } static void compute_pkt_fields(AVFormatContext *s, AVStream *st, AVCodecParserContext *pc, AVPacket *pkt) { int num, den, presentation_delayed, delay, i; - /* handle wrapping */ - if(st->cur_dts != AV_NOPTS_VALUE){ - if(pkt->pts != AV_NOPTS_VALUE) - pkt->pts= lsb2full(pkt->pts, st->cur_dts, st->pts_wrap_bits); - if(pkt->dts != AV_NOPTS_VALUE) - pkt->dts= lsb2full(pkt->dts, st->cur_dts, st->pts_wrap_bits); + int64_t offset; + + 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*/){ + pkt->dts -= 1LL<<st->pts_wrap_bits; } if (pkt->duration == 0) { compute_frame_duration(&num, &den, st, pc, pkt); if (den && num) { pkt->duration = av_rescale(1, num * (int64_t)st->time_base.den, den * (int64_t)st->time_base.num); + + if(st->cur_dts == 0) + update_initial_durations(s, st, pkt); } } - if(is_intra_only(st->codec)) - pkt->flags |= PKT_FLAG_KEY; + /* correct timestamps with byte offset if demuxers only have timestamps + on packet boundaries */ + if(pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size){ + /* this will estimate bitrate based on this frame's duration and size */ + offset = av_rescale(pc->offset, pkt->duration, pkt->size); + if(pkt->pts != AV_NOPTS_VALUE) + pkt->pts += offset; + if(pkt->dts != AV_NOPTS_VALUE) + pkt->dts += offset; + } - /* do we have a video B frame ? */ + /* do we have a video B-frame ? */ delay= st->codec->has_b_frames; presentation_delayed = 0; /* XXX: need has_b_frame, but cannot get it if the codec is @@ -610,34 +691,35 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, if (delay && pc && pc->pict_type != FF_B_TYPE) presentation_delayed = 1; - /* this may be redundant, but it shouldnt hurt */ + /* This may be redundant, but it should not hurt. */ if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts) presentation_delayed = 1; if(st->cur_dts == AV_NOPTS_VALUE){ - st->cur_dts = -delay * pkt->duration; + st->cur_dts = 0; //FIXME maybe set it to 0 during init } // av_log(NULL, AV_LOG_DEBUG, "IN delayed:%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64" st:%d pc:%p\n", presentation_delayed, pkt->pts, pkt->dts, st->cur_dts, pkt->stream_index, pc); /* interpolate PTS and DTS if they are not present */ if(delay <=1){ if (presentation_delayed) { - /* DTS = decompression time stamp */ - /* PTS = presentation time stamp */ + /* DTS = decompression timestamp */ + /* PTS = presentation timestamp */ if (pkt->dts == AV_NOPTS_VALUE) pkt->dts = st->last_IP_pts; + update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); if (pkt->dts == AV_NOPTS_VALUE) pkt->dts = st->cur_dts; /* this is tricky: the dts must be incremented by the duration - of the frame we are displaying, i.e. the last I or P frame */ + of the frame we are displaying, i.e. the last I- or P-frame */ if (st->last_IP_duration == 0) st->last_IP_duration = pkt->duration; st->cur_dts = pkt->dts + st->last_IP_duration; st->last_IP_duration = pkt->duration; st->last_IP_pts= pkt->pts; /* cannot compute PTS if not present (we can compute it only - by knowing the futur */ + by knowing the future */ } else if(pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE || pkt->duration){ if(pkt->pts != AV_NOPTS_VALUE && pkt->duration){ int64_t old_diff= FFABS(st->cur_dts - pkt->duration - pkt->pts); @@ -651,6 +733,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, /* presentation is not delayed : PTS and DTS are the same */ if(pkt->pts == AV_NOPTS_VALUE) pkt->pts = pkt->dts; + update_initial_timestamps(s, pkt->stream_index, pkt->pts, pkt->pts); if(pkt->pts == AV_NOPTS_VALUE) pkt->pts = st->cur_dts; pkt->dts = pkt->pts; @@ -666,6 +749,9 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i+1]); if(pkt->dts == AV_NOPTS_VALUE) pkt->dts= st->pts_buffer[0]; + if(delay>1){ + update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts); // this should happen on the first packet + } if(pkt->dts > st->cur_dts) st->cur_dts = pkt->dts; } @@ -673,9 +759,11 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, // av_log(NULL, AV_LOG_ERROR, "OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n", presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts); /* update flags */ - if (pc) { + if(is_intra_only(st->codec)) + pkt->flags |= PKT_FLAG_KEY; + else if (pc) { pkt->flags = 0; - /* key frame computation */ + /* keyframe computation */ if (pc->pict_type == FF_I_TYPE) pkt->flags |= PKT_FLAG_KEY; } @@ -691,6 +779,8 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) AVStream *st; int len, ret, i; + av_init_packet(pkt); + for(;;) { /* select current input stream component */ st = s->cur_st; @@ -715,6 +805,7 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) /* return packet if any */ if (pkt->size) { got_packet: + pkt->pos = s->cur_pkt.pos; // Isn't quite accurate but close. pkt->duration = 0; pkt->stream_index = st->index; pkt->pts = st->parser->pts; @@ -723,6 +814,7 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) compute_pkt_fields(s, st, st->parser, pkt); if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & PKT_FLAG_KEY){ + ff_reduce_index(s, st->index); av_add_index_entry(st, st->parser->frame_offset, pkt->dts, 0, 0, AVINDEX_KEYFRAME); } @@ -752,7 +844,7 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) goto got_packet; } } - /* no more packets: really terminates parsing */ + /* no more packets: really terminate parsing */ return ret; } @@ -770,9 +862,9 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (st->need_parsing && !st->parser) { st->parser = av_parser_init(st->codec->codec_id); if (!st->parser) { - /* no parser available : just output the raw packets */ - st->need_parsing = 0; - }else if(st->need_parsing == 2){ + /* no parser available: just output the raw packets */ + st->need_parsing = AVSTREAM_PARSE_NONE; + }else if(st->need_parsing == AVSTREAM_PARSE_HEADERS){ st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } if(st->parser && (s->iformat->flags & AVFMT_GENERIC_INDEX)){ @@ -792,6 +884,22 @@ static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt) return 0; } +static AVPacket *add_to_pktbuf(AVFormatContext *s, AVPacket *pkt){ + AVPacketList *pktl= s->packet_buffer; + AVPacketList **plast_pktl= &s->packet_buffer; + + while(*plast_pktl) plast_pktl= &(*plast_pktl)->next; //FIXME maybe maintain pointer to the last? + + pktl = av_mallocz(sizeof(AVPacketList)); + if (!pktl) + return NULL; + + /* add the packet in the buffered packet list */ + *plast_pktl = pktl; + pktl->pkt= *pkt; + return &pktl->pkt; +} + int av_read_frame(AVFormatContext *s, AVPacket *pkt) { AVPacketList *pktl; @@ -827,7 +935,6 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) } } if(genpts){ - AVPacketList **plast_pktl= &s->packet_buffer; int ret= av_read_frame_internal(s, pkt); if(ret<0){ if(pktl && ret != AVERROR(EAGAIN)){ @@ -837,19 +944,8 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) return ret; } - /* duplicate the packet */ - if (av_dup_packet(pkt) < 0) - return AVERROR_NOMEM; - - while(*plast_pktl) plast_pktl= &(*plast_pktl)->next; //FIXME maybe maintain pointer to the last? - - pktl = av_mallocz(sizeof(AVPacketList)); - if (!pktl) - return AVERROR_NOMEM; - - /* add the packet in the buffered packet list */ - *plast_pktl = pktl; - pktl->pkt= *pkt; + if(av_dup_packet(add_to_pktbuf(s, pkt)) < 0) + return AVERROR(ENOMEM); }else{ assert(!s->packet_buffer); return av_read_frame_internal(s, pkt); @@ -936,6 +1032,19 @@ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp){ } } +void ff_reduce_index(AVFormatContext *s, int stream_index) +{ + AVStream *st= s->streams[stream_index]; + unsigned int max_entries= s->max_index_size / sizeof(AVIndexEntry); + + if((unsigned)st->nb_index_entries >= max_entries){ + int i; + for(i=0; 2*i<st->nb_index_entries; i++) + st->index_entries[i]= st->index_entries[2*i]; + st->nb_index_entries= i; + } +} + int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int size, int distance, int flags) { @@ -967,7 +1076,7 @@ int av_add_index_entry(AVStream *st, return -1; memmove(entries + index + 1, entries + index, sizeof(AVIndexEntry)*(st->nb_index_entries - index)); st->nb_index_entries++; - }else if(ie->pos == pos && distance < ie->min_distance) //dont reduce the distance + }else if(ie->pos == pos && distance < ie->min_distance) //do not reduce the distance distance= ie->min_distance; } @@ -980,49 +1089,6 @@ int av_add_index_entry(AVStream *st, return index; } -/** - * build an index for raw streams using a parser. - */ -static void av_build_index_raw(AVFormatContext *s) -{ - AVPacket pkt1, *pkt = &pkt1; - int ret; - AVStream *st; - - st = s->streams[0]; - av_read_frame_flush(s); - url_fseek(&s->pb, s->data_offset, SEEK_SET); - - for(;;) { - ret = av_read_frame(s, pkt); - if (ret < 0) - break; - if (pkt->stream_index == 0 && st->parser && - (pkt->flags & PKT_FLAG_KEY)) { - av_add_index_entry(st, st->parser->frame_offset, pkt->dts, - 0, 0, AVINDEX_KEYFRAME); - } - av_free_packet(pkt); - } -} - -/** - * Returns TRUE if we deal with a raw stream. - * - * Raw codec data and parsing needed. - */ -static int is_raw_stream(AVFormatContext *s) -{ - AVStream *st; - - if (s->nb_streams != 1) - return 0; - st = s->streams[0]; - if (!st->need_parsing) - return 0; - return 1; -} - int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags) { @@ -1073,13 +1139,13 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts ts_max= ts_min= AV_NOPTS_VALUE; - pos_limit= -1; //gcc falsely says it may be uninitalized + pos_limit= -1; //gcc falsely says it may be uninitialized st= s->streams[stream_index]; if(st->index_entries){ AVIndexEntry *e; - index= av_index_search_timestamp(st, target_ts, flags | AVSEEK_FLAG_BACKWARD); //FIXME whole func must be checked for non keyframe entries in index case, especially read_timestamp() + index= av_index_search_timestamp(st, target_ts, flags | AVSEEK_FLAG_BACKWARD); //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp() index= FFMAX(index, 0); e= &st->index_entries[index]; @@ -1114,7 +1180,7 @@ int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts return -1; /* do the seek */ - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); av_update_cur_dts(s, st, ts); @@ -1139,7 +1205,7 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, i if(ts_max == AV_NOPTS_VALUE){ int step= 1024; - filesize = url_fsize(&s->pb); + filesize = url_fsize(s->pb); pos_max = filesize - 1; do{ pos_max -= step; @@ -1186,7 +1252,8 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, i // bisection, if interpolation failed to change min or max pos last time pos = (pos_min + pos_limit)>>1; }else{ - // linear search if bisection failed, can only happen if there are very few or no keframes between min/max + /* linear search if bisection failed, can only happen if there + are very few or no keyframes between min/max */ pos=pos_min; } if(pos <= pos_min) @@ -1203,6 +1270,10 @@ int64_t av_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts, i #ifdef DEBUG_SEEK av_log(s, AV_LOG_DEBUG, "%"PRId64" %"PRId64" %"PRId64" / %"PRId64" %"PRId64" %"PRId64" target:%"PRId64" limit:%"PRId64" start:%"PRId64" noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change); #endif + if(ts == AV_NOPTS_VALUE){ + av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n"); + return -1; + } assert(ts != AV_NOPTS_VALUE); if (target_ts <= ts) { pos_limit = start_pos - 1; @@ -1241,12 +1312,12 @@ static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, #endif pos_min = s->data_offset; - pos_max = url_fsize(&s->pb) - 1; + pos_max = url_fsize(s->pb) - 1; if (pos < pos_min) pos= pos_min; else if(pos > pos_max) pos= pos_max; - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); #if 0 av_update_cur_dts(s, st, ts); @@ -1265,16 +1336,16 @@ static int av_seek_frame_generic(AVFormatContext *s, index = av_index_search_timestamp(st, timestamp, flags); - if(index < 0){ + if(index < 0 || index==st->nb_index_entries-1){ int i; AVPacket pkt; if(st->index_entries && st->nb_index_entries){ ie= &st->index_entries[st->nb_index_entries-1]; - url_fseek(&s->pb, ie->pos, SEEK_SET); + url_fseek(s->pb, ie->pos, SEEK_SET); av_update_cur_dts(s, st, ie->timestamp); }else - url_fseek(&s->pb, 0, SEEK_SET); + url_fseek(s->pb, 0, SEEK_SET); for(i=0;; i++) { int ret = av_read_frame(s, &pkt); @@ -1297,7 +1368,7 @@ static int av_seek_frame_generic(AVFormatContext *s, return 0; } ie = &st->index_entries[index]; - url_fseek(&s->pb, ie->pos, SEEK_SET); + url_fseek(s->pb, ie->pos, SEEK_SET); av_update_cur_dts(s, st, ie->timestamp); @@ -1343,19 +1414,18 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int f /*******************************************************/ /** - * Returns TRUE if the stream has accurate timings in any stream. + * Returns TRUE if the stream has accurate duration in any stream. * - * @return TRUE if the stream has accurate timings for at least one component. + * @return TRUE if the stream has accurate duration for at least one component. */ -static int av_has_timings(AVFormatContext *ic) +static int av_has_duration(AVFormatContext *ic) { int i; AVStream *st; for(i = 0;i < ic->nb_streams; i++) { st = ic->streams[i]; - if (st->start_time != AV_NOPTS_VALUE && - st->duration != AV_NOPTS_VALUE) + if (st->duration != AV_NOPTS_VALUE) return 1; } return 0; @@ -1369,14 +1439,16 @@ static int av_has_timings(AVFormatContext *ic) static void av_update_stream_timings(AVFormatContext *ic) { int64_t start_time, start_time1, end_time, end_time1; + int64_t duration, duration1; int i; AVStream *st; start_time = 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) { + 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 (start_time1 < start_time) start_time = start_time1; @@ -1387,19 +1459,27 @@ static void av_update_stream_timings(AVFormatContext *ic) end_time = end_time1; } } + if (st->duration != AV_NOPTS_VALUE) { + duration1 = av_rescale_q(st->duration, st->time_base, AV_TIME_BASE_Q); + if (duration1 > duration) + duration = duration1; + } } if (start_time != INT64_MAX) { ic->start_time = start_time; if (end_time != INT64_MIN) { - ic->duration = end_time - start_time; - if (ic->file_size > 0) { - /* compute the bit rate */ - ic->bit_rate = (double)ic->file_size * 8.0 * AV_TIME_BASE / - (double)ic->duration; - } + if (end_time - start_time > duration) + duration = end_time - start_time; + } + } + if (duration != INT64_MIN) { + ic->duration = duration; + if (ic->file_size > 0) { + /* compute the bitrate */ + ic->bit_rate = (double)ic->file_size * 8.0 * AV_TIME_BASE / + (double)ic->duration; } } - } static void fill_all_stream_timings(AVFormatContext *ic) @@ -1444,11 +1524,8 @@ static void av_estimate_timings_from_bit_rate(AVFormatContext *ic) for(i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; duration= av_rescale(8*filesize, st->time_base.den, ic->bit_rate*(int64_t)st->time_base.num); - if (st->start_time == AV_NOPTS_VALUE || - st->duration == AV_NOPTS_VALUE) { - st->start_time = 0; + if (st->duration == AV_NOPTS_VALUE) st->duration = duration; - } } } } @@ -1465,11 +1542,25 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, offset_t old_offse int64_t end_time; int64_t filesize, offset, duration; - av_read_frame_flush(ic); + /* free previous packet */ + if (ic->cur_st && ic->cur_st->parser) + av_free_packet(&ic->cur_pkt); + ic->cur_st = NULL; + + /* flush packet queue */ + flush_packet_queue(ic); + + for(i=0;i<ic->nb_streams;i++) { + st = ic->streams[i]; + if (st->parser) { + av_parser_close(st->parser); + st->parser= NULL; + } + } /* we read the first packets to get the first PTS (not fully accurate, but it is enough now) */ - url_fseek(&ic->pb, 0, SEEK_SET); + url_fseek(ic->pb, 0, SEEK_SET); read_size = 0; for(;;) { if (read_size >= DURATION_MAX_READ_SIZE) @@ -1502,26 +1593,19 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, offset_t old_offse if (offset < 0) offset = 0; - url_fseek(&ic->pb, offset, SEEK_SET); + url_fseek(ic->pb, offset, SEEK_SET); read_size = 0; for(;;) { if (read_size >= DURATION_MAX_READ_SIZE) break; - /* if all info is available, we can stop */ - for(i = 0;i < ic->nb_streams; i++) { - st = ic->streams[i]; - if (st->duration == AV_NOPTS_VALUE) - break; - } - if (i == ic->nb_streams) - break; ret = av_read_packet(ic, pkt); if (ret != 0) break; read_size += pkt->size; st = ic->streams[pkt->stream_index]; - if (pkt->pts != AV_NOPTS_VALUE) { + if (pkt->pts != AV_NOPTS_VALUE && + st->start_time != AV_NOPTS_VALUE) { end_time = pkt->pts; duration = end_time - st->start_time; if (duration > 0) { @@ -1535,7 +1619,12 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, offset_t old_offse fill_all_stream_timings(ic); - url_fseek(&ic->pb, old_offset, SEEK_SET); + url_fseek(ic->pb, old_offset, SEEK_SET); + for(i=0; i<ic->nb_streams; i++){ + st= ic->streams[i]; + st->cur_dts= st->first_dts; + st->last_IP_pts = AV_NOPTS_VALUE; + } } static void av_estimate_timings(AVFormatContext *ic, offset_t old_offset) @@ -1546,7 +1635,7 @@ static void av_estimate_timings(AVFormatContext *ic, offset_t old_offset) if (ic->iformat->flags & AVFMT_NOFILE) { file_size = 0; } else { - file_size = url_fsize(&ic->pb); + file_size = url_fsize(ic->pb); if (file_size < 0) file_size = 0; } @@ -1554,15 +1643,15 @@ static void av_estimate_timings(AVFormatContext *ic, offset_t old_offset) if ((!strcmp(ic->iformat->name, "mpeg") || !strcmp(ic->iformat->name, "mpegts")) && - file_size && !ic->pb.is_streamed) { + file_size && !url_is_streamed(ic->pb)) { /* get accurate estimate from the PTSes */ av_estimate_timings_from_pts(ic, old_offset); - } else if (av_has_timings(ic)) { - /* at least one components has timings - we use them for all + } else if (av_has_duration(ic)) { + /* at least one component has timings - we use them for all the components */ fill_all_stream_timings(ic); } else { - /* less precise: use bit rate info */ + /* less precise: use bitrate info */ av_estimate_timings_from_bit_rate(ic); } av_update_stream_timings(ic); @@ -1599,7 +1688,7 @@ static int has_codec_parameters(AVCodecContext *enc) val = 1; break; } - return (val != 0); + return (enc->codec_id != CODEC_ID_NONE && val != 0); } static int try_decode_frame(AVStream *st, const uint8_t *data, int size) @@ -1622,7 +1711,7 @@ static int try_decode_frame(AVStream *st, const uint8_t *data, int size) switch(st->codec->codec_type) { case CODEC_TYPE_VIDEO: ret = avcodec_decode_video(st->codec, &picture, - &got_picture, (uint8_t *)data, size); + &got_picture, data, size); break; case CODEC_TYPE_AUDIO: data_size = FFMAX(size, AVCODEC_MAX_AUDIO_FRAME_SIZE); @@ -1630,7 +1719,7 @@ static int try_decode_frame(AVStream *st, const uint8_t *data, int size) if (!samples) goto fail; ret = avcodec_decode_audio2(st->codec, samples, - &data_size, (uint8_t *)data, size); + &data_size, data, size); av_free(samples); break; default: @@ -1641,6 +1730,67 @@ static int try_decode_frame(AVStream *st, const uint8_t *data, int size) return ret; } +static int set_codec_from_probe_data(AVStream *st, AVProbeData *pd, int score) +{ + AVInputFormat *fmt; + fmt = av_probe_input_format2(pd, 1, &score); + + if (fmt) { + if (strncmp(fmt->name, "mp3", 3) == 0) + st->codec->codec_id = CODEC_ID_MP3; + else if (strncmp(fmt->name, "ac3", 3) == 0) + st->codec->codec_id = CODEC_ID_AC3; + } + return !!fmt; +} + +unsigned int codec_get_tag(const AVCodecTag *tags, int id) +{ + while (tags->id != CODEC_ID_NONE) { + if (tags->id == id) + return tags->tag; + tags++; + } + return 0; +} + +enum CodecID codec_get_id(const AVCodecTag *tags, unsigned int tag) +{ + int i; + for(i=0; tags[i].id != CODEC_ID_NONE;i++) { + if(tag == tags[i].tag) + return tags[i].id; + } + for(i=0; tags[i].id != CODEC_ID_NONE; i++) { + if( toupper((tag >> 0)&0xFF) == toupper((tags[i].tag >> 0)&0xFF) + && toupper((tag >> 8)&0xFF) == toupper((tags[i].tag >> 8)&0xFF) + && toupper((tag >>16)&0xFF) == toupper((tags[i].tag >>16)&0xFF) + && toupper((tag >>24)&0xFF) == toupper((tags[i].tag >>24)&0xFF)) + return tags[i].id; + } + return CODEC_ID_NONE; +} + +unsigned int av_codec_get_tag(const AVCodecTag *tags[4], enum CodecID id) +{ + int i; + for(i=0; tags && tags[i]; i++){ + int tag= codec_get_tag(tags[i], id); + if(tag) return tag; + } + return 0; +} + +enum CodecID av_codec_get_id(const AVCodecTag *tags[4], unsigned int tag) +{ + int i; + for(i=0; tags && tags[i]; i++){ + enum CodecID id= codec_get_id(tags[i], tag); + if(id!=CODEC_ID_NONE) return id; + } + return CODEC_ID_NONE; +} + /* absolute maximum size we read until we abort */ #define MAX_READ_SIZE 5000000 @@ -1650,21 +1800,40 @@ static int get_std_framerate(int i){ else return ((int[]){24,30,60,12,15})[i-60*12]*1000*12; } +/* + * Is the time base unreliable. + * This is a heuristic to balance between quick acceptance of the values in + * the headers vs. some extra checks. + * Old DivX and Xvid often have nonsense timebases like 1fps or 2fps. + * MPEG-2 commonly misuses field repeat flags to store different framerates. + * And there are "variable" fps files this needs to detect as well. + */ +static int tb_unreliable(AVCodecContext *c){ + if( c->time_base.den >= 101L*c->time_base.num + || c->time_base.den < 5L*c->time_base.num +/* || c->codec_tag == ff_get_fourcc("DIVX") + || c->codec_tag == ff_get_fourcc("XVID")*/ + || c->codec_id == CODEC_ID_MPEG2VIDEO) + return 1; + return 0; +} + int av_find_stream_info(AVFormatContext *ic) { int i, count, ret, read_size, j; AVStream *st; AVPacket pkt1, *pkt; - AVPacketList *pktl=NULL, **ppktl; int64_t last_dts[MAX_STREAMS]; int duration_count[MAX_STREAMS]={0}; double (*duration_error)[MAX_STD_TIMEBASES]; - offset_t old_offset = url_ftell(&ic->pb); + offset_t old_offset = url_ftell(ic->pb); int64_t codec_info_duration[MAX_STREAMS]={0}; int codec_info_nb_frames[MAX_STREAMS]={0}; + AVProbeData probe_data[MAX_STREAMS]; + int codec_identified[MAX_STREAMS]={0}; duration_error = av_mallocz(MAX_STREAMS * sizeof(*duration_error)); - if (!duration_error) return AVERROR_NOMEM; + if (!duration_error) return AVERROR(ENOMEM); for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; @@ -1677,7 +1846,7 @@ int av_find_stream_info(AVFormatContext *ic) //only for the split stuff if (!st->parser) { st->parser = av_parser_init(st->codec->codec_id); - if(st->need_parsing == 2 && st->parser){ + if(st->need_parsing == AVSTREAM_PARSE_HEADERS && st->parser){ st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } } @@ -1687,9 +1856,9 @@ int av_find_stream_info(AVFormatContext *ic) last_dts[i]= AV_NOPTS_VALUE; } + memset(probe_data, 0, sizeof(probe_data)); count = 0; read_size = 0; - ppktl = &ic->packet_buffer; for(;;) { /* check if one codec still needs to be handled */ for(i=0;i<ic->nb_streams;i++) { @@ -1697,11 +1866,13 @@ int av_find_stream_info(AVFormatContext *ic) if (!has_codec_parameters(st->codec)) break; /* variable fps and no guess at the real fps */ - if( (st->codec->time_base.den >= 101LL*st->codec->time_base.num || st->codec->codec_id == CODEC_ID_MPEG2VIDEO) + if( tb_unreliable(st->codec) && duration_count[i]<20 && st->codec->codec_type == CODEC_TYPE_VIDEO) break; if(st->parser && st->parser->parser->split && !st->codec->extradata) break; + if(st->first_dts == AV_NOPTS_VALUE) + break; } if (i == ic->nb_streams) { /* NOTE: if the format has no header, then we need to read @@ -1738,24 +1909,9 @@ int av_find_stream_info(AVFormatContext *ic) break; } - pktl = av_mallocz(sizeof(AVPacketList)); - if (!pktl) { - ret = AVERROR_NOMEM; - break; - } - - /* add the packet in the buffered packet list */ - *ppktl = pktl; - ppktl = &pktl->next; - - pkt = &pktl->pkt; - *pkt = pkt1; - - /* duplicate the packet */ - if (av_dup_packet(pkt) < 0) { - ret = AVERROR_NOMEM; - break; - } + pkt= add_to_pktbuf(ic, &pkt1); + if(av_dup_packet(pkt) < 0) + return AVERROR(ENOMEM); read_size += pkt->size; @@ -1787,6 +1943,14 @@ int av_find_stream_info(AVFormatContext *ic) } if(last == AV_NOPTS_VALUE || duration_count[index]<=1) last_dts[pkt->stream_index]= pkt->dts; + + if (st->codec->codec_id == CODEC_ID_NONE) { + AVProbeData *pd = &(probe_data[st->index]); + pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE); + memcpy(pd->buf+pd->buf_size, pkt->data, pkt->size); + pd->buf_size += pkt->size; + memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE); + } } if(st->parser && st->parser->parser->split && !st->codec->extradata){ int i= st->parser->parser->split(st->codec, pkt->data, pkt->size); @@ -1800,8 +1964,8 @@ int av_find_stream_info(AVFormatContext *ic) /* if still no information, we try to open the codec and to decompress the frame. We try to avoid that in most cases as - it takes longer and uses more memory. For MPEG4, we need to - decompress for Quicktime. */ + it takes longer and uses more memory. For MPEG-4, we need to + decompress for QuickTime. */ if (!has_codec_parameters(st->codec) /*&& (st->codec->codec_id == CODEC_ID_FLV1 || st->codec->codec_id == CODEC_ID_H264 || @@ -1819,7 +1983,7 @@ int av_find_stream_info(AVFormatContext *ic) (st->codec->codec_id == CODEC_ID_MPEG4 && !st->need_parsing))*/) try_decode_frame(st, pkt->data, pkt->size); - if (av_rescale_q(codec_info_duration[st->index], st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) { + if (st->time_base.den > 0 && av_rescale_q(codec_info_duration[st->index], st->time_base, AV_TIME_BASE_Q) >= ic->max_analyze_duration) { break; } count++; @@ -1838,8 +2002,8 @@ int av_find_stream_info(AVFormatContext *ic) st->codec->codec_tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt); if(duration_count[i] - && (st->codec->time_base.num*101LL <= st->codec->time_base.den || st->codec->codec_id == CODEC_ID_MPEG2VIDEO) /*&& - //FIXME we should not special case mpeg2, but this needs testing with non mpeg2 ... + && 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]/duration_count[i]*101LL > st->time_base.den*/){ double best_error= 2*av_q2d(st->time_base); best_error= best_error*best_error*duration_count[i]*1000*12*30; @@ -1866,14 +2030,39 @@ int av_find_stream_info(AVFormatContext *ic) } } }else if(st->codec->codec_type == CODEC_TYPE_AUDIO) { + if (st->codec->codec_id == CODEC_ID_NONE && probe_data[st->index].buf_size > 0) { + codec_identified[st->index] = set_codec_from_probe_data(st, &(probe_data[st->index]), 1); + if (codec_identified[st->index]) { + st->need_parsing = AVSTREAM_PARSE_FULL; + } + } if(!st->codec->bits_per_sample) st->codec->bits_per_sample= av_get_bits_per_sample(st->codec->codec_id); } } av_estimate_timings(ic, old_offset); + + for(i=0;i<ic->nb_streams;i++) { + st = ic->streams[i]; + if (codec_identified[st->index]) + break; + } + //FIXME this is a mess + if(i!=ic->nb_streams){ + av_read_frame_flush(ic); + for(i=0;i<ic->nb_streams;i++) { + st = ic->streams[i]; + if (codec_identified[st->index]) { + av_seek_frame(ic, st->index, 0.0, 0); + } + st->cur_dts= st->first_dts; + } + url_fseek(ic->pb, ic->data_offset, SEEK_SET); + } + #if 0 - /* correct DTS for b frame streams with no timestamps */ + /* correct DTS for B-frame streams with no timestamps */ for(i=0;i<ic->nb_streams;i++) { st = ic->streams[i]; if (st->codec->codec_type == CODEC_TYPE_VIDEO) { @@ -1898,6 +2087,9 @@ int av_find_stream_info(AVFormatContext *ic) #endif av_free(duration_error); + for(i=0;i<MAX_STREAMS;i++){ + av_freep(&(probe_data[i].buf)); + } return ret; } @@ -1906,21 +2098,25 @@ int av_find_stream_info(AVFormatContext *ic) int av_read_play(AVFormatContext *s) { - if (!s->iformat->read_play) - return AVERROR_NOTSUPP; - return s->iformat->read_play(s); + if (s->iformat->read_play) + return s->iformat->read_play(s); + if (s->pb) + return av_url_read_fpause(s->pb, 0); + return AVERROR(ENOSYS); } int av_read_pause(AVFormatContext *s) { - if (!s->iformat->read_pause) - return AVERROR_NOTSUPP; - return s->iformat->read_pause(s); + if (s->iformat->read_pause) + return s->iformat->read_pause(s); + if (s->pb) + return av_url_read_fpause(s->pb, 1); + return AVERROR(ENOSYS); } -void av_close_input_file(AVFormatContext *s) +void av_close_input_stream(AVFormatContext *s) { - int i, must_open_file; + int i; AVStream *st; /* free previous packet */ @@ -1938,20 +2134,28 @@ void av_close_input_file(AVFormatContext *s) av_free(st->index_entries); av_free(st->codec->extradata); av_free(st->codec); + av_free(st->filename); av_free(st); } - flush_packet_queue(s); - must_open_file = 1; - if (s->iformat->flags & AVFMT_NOFILE) { - must_open_file = 0; - } - if (must_open_file) { - url_fclose(&s->pb); + for(i=s->nb_programs-1; i>=0; i--) { + av_freep(&s->programs[i]->provider_name); + av_freep(&s->programs[i]->name); + av_freep(&s->programs[i]->stream_index); + av_freep(&s->programs[i]); } + flush_packet_queue(s); av_freep(&s->priv_data); av_free(s); } +void av_close_input_file(AVFormatContext *s) +{ + ByteIOContext *pb = s->iformat->flags & AVFMT_NOFILE ? NULL : s->pb; + av_close_input_stream(s); + if (pb) + url_fclose(pb); +} + AVStream *av_new_stream(AVFormatContext *s, int id) { AVStream *st; @@ -1974,8 +2178,9 @@ AVStream *av_new_stream(AVFormatContext *s, int id) st->start_time = AV_NOPTS_VALUE; st->duration = AV_NOPTS_VALUE; st->cur_dts = AV_NOPTS_VALUE; + st->first_dts = AV_NOPTS_VALUE; - /* default pts settings is MPEG like */ + /* default pts setting is MPEG-like */ av_set_pts_info(st, 33, 1, 90000); st->last_IP_pts = AV_NOPTS_VALUE; for(i=0; i<MAX_REORDER_DELAY+1; i++) @@ -1985,6 +2190,43 @@ AVStream *av_new_stream(AVFormatContext *s, int id) return st; } +AVProgram *av_new_program(AVFormatContext *ac, int id) +{ + AVProgram *program=NULL; + int i; + +#ifdef DEBUG_SI + av_log(ac, AV_LOG_DEBUG, "new_program: id=0x%04x\n", id); +#endif + + for(i=0; i<ac->nb_programs; i++) + if(ac->programs[i]->id == id) + program = ac->programs[i]; + + if(!program){ + program = av_mallocz(sizeof(AVProgram)); + if (!program) + return NULL; + dynarray_add(&ac->programs, &ac->nb_programs, program); + program->discard = AVDISCARD_NONE; + } + program->id = id; + + return program; +} + +void av_set_program_name(AVProgram *program, char *provider_name, char *name) +{ + assert(!provider_name == !name); + if(name){ + av_free(program->provider_name); + av_free(program-> name); + program->provider_name = av_strdup(provider_name); + program-> name = av_strdup( name); + } +} + + /************************************************************/ /* output media file */ @@ -1995,7 +2237,7 @@ int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) if (s->oformat->priv_data_size > 0) { s->priv_data = av_mallocz(s->oformat->priv_data_size); if (!s->priv_data) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } else s->priv_data = NULL; @@ -2039,7 +2281,7 @@ int av_write_header(AVFormatContext *s) if(st->codec->codec_tag){ //FIXME //check that tag + id is in the table - //if neither is in the table -> ok + //if neither is in the table -> OK //if tag is in the table with another id -> FAIL //if id is in the table with another tag -> FAIL unless strict < ? }else @@ -2050,7 +2292,7 @@ int av_write_header(AVFormatContext *s) if (!s->priv_data && s->oformat->priv_data_size > 0) { s->priv_data = av_mallocz(s->oformat->priv_data_size); if (!s->priv_data) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); } if(s->oformat->write_header){ @@ -2120,12 +2362,11 @@ static int compute_pkt_fields2(AVStream *st, AVPacket *pkt){ } if(st->cur_dts && st->cur_dts != AV_NOPTS_VALUE && st->cur_dts >= pkt->dts){ - av_log(NULL, AV_LOG_ERROR, "error, non monotone timestamps %"PRId64" >= %"PRId64" st:%d\n", st->cur_dts, pkt->dts, st->index); + av_log(NULL, AV_LOG_ERROR, "error, non monotone timestamps %"PRId64" >= %"PRId64"\n", st->cur_dts, pkt->dts); return -1; } if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts < pkt->dts){ - av_log(NULL, AV_LOG_ERROR, "error, pts < dts (%"PRId64" < %"PRId64")\n", - pkt->pts, pkt->dts); + av_log(NULL, AV_LOG_ERROR, "error, pts < dts\n"); return -1; } @@ -2138,8 +2379,9 @@ static int compute_pkt_fields2(AVStream *st, AVPacket *pkt){ case CODEC_TYPE_AUDIO: frame_size = get_audio_frame_size(st->codec, pkt->size); - /* HACK/FIXME, we skip the initial 0-size packets as they are most likely equal to the encoder delay, - but it would be better if we had the real timestamps from the encoder */ + /* HACK/FIXME, we skip the initial 0 size packets as they are most + likely equal to the encoder delay, but it would be better if we + had the real timestamps from the encoder */ if (frame_size >= 0 && (pkt->size || st->pts.num!=st->pts.den>>1 || st->pts.val)) { av_frac_add(&st->pts, (int64_t)st->time_base.den * frame_size); } @@ -2157,7 +2399,7 @@ static void truncate_ts(AVStream *st, AVPacket *pkt){ int64_t pts_mask = (2LL << (st->pts_wrap_bits-1)) - 1; // if(pkt->dts < 0) -// pkt->dts= 0; //this happens for low_delay=0 and b frames, FIXME, needs further invstigation about what we should do here +// pkt->dts= 0; //this happens for low_delay=0 and B-frames, FIXME, needs further investigation about what we should do here if (pkt->pts != AV_NOPTS_VALUE) pkt->pts &= pts_mask; @@ -2177,7 +2419,7 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) ret= s->oformat->write_packet(s, pkt); if(!ret) - ret= url_ferror(&s->pb); + ret= url_ferror(s->pb); return ret; } @@ -2194,7 +2436,7 @@ int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pk this_pktl = av_mallocz(sizeof(AVPacketList)); this_pktl->pkt= *pkt; if(pkt->destruct == av_destruct_packet) - pkt->destruct= NULL; // non shared -> must keep original from being freed + pkt->destruct= NULL; // not shared -> must keep original from being freed else av_dup_packet(&this_pktl->pkt); //shared -> must dup @@ -2235,7 +2477,7 @@ int av_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out, AVPacket *pk } /** - * Interleaves a AVPacket correctly so it can be muxed. + * Interleaves an AVPacket correctly so it can be muxed. * @param out the interleaved packet will be output here * @param in the input packet * @param flush 1 if no further packets are available as input and all @@ -2278,8 +2520,8 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt){ if(ret<0) return ret; - if(url_ferror(&s->pb)) - return url_ferror(&s->pb); + if(url_ferror(s->pb)) + return url_ferror(s->pb); } } @@ -2302,7 +2544,7 @@ int av_write_trailer(AVFormatContext *s) if(ret<0) goto fail; - if(url_ferror(&s->pb)) + if(url_ferror(s->pb)) goto fail; } @@ -2310,22 +2552,70 @@ int av_write_trailer(AVFormatContext *s) ret = s->oformat->write_trailer(s); fail: if(ret == 0) - ret=url_ferror(&s->pb); + ret=url_ferror(s->pb); for(i=0;i<s->nb_streams;i++) av_freep(&s->streams[i]->priv_data); av_freep(&s->priv_data); return ret; } +void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx) +{ + int i, j; + AVProgram *program=NULL; + void *tmp; + + for(i=0; i<ac->nb_programs; i++){ + if(ac->programs[i]->id != progid) + continue; + program = ac->programs[i]; + for(j=0; j<program->nb_stream_indexes; j++) + if(program->stream_index[j] == idx) + return; + + tmp = av_realloc(program->stream_index, sizeof(unsigned int)*(program->nb_stream_indexes+1)); + if(!tmp) + return; + program->stream_index = tmp; + program->stream_index[program->nb_stream_indexes++] = idx; + return; + } +} + /* "user interface" functions */ +static void dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) +{ + char buf[256]; + int flags = (is_output ? ic->oformat->flags : ic->iformat->flags); + AVStream *st = ic->streams[i]; + int g = ff_gcd(st->time_base.num, st->time_base.den); + avcodec_string(buf, sizeof(buf), st->codec, is_output); + 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) + av_log(NULL, AV_LOG_INFO, "[0x%x]", st->id); + if (strlen(st->language) > 0) + av_log(NULL, AV_LOG_INFO, "(%s)", st->language); + av_log(NULL, AV_LOG_DEBUG, ", %d/%d", st->time_base.num/g, st->time_base.den/g); + av_log(NULL, AV_LOG_INFO, ": %s", buf); + if(st->codec->codec_type == CODEC_TYPE_VIDEO){ + if(st->r_frame_rate.den && st->r_frame_rate.num) + av_log(NULL, AV_LOG_INFO, ", %5.2f tb(r)", av_q2d(st->r_frame_rate)); +/* else if(st->time_base.den && st->time_base.num) + av_log(NULL, AV_LOG_INFO, ", %5.2f tb(m)", 1/av_q2d(st->time_base));*/ + else + av_log(NULL, AV_LOG_INFO, ", %5.2f tb(c)", 1/av_q2d(st->codec->time_base)); + } + av_log(NULL, AV_LOG_INFO, "\n"); +} void dump_format(AVFormatContext *ic, int index, const char *url, int is_output) { - int i, flags; - char buf[256]; + int i; av_log(NULL, AV_LOG_INFO, "%s #%d, %s, %s '%s':\n", is_output ? "Output" : "Input", @@ -2363,124 +2653,43 @@ void dump_format(AVFormatContext *ic, } av_log(NULL, AV_LOG_INFO, "\n"); } - for(i=0;i<ic->nb_streams;i++) { - AVStream *st = ic->streams[i]; - int g= ff_gcd(st->time_base.num, st->time_base.den); - avcodec_string(buf, sizeof(buf), st->codec, is_output); - 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 (is_output) - flags = ic->oformat->flags; - else - flags = ic->iformat->flags; - if (flags & AVFMT_SHOW_IDS) { - av_log(NULL, AV_LOG_INFO, "[0x%x]", st->id); - } - if (strlen(st->language) > 0) { - av_log(NULL, AV_LOG_INFO, "(%s)", st->language); - } - av_log(NULL, AV_LOG_DEBUG, ", %d/%d", st->time_base.num/g, st->time_base.den/g); - av_log(NULL, AV_LOG_INFO, ": %s", buf); - if(st->codec->codec_type == CODEC_TYPE_VIDEO){ - if(st->r_frame_rate.den && st->r_frame_rate.num) - av_log(NULL, AV_LOG_INFO, ", %5.2f fps(r)", av_q2d(st->r_frame_rate)); -/* else if(st->time_base.den && st->time_base.num) - av_log(NULL, AV_LOG_INFO, ", %5.2f fps(m)", 1/av_q2d(st->time_base));*/ - else - av_log(NULL, AV_LOG_INFO, ", %5.2f fps(c)", 1/av_q2d(st->codec->time_base)); - } - av_log(NULL, AV_LOG_INFO, "\n"); - } + if(ic->nb_programs) { + int j, k; + for(j=0; j<ic->nb_programs; j++) { + av_log(NULL, AV_LOG_INFO, " Program %d %s\n", ic->programs[j]->id, + ic->programs[j]->name ? ic->programs[j]->name : ""); + for(k=0; k<ic->programs[j]->nb_stream_indexes; k++) + dump_stream_format(ic, ic->programs[j]->stream_index[k], index, is_output); + } + } else + for(i=0;i<ic->nb_streams;i++) + dump_stream_format(ic, i, index, is_output); } -typedef struct { - const char *abv; - int width, height; - int frame_rate, frame_rate_base; -} AbvEntry; - -static AbvEntry frame_abvs[] = { - { "ntsc", 720, 480, 30000, 1001 }, - { "pal", 720, 576, 25, 1 }, - { "qntsc", 352, 240, 30000, 1001 }, /* VCD compliant ntsc */ - { "qpal", 352, 288, 25, 1 }, /* VCD compliant pal */ - { "sntsc", 640, 480, 30000, 1001 }, /* square pixel ntsc */ - { "spal", 768, 576, 25, 1 }, /* square pixel pal */ - { "film", 352, 240, 24, 1 }, - { "ntsc-film", 352, 240, 24000, 1001 }, - { "sqcif", 128, 96, 0, 0 }, - { "qcif", 176, 144, 0, 0 }, - { "cif", 352, 288, 0, 0 }, - { "4cif", 704, 576, 0, 0 }, -}; - int parse_image_size(int *width_ptr, int *height_ptr, const char *str) { - int i; - int n = sizeof(frame_abvs) / sizeof(AbvEntry); - const char *p; - int frame_width = 0, frame_height = 0; - - for(i=0;i<n;i++) { - if (!strcmp(frame_abvs[i].abv, str)) { - frame_width = frame_abvs[i].width; - frame_height = frame_abvs[i].height; - break; - } - } - if (i == n) { - p = str; - frame_width = strtol(p, (char **)&p, 10); - if (*p) - p++; - frame_height = strtol(p, (char **)&p, 10); - } - if (frame_width <= 0 || frame_height <= 0) - return -1; - *width_ptr = frame_width; - *height_ptr = frame_height; - return 0; + return av_parse_video_frame_size(width_ptr, height_ptr, str); } -int parse_frame_rate(int *frame_rate, int *frame_rate_base, const char *arg) +int parse_frame_rate(int *frame_rate_num, int *frame_rate_den, const char *arg) { - int i; - char* cp; - - /* First, we check our abbreviation table */ - for (i = 0; i < sizeof(frame_abvs)/sizeof(*frame_abvs); ++i) - if (!strcmp(frame_abvs[i].abv, arg)) { - *frame_rate = frame_abvs[i].frame_rate; - *frame_rate_base = frame_abvs[i].frame_rate_base; - return 0; - } + AVRational frame_rate; + int ret = av_parse_video_frame_rate(&frame_rate, arg); + *frame_rate_num= frame_rate.num; + *frame_rate_den= frame_rate.den; + return ret; +} - /* Then, we try to parse it as fraction */ - cp = strchr(arg, '/'); - if (!cp) - cp = strchr(arg, ':'); - if (cp) { - char* cpp; - *frame_rate = strtol(arg, &cpp, 10); - if (cpp != arg || cpp == cp) - *frame_rate_base = strtol(cp+1, &cpp, 10); - else - *frame_rate = 0; - } - else { - /* Finally we give up and parse it as double */ - AVRational time_base = av_d2q(strtod(arg, 0), DEFAULT_FRAME_RATE_BASE); - *frame_rate_base = time_base.den; - *frame_rate = time_base.num; - } - if (!*frame_rate || !*frame_rate_base) - return -1; - else - return 0; +/** + * Gets the current time in microseconds. + */ +int64_t av_gettime(void) +{ + struct timeval tv; + gettimeofday(&tv,NULL); + return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; } -#ifndef CONFIG_WINCE int64_t parse_date(const char *datestr, int duration) { const char *p; @@ -2515,6 +2724,7 @@ int64_t parse_date(const char *datestr, int duration) p = datestr; q = NULL; if (!duration) { + /* parse the year-month-day part */ for (i = 0; i < sizeof(date_fmt) / sizeof(date_fmt[0]); i++) { q = small_strptime(p, date_fmt[i], &dt); if (q) { @@ -2522,6 +2732,8 @@ int64_t parse_date(const char *datestr, int duration) } } + /* if the year-month-day part is missing, then take the + * current year-month-day time */ if (!q) { if (is_utc) { dt = *gmtime(&now); @@ -2536,6 +2748,7 @@ int64_t parse_date(const char *datestr, int duration) if (*p == 'T' || *p == 't' || *p == ' ') p++; + /* parse the hour-minute-second part */ for (i = 0; i < sizeof(time_fmt) / sizeof(time_fmt[0]); i++) { q = small_strptime(p, time_fmt[i], &dt); if (q) { @@ -2543,13 +2756,19 @@ int64_t parse_date(const char *datestr, int duration) } } } else { + /* parse datestr as a duration */ if (p[0] == '-') { negative = 1; ++p; } + /* parse datestr as HH:MM:SS */ q = small_strptime(p, time_fmt[0], &dt); if (!q) { + /* parse datestr as S+ */ dt.tm_sec = strtol(p, (char **)&q, 10); + if (q == p) + /* the parsing didn't succeed */ + return INT64_MIN; dt.tm_min = 0; dt.tm_hour = 0; } @@ -2557,10 +2776,7 @@ int64_t parse_date(const char *datestr, int duration) /* Now we have all the fields that we can get */ if (!q) { - if (duration) - return 0; - else - return now * INT64_C(1000000); + return INT64_MIN; } if (duration) { @@ -2576,6 +2792,7 @@ int64_t parse_date(const char *datestr, int duration) t *= 1000000; + /* parse the .m... part */ if (*q == '.') { int val, n; q++; @@ -2588,7 +2805,6 @@ int64_t parse_date(const char *datestr, int duration) } return negative ? -t : t; } -#endif /* CONFIG_WINCE */ int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info) { @@ -2735,7 +2951,7 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt, int PRINT("N/A"); else PRINT("%0.3f", (double)pkt->dts / AV_TIME_BASE); - /* PTS may be not known if B frames are present */ + /* PTS may not be known if B-frames are present. */ PRINT(" pts="); if (pkt->pts == AV_NOPTS_VALUE) PRINT("N/A"); @@ -2765,68 +2981,58 @@ void url_split(char *proto, int proto_size, char *path, int path_size, const char *url) { - const char *p; - char *q; - int port; + const char *p, *ls, *at, *col, *brk; - port = -1; + if (port_ptr) *port_ptr = -1; + if (proto_size > 0) proto[0] = 0; + if (authorization_size > 0) authorization[0] = 0; + if (hostname_size > 0) hostname[0] = 0; + if (path_size > 0) path[0] = 0; - p = url; - q = proto; - while (*p != ':' && *p != '\0') { - if ((q - proto) < proto_size - 1) - *q++ = *p; - p++; - } - if (proto_size > 0) - *q = '\0'; - if (authorization_size > 0) - authorization[0] = '\0'; - if (*p == '\0') { - if (proto_size > 0) - proto[0] = '\0'; - if (hostname_size > 0) - hostname[0] = '\0'; - p = url; + /* parse protocol */ + if ((p = strchr(url, ':'))) { + av_strlcpy(proto, url, FFMIN(proto_size, p + 1 - url)); + p++; /* skip ':' */ + if (*p == '/') p++; + if (*p == '/') p++; } else { - char *at,*slash; // PETR: position of '@' character and '/' character + /* no protocol means plain filename */ + av_strlcpy(path, url, path_size); + return; + } - p++; - if (*p == '/') - p++; - if (*p == '/') - p++; - at = strchr(p,'@'); // PETR: get the position of '@' - slash = strchr(p,'/'); // PETR: get position of '/' - end of hostname - if (at && slash && at > slash) at = NULL; // PETR: not interested in '@' behind '/' - - q = at ? authorization : hostname; // PETR: if '@' exists starting with auth. - - while ((at || *p != ':') && *p != '/' && *p != '?' && *p != '\0') { // PETR: - if (*p == '@') { // PETR: passed '@' - if (authorization_size > 0) - *q = '\0'; - q = hostname; - at = NULL; - } else if (!at) { // PETR: hostname - if ((q - hostname) < hostname_size - 1) - *q++ = *p; - } else { - if ((q - authorization) < authorization_size - 1) - *q++ = *p; - } - p++; - } - if (hostname_size > 0) - *q = '\0'; - if (*p == ':') { - p++; - port = strtoul(p, (char **)&p, 10); + /* separate path from hostname */ + ls = strchr(p, '/'); + if(!ls) + ls = strchr(p, '?'); + if(ls) + av_strlcpy(path, ls, path_size); + else + ls = &p[strlen(p)]; // XXX + + /* the rest is hostname, use that to parse auth/port */ + if (ls != p) { + /* authorization (user[:pass]@hostname) */ + if ((at = strchr(p, '@')) && at < ls) { + av_strlcpy(authorization, p, + FFMIN(authorization_size, at + 1 - p)); + p = at + 1; /* skip '@' */ } + + if (*p == '[' && (brk = strchr(p, ']')) && brk < ls) { + /* [host]:port */ + av_strlcpy(hostname, p + 1, + FFMIN(hostname_size, brk - p)); + if (brk[1] == ':' && port_ptr) + *port_ptr = atoi(brk + 2); + } else if ((col = strchr(p, ':')) && col < ls) { + av_strlcpy(hostname, p, + FFMIN(col + 1 - p, hostname_size)); + if (port_ptr) *port_ptr = atoi(col + 1); + } else + av_strlcpy(hostname, p, + FFMIN(ls + 1 - p, hostname_size)); } - if (port_ptr) - *port_ptr = port; - pstrcpy(path, path_size, p); } void av_set_pts_info(AVStream *s, int pts_wrap_bits, @@ -2862,7 +3068,7 @@ static void av_frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den) } /** - * Fractionnal addition to f: f = f + (incr / f->den). + * Fractional addition to f: f = f + (incr / f->den). * * @param f fractional number * @param incr increment, can be positive or negative diff --git a/contrib/ffmpeg/libavformat/v4l2.c b/contrib/ffmpeg/libavformat/v4l2.c deleted file mode 100644 index aeaac3347..000000000 --- a/contrib/ffmpeg/libavformat/v4l2.c +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Video4Linux2 grab interface - * Copyright (c) 2000,2001 Fabrice Bellard. - * Copyright (c) 2006 Luca Abeni. - * - * Part of this file is based on the V4L2 video capture example - * (http://v4l2spec.bytesex.org/v4l2spec/capture.c) - * - * Thanks to Michael Niedermayer for providing the mapping between - * V4L2_PIX_FMT_* and PIX_FMT_* - * - * - * 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 <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#include <asm/types.h> -#include <linux/videodev2.h> -#include <time.h> - -static const int desired_video_buffers = 256; - -enum io_method { - io_read, - io_mmap, - io_userptr -}; - -struct video_data { - int fd; - int frame_format; /* V4L2_PIX_FMT_* */ - enum io_method io_method; - int width, height; - int frame_rate; - int frame_rate_base; - int frame_size; - int top_field_first; - - int buffers; - void **buf_start; - unsigned int *buf_len; -}; - -struct buff_data { - int index; - int fd; -}; - -struct fmt_map { - enum PixelFormat ff_fmt; - int32_t v4l2_fmt; -}; - -static struct fmt_map fmt_conversion_table[] = { - { - .ff_fmt = PIX_FMT_YUV420P, - .v4l2_fmt = V4L2_PIX_FMT_YUV420, - }, - { - .ff_fmt = PIX_FMT_YUV422P, - .v4l2_fmt = V4L2_PIX_FMT_YUV422P, - }, - { - .ff_fmt = PIX_FMT_YUYV422, - .v4l2_fmt = V4L2_PIX_FMT_YUYV, - }, - { - .ff_fmt = PIX_FMT_UYVY422, - .v4l2_fmt = V4L2_PIX_FMT_UYVY, - }, - { - .ff_fmt = PIX_FMT_YUV411P, - .v4l2_fmt = V4L2_PIX_FMT_YUV411P, - }, - { - .ff_fmt = PIX_FMT_YUV410P, - .v4l2_fmt = V4L2_PIX_FMT_YUV410, - }, - { - .ff_fmt = PIX_FMT_BGR24, - .v4l2_fmt = V4L2_PIX_FMT_BGR24, - }, - { - .ff_fmt = PIX_FMT_RGB24, - .v4l2_fmt = V4L2_PIX_FMT_RGB24, - }, - /* - { - .ff_fmt = PIX_FMT_RGB32, - .v4l2_fmt = V4L2_PIX_FMT_BGR32, - }, - */ - { - .ff_fmt = PIX_FMT_GRAY8, - .v4l2_fmt = V4L2_PIX_FMT_GREY, - }, -}; - -static int device_open(AVFormatContext *ctx, uint32_t *capabilities) -{ - struct v4l2_capability cap; - int fd; - int res; - - fd = open(ctx->filename, O_RDWR /*| O_NONBLOCK*/, 0); - if (fd < 0) { - av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s : %s\n", - ctx->filename, strerror(errno)); - - return -1; - } - - res = ioctl(fd, VIDIOC_QUERYCAP, &cap); - // ENOIOCTLCMD definition only availble on __KERNEL__ - if (res < 0 && errno == 515) - { - av_log(ctx, AV_LOG_ERROR, "QUERYCAP not implemented, probably V4L device but not supporting V4L2\n"); - close(fd); - - return -1; - } - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n", - strerror(errno)); - close(fd); - - return -1; - } - if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { - av_log(ctx, AV_LOG_ERROR, "Not a video capture device\n"); - close(fd); - - return -1; - } - *capabilities = cap.capabilities; - - return fd; -} - -static int device_init(AVFormatContext *ctx, int *width, int *height, int pix_fmt) -{ - struct video_data *s = ctx->priv_data; - int fd = s->fd; - struct v4l2_format fmt; - int res; - - memset(&fmt, 0, sizeof(struct v4l2_format)); - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = *width; - fmt.fmt.pix.height = *height; - fmt.fmt.pix.pixelformat = pix_fmt; - fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - res = ioctl(fd, VIDIOC_S_FMT, &fmt); - if ((*width != fmt.fmt.pix.width) || (*height != fmt.fmt.pix.height)) { - av_log(ctx, AV_LOG_INFO, "The V4L2 driver changed the video from %dx%d to %dx%d\n", *width, *height, fmt.fmt.pix.width, fmt.fmt.pix.height); - *width = fmt.fmt.pix.width; - *height = fmt.fmt.pix.height; - } - - return res; -} - -static int first_field(int fd) -{ - int res; - v4l2_std_id std; - - res = ioctl(fd, VIDIOC_G_STD, &std); - if (res < 0) { - return 0; - } - if (std & V4L2_STD_NTSC) { - return 0; - } - - return 1; -} - -static uint32_t fmt_ff2v4l(enum PixelFormat pix_fmt) -{ - int i; - - for (i = 0; i < sizeof(fmt_conversion_table) / sizeof(struct fmt_map); i++) { - if (fmt_conversion_table[i].ff_fmt == pix_fmt) { - return fmt_conversion_table[i].v4l2_fmt; - } - } - - return 0; -} - -static enum PixelFormat fmt_v4l2ff(uint32_t pix_fmt) -{ - int i; - - for (i = 0; i < sizeof(fmt_conversion_table) / sizeof(struct fmt_map); i++) { - if (fmt_conversion_table[i].v4l2_fmt == pix_fmt) { - return fmt_conversion_table[i].ff_fmt; - } - } - - return -1; -} - -static int mmap_init(AVFormatContext *ctx) -{ - struct video_data *s = ctx->priv_data; - struct v4l2_requestbuffers req; - int i, res; - - memset(&req, 0, sizeof(struct v4l2_requestbuffers)); - req.count = desired_video_buffers; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_MMAP; - res = ioctl (s->fd, VIDIOC_REQBUFS, &req); - if (res < 0) { - if (errno == EINVAL) { - av_log(ctx, AV_LOG_ERROR, "Device does not support mmap\n"); - } else { - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_REQBUFS)\n"); - } - - return -1; - } - - if (req.count < 2) { - av_log(ctx, AV_LOG_ERROR, "Insufficient buffer memory\n"); - - return -1; - } - s->buffers = req.count; - s->buf_start = av_malloc(sizeof(void *) * s->buffers); - if (s->buf_start == NULL) { - av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n"); - - return -1; - } - s->buf_len = av_malloc(sizeof(unsigned int) * s->buffers); - if (s->buf_len == NULL) { - av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n"); - av_free(s->buf_start); - - return -1; - } - - for (i = 0; i < req.count; i++) { - struct v4l2_buffer buf; - - memset(&buf, 0, sizeof(struct v4l2_buffer)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = i; - res = ioctl (s->fd, VIDIOC_QUERYBUF, &buf); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF)\n"); - - return -1; - } - - s->buf_len[i] = buf.length; - if (s->buf_len[i] < s->frame_size) { - av_log(ctx, AV_LOG_ERROR, "Buffer len [%d] = %d != %d\n", i, s->buf_len[i], s->frame_size); - - return -1; - } - s->buf_start[i] = mmap (NULL, buf.length, - PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, buf.m.offset); - if (s->buf_start[i] == MAP_FAILED) { - av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", strerror(errno)); - - return -1; - } - } - - return 0; -} - -static int read_init(AVFormatContext *ctx) -{ - return -1; -} - -static void mmap_release_buffer(AVPacket *pkt) -{ - struct v4l2_buffer buf; - int res, fd; - struct buff_data *buf_descriptor = pkt->priv; - - memset(&buf, 0, sizeof(struct v4l2_buffer)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = buf_descriptor->index; - fd = buf_descriptor->fd; - av_free(buf_descriptor); - - res = ioctl (fd, VIDIOC_QBUF, &buf); - if (res < 0) { - av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n"); - } - pkt->data = NULL; - pkt->size = 0; -} - -static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) -{ - struct video_data *s = ctx->priv_data; - struct v4l2_buffer buf; - struct buff_data *buf_descriptor; - int res; - - memset(&buf, 0, sizeof(struct v4l2_buffer)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - - /* FIXME: Some special treatment might be needed in case of loss of signal... */ - while ((res = ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && - ((errno == EAGAIN) || (errno == EINTR))); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n", strerror(errno)); - - return -1; - } - assert (buf.index < s->buffers); - if (buf.bytesused != s->frame_size) { - av_log(ctx, AV_LOG_ERROR, "The v4l2 frame is %d bytes, but %d bytes are expected\n", buf.bytesused, s->frame_size); - - return -1; - } - - /* Image is at s->buff_start[buf.index] */ - pkt->data= s->buf_start[buf.index]; - pkt->size = buf.bytesused; - pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec; - pkt->destruct = mmap_release_buffer; - buf_descriptor = av_malloc(sizeof(struct buff_data)); - if (buf_descriptor == NULL) { - /* Something went wrong... Since av_malloc() failed, we cannot even - * allocate a buffer for memcopying into it - */ - av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n"); - res = ioctl (s->fd, VIDIOC_QBUF, &buf); - - return -1; - } - buf_descriptor->fd = s->fd; - buf_descriptor->index = buf.index; - pkt->priv = buf_descriptor; - - return s->buf_len[buf.index]; -} - -static int read_frame(AVFormatContext *ctx, AVPacket *pkt) -{ - return -1; -} - -static int mmap_start(AVFormatContext *ctx) -{ - struct video_data *s = ctx->priv_data; - enum v4l2_buf_type type; - int i, res; - - for (i = 0; i < s->buffers; i++) { - struct v4l2_buffer buf; - - memset(&buf, 0, sizeof(struct v4l2_buffer)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = i; - - res = ioctl (s->fd, VIDIOC_QBUF, &buf); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", strerror(errno)); - - return -1; - } - } - - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - res = ioctl (s->fd, VIDIOC_STREAMON, &type); - if (res < 0) { - av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", strerror(errno)); - - return -1; - } - - return 0; -} - -static void mmap_close(struct video_data *s) -{ - enum v4l2_buf_type type; - int i; - - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - /* We do not check for the result, because we could - * not do anything about it anyway... - */ - ioctl(s->fd, VIDIOC_STREAMOFF, &type); - for (i = 0; i < s->buffers; i++) { - munmap(s->buf_start[i], s->buf_len[i]); - } - av_free(s->buf_start); - av_free(s->buf_len); -} - -static int v4l2_set_parameters( AVFormatContext *s1, AVFormatParameters *ap ) -{ - struct video_data *s = s1->priv_data; - struct v4l2_input input; - struct v4l2_standard standard; - int i; - - /* set tv video input */ - memset (&input, 0, sizeof (input)); - input.index = ap->channel; - if(ioctl (s->fd, VIDIOC_ENUMINPUT, &input) < 0) { - av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl enum input failed:\n"); - return AVERROR_IO; - } - - av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set input_id: %d, input: %s\n", - ap->channel, input.name); - if(ioctl (s->fd, VIDIOC_S_INPUT, &input.index) < 0 ) { - av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl set input(%d) failed\n", - ap->channel); - return AVERROR_IO; - } - - av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set standard: %s\n", - ap->standard ); - /* set tv standard */ - memset (&standard, 0, sizeof (standard)); - for(i=0;;i++) { - standard.index = i; - if (ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) { - av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl set standard(%s) failed\n", - ap->standard); - return AVERROR_IO; - } - - if(!strcasecmp(standard.name, ap->standard)) { - break; - } - } - - av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set standard: %s, id: %"PRIu64"\n", - ap->standard, standard.id); - if (ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) { - av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl set standard(%s) failed\n", - ap->standard); - return AVERROR_IO; - } - - return 0; -} - -static int v4l2_read_header(AVFormatContext *s1, AVFormatParameters *ap) -{ - struct video_data *s = s1->priv_data; - AVStream *st; - int width, height; - int res, frame_rate, frame_rate_base; - uint32_t desired_format, capabilities; - - if (ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) { - av_log(s1, AV_LOG_ERROR, "Missing/Wrong parameters\n"); - - return -1; - } - - width = ap->width; - height = ap->height; - frame_rate = ap->time_base.den; - frame_rate_base = ap->time_base.num; - - if((unsigned)width > 32767 || (unsigned)height > 32767) { - av_log(s1, AV_LOG_ERROR, "Wrong size %dx%d\n", width, height); - - return -1; - } - - st = av_new_stream(s1, 0); - if (!st) { - return AVERROR(ENOMEM); - } - av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ - - s->width = width; - s->height = height; - s->frame_rate = frame_rate; - s->frame_rate_base = frame_rate_base; - - capabilities = 0; - s->fd = device_open(s1, &capabilities); - if (s->fd < 0) { - av_free(st); - - return AVERROR_IO; - } - av_log(s1, AV_LOG_INFO, "[%d]Capabilities: %x\n", s->fd, capabilities); - - desired_format = fmt_ff2v4l(ap->pix_fmt); - if (desired_format == 0 || (device_init(s1, &width, &height, desired_format) < 0)) { - int i, done; - - done = 0; i = 0; - while (!done) { - desired_format = fmt_conversion_table[i].v4l2_fmt; - if (device_init(s1, &width, &height, desired_format) < 0) { - desired_format = 0; - i++; - } else { - done = 1; - } - if (i == sizeof(fmt_conversion_table) / sizeof(struct fmt_map)) { - done = 1; - } - } - } - if (desired_format == 0) { - av_log(s1, AV_LOG_ERROR, "Cannot find a proper format.\n"); - close(s->fd); - av_free(st); - - return AVERROR_IO; - } - s->frame_format = desired_format; - - if( v4l2_set_parameters( s1, ap ) < 0 ) - return AVERROR_IO; - - st->codec->pix_fmt = fmt_v4l2ff(desired_format); - s->frame_size = avpicture_get_size(st->codec->pix_fmt, width, height); - if (capabilities & V4L2_CAP_STREAMING) { - s->io_method = io_mmap; - res = mmap_init(s1); - if (res == 0) { - res = mmap_start(s1); - } - } else { - s->io_method = io_read; - res = read_init(s1); - } - if (res < 0) { - close(s->fd); - av_free(st); - - return AVERROR_IO; - } - s->top_field_first = first_field(s->fd); - - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = CODEC_ID_RAWVIDEO; - st->codec->width = width; - st->codec->height = height; - st->codec->time_base.den = frame_rate; - st->codec->time_base.num = frame_rate_base; - st->codec->bit_rate = s->frame_size * 1/av_q2d(st->codec->time_base) * 8; - - return 0; -} - -static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - struct video_data *s = s1->priv_data; - int res; - - if (s->io_method == io_mmap) { - av_init_packet(pkt); - res = mmap_read_frame(s1, pkt); - } else if (s->io_method == io_read) { - if (av_new_packet(pkt, s->frame_size) < 0) - return AVERROR_IO; - - res = read_frame(s1, pkt); - } else { - return AVERROR_IO; - } - if (res < 0) { - return AVERROR_IO; - } - - if (s1->streams[0]->codec->coded_frame) { - s1->streams[0]->codec->coded_frame->interlaced_frame = 1; - s1->streams[0]->codec->coded_frame->top_field_first = s->top_field_first; - } - - return s->frame_size; -} - -static int v4l2_read_close(AVFormatContext *s1) -{ - struct video_data *s = s1->priv_data; - - if (s->io_method == io_mmap) { - mmap_close(s); - } - - close(s->fd); - return 0; -} - -AVInputFormat v4l2_demuxer = { - "video4linux2", - "video grab", - sizeof(struct video_data), - NULL, - v4l2_read_header, - v4l2_read_packet, - v4l2_read_close, - .flags = AVFMT_NOFILE, -}; diff --git a/contrib/ffmpeg/libavformat/vc1test.c b/contrib/ffmpeg/libavformat/vc1test.c new file mode 100644 index 000000000..c8340179c --- /dev/null +++ b/contrib/ffmpeg/libavformat/vc1test.c @@ -0,0 +1,112 @@ +/* + * VC1 Test Bitstreams Format Demuxer + * Copyright (c) 2006, 2008 Konstantin Shishkov + * + * 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 vc1test.c + * VC1 test bitstream file demuxer + * by Konstantin Shishkov + * Format specified in SMPTE standard 421 Annex L + */ + +#include "avformat.h" + +#define VC1_EXTRADATA_SIZE 4 + +static int vc1t_probe(AVProbeData *p) +{ + if (p->buf[3] != 0xC5 && AV_RL32(&p->buf[4]) != 4) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int vc1t_read_header(AVFormatContext *s, + AVFormatParameters *ap) +{ + ByteIOContext *pb = s->pb; + AVStream *st; + int fps, frames; + + frames = get_le24(pb); + if(get_byte(pb) != 0xC5 || get_le32(pb) != 4) + return -1; + + /* init video codec */ + st = av_new_stream(s, 0); + if (!st) + return -1; + + st->codec->codec_type = CODEC_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_WMV3; + + st->codec->extradata = av_malloc(VC1_EXTRADATA_SIZE); + st->codec->extradata_size = VC1_EXTRADATA_SIZE; + get_buffer(pb, st->codec->extradata, VC1_EXTRADATA_SIZE); + st->codec->height = get_le32(pb); + st->codec->width = get_le32(pb); + if(get_le32(pb) != 0xC) + return -1; + url_fskip(pb, 8); + fps = get_le32(pb); + if(fps == -1) + av_set_pts_info(st, 32, 1, 1000); + else{ + av_set_pts_info(st, 24, 1, fps); + st->duration = frames; + } + + return 0; +} + +static int vc1t_read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + ByteIOContext *pb = s->pb; + int frame_size; + int keyframe = 0; + uint32_t pts; + + if(url_feof(pb)) + return AVERROR(EIO); + + frame_size = get_le24(pb); + if(get_byte(pb) & 0x80) + keyframe = 1; + pts = get_le32(pb); + if(av_get_packet(pb, pkt, frame_size) < 0) + return AVERROR(EIO); + if(s->streams[0]->time_base.den == 1000) + pkt->pts = pts; + pkt->flags |= keyframe ? PKT_FLAG_KEY : 0; + pkt->pos -= 8; + + return pkt->size; +} + +AVInputFormat vc1t_demuxer = { + "vc1test", + "VC1 test bitstream format", + 0, + vc1t_probe, + vc1t_read_header, + vc1t_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/contrib/ffmpeg/libavformat/voc.c b/contrib/ffmpeg/libavformat/voc.c index 97b73d163..750f78d15 100644 --- a/contrib/ffmpeg/libavformat/voc.c +++ b/contrib/ffmpeg/libavformat/voc.c @@ -16,7 +16,7 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "voc.h" diff --git a/contrib/ffmpeg/libavformat/voc.h b/contrib/ffmpeg/libavformat/voc.h index 9b2bb8cce..606f2152e 100644 --- a/contrib/ffmpeg/libavformat/voc.h +++ b/contrib/ffmpeg/libavformat/voc.h @@ -16,11 +16,11 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef VOC_H -#define VOC_H +#ifndef FFMPEG_VOC_H +#define FFMPEG_VOC_H #include "avformat.h" #include "riff.h" /* for CodecTag */ @@ -48,4 +48,4 @@ extern const AVCodecTag voc_codec_tags[]; int voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size); -#endif +#endif /* FFMPEG_VOC_H */ diff --git a/contrib/ffmpeg/libavformat/vocdec.c b/contrib/ffmpeg/libavformat/vocdec.c index 85d304dff..7c50fa588 100644 --- a/contrib/ffmpeg/libavformat/vocdec.c +++ b/contrib/ffmpeg/libavformat/vocdec.c @@ -16,24 +16,20 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "voc.h" - - static int voc_probe(AVProbeData *p) { int version, check; - if (p->buf_size < 26) - return 0; if (memcmp(p->buf, voc_magic, sizeof(voc_magic) - 1)) return 0; - version = p->buf[22] | (p->buf[23] << 8); - check = p->buf[24] | (p->buf[25] << 8); + version = AV_RL16(p->buf + 22); + check = AV_RL16(p->buf + 24); if (~version + 0x1234 != check) return 10; @@ -43,7 +39,7 @@ static int voc_probe(AVProbeData *p) static int voc_read_header(AVFormatContext *s, AVFormatParameters *ap) { voc_dec_context_t *voc = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int header_size; AVStream *st; @@ -51,12 +47,12 @@ static int voc_read_header(AVFormatContext *s, AVFormatParameters *ap) header_size = get_le16(pb) - 22; if (header_size != 4) { av_log(s, AV_LOG_ERROR, "unknown header size: %d\n", header_size); - return AVERROR_NOTSUPP; + return AVERROR(ENOSYS); } url_fskip(pb, header_size); st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); st->codec->codec_type = CODEC_TYPE_AUDIO; voc->remaining_size = 0; @@ -68,7 +64,7 @@ voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) { voc_dec_context_t *voc = s->priv_data; AVCodecContext *dec = st->codec; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; voc_type_t type; int size; int sample_rate = 0; @@ -77,7 +73,7 @@ voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) while (!voc->remaining_size) { type = get_byte(pb); if (type == VOC_TYPE_EOF) - return AVERROR_IO; + return AVERROR(EIO); voc->remaining_size = get_le24(pb); max_size -= 4; @@ -138,11 +134,6 @@ static int voc_read_packet(AVFormatContext *s, AVPacket *pkt) return voc_get_packet(s, pkt, s->streams[0], 0); } -static int voc_read_close(AVFormatContext *s) -{ - return 0; -} - AVInputFormat voc_demuxer = { "voc", "Creative Voice File format", @@ -150,6 +141,5 @@ AVInputFormat voc_demuxer = { voc_probe, voc_read_header, voc_read_packet, - voc_read_close, .codec_tag=(const AVCodecTag*[]){voc_codec_tags, 0}, }; diff --git a/contrib/ffmpeg/libavformat/vocenc.c b/contrib/ffmpeg/libavformat/vocenc.c index 6a07c92dd..d967fae09 100644 --- a/contrib/ffmpeg/libavformat/vocenc.c +++ b/contrib/ffmpeg/libavformat/vocenc.c @@ -16,7 +16,7 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "voc.h" @@ -28,13 +28,13 @@ typedef struct voc_enc_context { static int voc_write_header(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; const int header_size = 26; const int version = 0x0114; if (s->nb_streams != 1 || s->streams[0]->codec->codec_type != CODEC_TYPE_AUDIO) - return AVERROR_NOTSUPP; + return AVERROR_PATCHWELCOME; put_buffer(pb, voc_magic, sizeof(voc_magic) - 1); put_le16(pb, header_size); @@ -48,7 +48,7 @@ static int voc_write_packet(AVFormatContext *s, AVPacket *pkt) { voc_enc_context_t *voc = s->priv_data; AVCodecContext *enc = s->streams[0]->codec; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; if (!voc->param_written) { if (enc->codec_tag > 0xFF) { @@ -84,7 +84,7 @@ static int voc_write_packet(AVFormatContext *s, AVPacket *pkt) static int voc_write_trailer(AVFormatContext *s) { - put_byte(&s->pb, 0); + put_byte(s->pb, 0); return 0; } diff --git a/contrib/ffmpeg/libavformat/wav.c b/contrib/ffmpeg/libavformat/wav.c index 0699bec70..5053d1500 100644 --- a/contrib/ffmpeg/libavformat/wav.c +++ b/contrib/ffmpeg/libavformat/wav.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "avformat.h" -#include "allformats.h" +#include "raw.h" #include "riff.h" typedef struct { @@ -34,7 +34,7 @@ typedef struct { static int wav_write_header(AVFormatContext *s) { WAVContext *wav = s->priv_data; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; offset_t fmt, fact; put_tag(pb, "RIFF"); @@ -50,7 +50,7 @@ static int wav_write_header(AVFormatContext *s) end_tag(pb, fmt); if(s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ - && !url_is_streamed(&s->pb)) { + && !url_is_streamed(s->pb)) { fact = start_tag(pb, "fact"); put_le32(pb, 0); end_tag(pb, fact); @@ -70,7 +70,7 @@ static int wav_write_header(AVFormatContext *s) static int wav_write_packet(AVFormatContext *s, AVPacket *pkt) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; WAVContext *wav = s->priv_data; put_buffer(pb, pkt->data, pkt->size); if(pkt->pts != AV_NOPTS_VALUE) { @@ -84,11 +84,11 @@ static int wav_write_packet(AVFormatContext *s, AVPacket *pkt) static int wav_write_trailer(AVFormatContext *s) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; WAVContext *wav = s->priv_data; offset_t file_size; - if (!url_is_streamed(&s->pb)) { + if (!url_is_streamed(s->pb)) { end_tag(pb, wav->data); /* update file size */ @@ -156,7 +156,7 @@ static int wav_read_header(AVFormatContext *s, { int size; unsigned int tag; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVStream *st; WAVContext *wav = s->priv_data; @@ -176,10 +176,10 @@ static int wav_read_header(AVFormatContext *s, return -1; st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); get_wav_header(pb, st->codec, size); - st->need_parsing = 1; + st->need_parsing = AVSTREAM_PARSE_FULL; av_set_pts_info(st, 64, 1, st->codec->sample_rate); @@ -199,17 +199,17 @@ static int wav_read_packet(AVFormatContext *s, AVStream *st; WAVContext *wav = s->priv_data; - if (url_feof(&s->pb)) - return AVERROR_IO; + if (url_feof(s->pb)) + return AVERROR(EIO); st = s->streams[0]; - left= wav->data_end - url_ftell(&s->pb); + left= wav->data_end - url_ftell(s->pb); if(left <= 0){ - left = find_tag(&(s->pb), MKTAG('d', 'a', 't', 'a')); + left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a')); if (left < 0) { - return AVERROR_IO; + return AVERROR(EIO); } - wav->data_end= url_ftell(&s->pb) + left; + wav->data_end= url_ftell(s->pb) + left; } size = MAX_SIZE; @@ -219,9 +219,9 @@ static int wav_read_packet(AVFormatContext *s, size = (size / st->codec->block_align) * st->codec->block_align; } size= FFMIN(size, left); - ret= av_get_packet(&s->pb, pkt, size); + ret= av_get_packet(s->pb, pkt, size); if (ret <= 0) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = 0; /* note: we need to modify the packet size here to handle the last diff --git a/contrib/ffmpeg/libavformat/wc3movie.c b/contrib/ffmpeg/libavformat/wc3movie.c index 3e58a1bba..00efb02ca 100644 --- a/contrib/ffmpeg/libavformat/wc3movie.c +++ b/contrib/ffmpeg/libavformat/wc3movie.c @@ -33,7 +33,7 @@ #define FORM_TAG MKTAG('F', 'O', 'R', 'M') #define MOVE_TAG MKTAG('M', 'O', 'V', 'E') -#define _PC__TAG MKTAG('_', 'P', 'C', '_') +#define PC__TAG MKTAG('_', 'P', 'C', '_') #define SOND_TAG MKTAG('S', 'O', 'N', 'D') #define BNAM_TAG MKTAG('B', 'N', 'A', 'M') #define SIZE_TAG MKTAG('S', 'I', 'Z', 'E') @@ -125,8 +125,8 @@ static int wc3_probe(AVProbeData *p) static int wc3_read_header(AVFormatContext *s, AVFormatParameters *ap) { - Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + Wc3DemuxContext *wc3 = s->priv_data; + ByteIOContext *pb = s->pb; unsigned int fourcc_tag; unsigned int size; AVStream *st; @@ -152,7 +152,7 @@ static int wc3_read_header(AVFormatContext *s, * the first BRCH tag */ if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) != WC3_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); fourcc_tag = AV_RL32(&preamble[0]); size = (AV_RB32(&preamble[4]) + 1) & (~1); @@ -165,11 +165,11 @@ static int wc3_read_header(AVFormatContext *s, url_fseek(pb, size, SEEK_CUR); break; - case _PC__TAG: + case PC__TAG: /* need the number of palettes */ url_fseek(pb, 8, SEEK_CUR); if ((ret = get_buffer(pb, preamble, 4)) != 4) - return AVERROR_IO; + return AVERROR(EIO); wc3->palette_count = AV_RL32(&preamble[0]); if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE){ wc3->palette_count= 0; @@ -185,14 +185,14 @@ static int wc3_read_header(AVFormatContext *s, else bytes_to_read = 512; if ((ret = get_buffer(pb, s->title, bytes_to_read)) != bytes_to_read) - return AVERROR_IO; + return AVERROR(EIO); break; case SIZE_TAG: /* video resolution override */ if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) != WC3_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); wc3->width = AV_RL32(&preamble[0]); wc3->height = AV_RL32(&preamble[4]); break; @@ -204,7 +204,7 @@ static int wc3_read_header(AVFormatContext *s, if ((ret = get_buffer(pb, &wc3->palettes[current_palette * PALETTE_SIZE], PALETTE_SIZE)) != PALETTE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); /* transform the current palette in place */ for (i = current_palette * PALETTE_SIZE; @@ -228,7 +228,7 @@ static int wc3_read_header(AVFormatContext *s, if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) != WC3_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); fourcc_tag = AV_RL32(&preamble[0]); /* chunk sizes are 16-bit aligned */ size = (AV_RB32(&preamble[4]) + 1) & (~1); @@ -238,7 +238,7 @@ static int wc3_read_header(AVFormatContext *s, /* initialize the decoder streams */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, 90000); wc3->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; @@ -252,7 +252,7 @@ static int wc3_read_header(AVFormatContext *s, st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, 90000); wc3->audio_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_AUDIO; @@ -271,8 +271,8 @@ static int wc3_read_header(AVFormatContext *s, static int wc3_read_packet(AVFormatContext *s, AVPacket *pkt) { - Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + Wc3DemuxContext *wc3 = s->priv_data; + ByteIOContext *pb = s->pb; unsigned int fourcc_tag; unsigned int size; int packet_read = 0; @@ -289,7 +289,7 @@ static int wc3_read_packet(AVFormatContext *s, /* get the next chunk preamble */ if ((ret = get_buffer(pb, preamble, WC3_PREAMBLE_SIZE)) != WC3_PREAMBLE_SIZE) - ret = AVERROR_IO; + ret = AVERROR(EIO); fourcc_tag = AV_RL32(&preamble[0]); /* chunk sizes are 16-bit aligned */ @@ -304,7 +304,7 @@ static int wc3_read_packet(AVFormatContext *s, case SHOT_TAG: /* load up new palette */ if ((ret = get_buffer(pb, preamble, 4)) != 4) - return AVERROR_IO; + return AVERROR(EIO); palette_number = AV_RL32(&preamble[0]); if (palette_number >= wc3->palette_count) return AVERROR_INVALIDDATA; @@ -324,7 +324,7 @@ static int wc3_read_packet(AVFormatContext *s, pkt->stream_index = wc3->video_stream_index; pkt->pts = wc3->pts; if (ret != size) - ret = AVERROR_IO; + ret = AVERROR(EIO); packet_read = 1; break; @@ -334,7 +334,7 @@ static int wc3_read_packet(AVFormatContext *s, url_fseek(pb, size, SEEK_CUR); #else if ((unsigned)size > sizeof(text) || (ret = get_buffer(pb, text, size)) != size) - ret = AVERROR_IO; + ret = AVERROR(EIO); else { int i = 0; av_log (s, AV_LOG_DEBUG, "Subtitle time!\n"); @@ -353,7 +353,7 @@ static int wc3_read_packet(AVFormatContext *s, pkt->stream_index = wc3->audio_stream_index; pkt->pts = wc3->pts; if (ret != size) - ret = AVERROR_IO; + ret = AVERROR(EIO); /* time to advance pts */ wc3->pts += WC3_FRAME_PTS_INC; @@ -376,7 +376,7 @@ static int wc3_read_packet(AVFormatContext *s, static int wc3_read_close(AVFormatContext *s) { - Wc3DemuxContext *wc3 = (Wc3DemuxContext *)s->priv_data; + Wc3DemuxContext *wc3 = s->priv_data; av_free(wc3->palettes); diff --git a/contrib/ffmpeg/libavformat/westwood.c b/contrib/ffmpeg/libavformat/westwood.c index bed2f0d14..268f2e71e 100644 --- a/contrib/ffmpeg/libavformat/westwood.c +++ b/contrib/ffmpeg/libavformat/westwood.c @@ -117,13 +117,13 @@ static int wsaud_probe(AVProbeData *p) static int wsaud_read_header(AVFormatContext *s, AVFormatParameters *ap) { - WsAudDemuxContext *wsaud = (WsAudDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + WsAudDemuxContext *wsaud = s->priv_data; + ByteIOContext *pb = s->pb; AVStream *st; unsigned char header[AUD_HEADER_SIZE]; if (get_buffer(pb, header, AUD_HEADER_SIZE) != AUD_HEADER_SIZE) - return AVERROR_IO; + return AVERROR(EIO); wsaud->audio_samplerate = AV_RL16(&header[0]); if (header[11] == 99) wsaud->audio_type = CODEC_ID_ADPCM_IMA_WS; @@ -138,7 +138,7 @@ static int wsaud_read_header(AVFormatContext *s, /* initialize the audio decoder stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, wsaud->audio_samplerate); st->codec->codec_type = CODEC_TYPE_AUDIO; st->codec->codec_id = wsaud->audio_type; @@ -159,15 +159,15 @@ static int wsaud_read_header(AVFormatContext *s, static int wsaud_read_packet(AVFormatContext *s, AVPacket *pkt) { - WsAudDemuxContext *wsaud = (WsAudDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + WsAudDemuxContext *wsaud = s->priv_data; + ByteIOContext *pb = s->pb; unsigned char preamble[AUD_CHUNK_PREAMBLE_SIZE]; unsigned int chunk_size; int ret = 0; if (get_buffer(pb, preamble, AUD_CHUNK_PREAMBLE_SIZE) != AUD_CHUNK_PREAMBLE_SIZE) - return AVERROR_IO; + return AVERROR(EIO); /* validate the chunk */ if (AV_RL32(&preamble[4]) != AUD_CHUNK_SIGNATURE) @@ -176,7 +176,7 @@ static int wsaud_read_packet(AVFormatContext *s, chunk_size = AV_RL16(&preamble[0]); ret= av_get_packet(pb, pkt, chunk_size); if (ret != chunk_size) - return AVERROR_IO; + return AVERROR(EIO); pkt->stream_index = wsaud->audio_stream_index; pkt->pts = wsaud->audio_frame_counter; pkt->pts /= wsaud->audio_samplerate; @@ -189,7 +189,7 @@ static int wsaud_read_packet(AVFormatContext *s, static int wsaud_read_close(AVFormatContext *s) { -// WsAudDemuxContext *wsaud = (WsAudDemuxContext *)s->priv_data; +// WsAudDemuxContext *wsaud = s->priv_data; return 0; } @@ -212,8 +212,8 @@ static int wsvqa_probe(AVProbeData *p) static int wsvqa_read_header(AVFormatContext *s, AVFormatParameters *ap) { - WsVqaDemuxContext *wsvqa = (WsVqaDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + WsVqaDemuxContext *wsvqa = s->priv_data; + ByteIOContext *pb = s->pb; AVStream *st; unsigned char *header; unsigned char scratch[VQA_PREAMBLE_SIZE]; @@ -223,7 +223,7 @@ static int wsvqa_read_header(AVFormatContext *s, /* initialize the video decoder stream */ st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, VQA_FRAMERATE); wsvqa->video_stream_index = st->index; st->codec->codec_type = CODEC_TYPE_VIDEO; @@ -240,7 +240,7 @@ static int wsvqa_read_header(AVFormatContext *s, if (get_buffer(pb, st->codec->extradata, VQA_HEADER_SIZE) != VQA_HEADER_SIZE) { av_free(st->codec->extradata); - return AVERROR_IO; + return AVERROR(EIO); } st->codec->width = AV_RL16(&header[6]); st->codec->height = AV_RL16(&header[8]); @@ -249,7 +249,7 @@ static int wsvqa_read_header(AVFormatContext *s, if (AV_RL16(&header[24]) || (AV_RL16(&header[0]) == 1 && AV_RL16(&header[2]) == 1)) { st = av_new_stream(s, 0); if (!st) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); av_set_pts_info(st, 33, 1, VQA_FRAMERATE); st->codec->codec_type = CODEC_TYPE_AUDIO; if (AV_RL16(&header[0]) == 1) @@ -279,7 +279,7 @@ static int wsvqa_read_header(AVFormatContext *s, do { if (get_buffer(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE) { av_free(st->codec->extradata); - return AVERROR_IO; + return AVERROR(EIO); } chunk_tag = AV_RB32(&scratch[0]); chunk_size = AV_RB32(&scratch[4]); @@ -314,8 +314,8 @@ static int wsvqa_read_header(AVFormatContext *s, static int wsvqa_read_packet(AVFormatContext *s, AVPacket *pkt) { - WsVqaDemuxContext *wsvqa = (WsVqaDemuxContext *)s->priv_data; - ByteIOContext *pb = &s->pb; + WsVqaDemuxContext *wsvqa = s->priv_data; + ByteIOContext *pb = s->pb; int ret = -1; unsigned char preamble[VQA_PREAMBLE_SIZE]; unsigned int chunk_type; @@ -330,11 +330,11 @@ 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)) - return AVERROR_IO; + return AVERROR(EIO); ret = get_buffer(pb, pkt->data, chunk_size); if (ret != chunk_size) { av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } if (chunk_type == SND2_TAG) { @@ -371,7 +371,7 @@ static int wsvqa_read_packet(AVFormatContext *s, static int wsvqa_read_close(AVFormatContext *s) { -// WsVqaDemuxContext *wsvqa = (WsVqaDemuxContext *)s->priv_data; +// WsVqaDemuxContext *wsvqa = s->priv_data; return 0; } diff --git a/contrib/ffmpeg/libavformat/wv.c b/contrib/ffmpeg/libavformat/wv.c index ed1eefeea..2240dfde2 100644 --- a/contrib/ffmpeg/libavformat/wv.c +++ b/contrib/ffmpeg/libavformat/wv.c @@ -20,7 +20,6 @@ */ #include "avformat.h" -#include "allformats.h" #include "bswap.h" // specs say that maximum block size is 1Mb @@ -86,7 +85,7 @@ static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb) } wc->blksize = size; ver = get_le16(pb); - if(ver < 0x402 || ver > 0x40F){ + if(ver < 0x402 || ver > 0x410){ av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", ver); return -1; } @@ -105,10 +104,6 @@ static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb) av_log(ctx, AV_LOG_ERROR, "Hybrid coding mode is not supported\n"); return -1; } - if(wc->flags & WV_INT32){ - av_log(ctx, AV_LOG_ERROR, "Integer point data is not supported\n"); - return -1; - } bpp = ((wc->flags & 3) + 1) << 3; chan = 1 + !(wc->flags & WV_MONO); @@ -140,7 +135,7 @@ static int wv_read_block_header(AVFormatContext *ctx, ByteIOContext *pb) static int wv_read_header(AVFormatContext *s, AVFormatParameters *ap) { - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; WVContext *wc = s->priv_data; AVStream *st; @@ -169,20 +164,20 @@ static int wv_read_packet(AVFormatContext *s, WVContext *wc = s->priv_data; int ret; - if (url_feof(&s->pb)) + if (url_feof(s->pb)) return AVERROR(EIO); if(wc->block_parsed){ - if(wv_read_block_header(s, &s->pb) < 0) + if(wv_read_block_header(s, s->pb) < 0) return -1; } if(av_new_packet(pkt, wc->blksize + WV_EXTRA_SIZE) < 0) - return AVERROR_NOMEM; + return AVERROR(ENOMEM); memcpy(pkt->data, wc->extra, WV_EXTRA_SIZE); - ret = get_buffer(&s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize); + ret = get_buffer(s->pb, pkt->data + WV_EXTRA_SIZE, wc->blksize); if(ret != wc->blksize){ av_free_packet(pkt); - return AVERROR_IO; + return AVERROR(EIO); } pkt->stream_index = 0; wc->block_parsed = 1; @@ -209,18 +204,18 @@ static int wv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, /* if found, seek there */ if (index >= 0){ wc->block_parsed = 1; - url_fseek(&s->pb, st->index_entries[index].pos, SEEK_SET); + url_fseek(s->pb, st->index_entries[index].pos, SEEK_SET); return 0; } /* if timestamp is out of bounds, return error */ if(timestamp < 0 || timestamp >= s->duration) return -1; - pos = url_ftell(&s->pb); + pos = url_ftell(s->pb); do{ ret = av_read_frame(s, pkt); if (ret < 0){ - url_fseek(&s->pb, pos, SEEK_SET); + url_fseek(s->pb, pos, SEEK_SET); return -1; } pts = pkt->pts; diff --git a/contrib/ffmpeg/libavformat/x11grab.c b/contrib/ffmpeg/libavformat/x11grab.c deleted file mode 100644 index 8916d799a..000000000 --- a/contrib/ffmpeg/libavformat/x11grab.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * X11 video grab interface - * - * This file is part of FFmpeg. - * - * FFmpeg integration: - * Copyright (C) 2006 Clemens Fruhwirth <clemens@endorphin.org> - * Edouard Gomez <ed.gomez@free.fr> - * - * This file contains code from grab.c: - * Copyright (c) 2000-2001 Fabrice Bellard - * - * This file contains code from the xvidcap project: - * Copyright (C) 1997-1998 Rasca, Berlin - * 2003-2004 Karl H. Beckers, Frankfurt - * - * FFmpeg is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU 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 x11grab.c - * X11 frame device demuxer by Clemens Fruhwirth <clemens@endorphin.org> - * and Edouard Gomez <ed.gomez@free.fr>. - */ - -#include "avformat.h" -#include <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> -#define _LINUX_TIME_H 1 -#include <time.h> -#include <X11/X.h> -#include <X11/Xlib.h> -#include <X11/Xlibint.h> -#include <X11/Xproto.h> -#include <X11/Xutil.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#include <X11/extensions/XShm.h> - -/** - * X11 Device Demuxer context - */ -typedef struct x11_grab_s -{ - int frame_size; /**< Size in bytes of a grabbed frame */ - AVRational time_base; /**< Time base */ - int64_t time_frame; /**< Current time */ - - int height; /**< Height of the grab frame */ - int width; /**< Width of the grab frame */ - int x_off; /**< Horizontal top-left corner coordinate */ - int y_off; /**< Vertical top-left corner coordinate */ - - Display *dpy; /**< X11 display from which x11grab grabs frames */ - XImage *image; /**< X11 image holding the grab */ - int use_shm; /**< !0 when using XShm extension */ - XShmSegmentInfo shminfo; /**< When using XShm, keeps track of XShm infos */ - int mouse_warning_shown; -} x11_grab_t; - -/** - * Initializes the x11 grab device demuxer (public device demuxer API). - * - * @param s1 Context from avformat core - * @param ap Parameters from avformat core - * @return <ul> - * <li>ENOMEM no memory left</li> - * <li>AVERROR_IO other failure case</li> - * <li>0 success</li> - * </ul> - */ -static int -x11grab_read_header(AVFormatContext *s1, AVFormatParameters *ap) -{ - x11_grab_t *x11grab = s1->priv_data; - Display *dpy; - AVStream *st = NULL; - int input_pixfmt; - XImage *image; - int x_off = 0; - int y_off = 0; - int use_shm; - char *param, *offset; - - param = av_strdup(s1->filename); - offset = strchr(param, '+'); - if (offset) { - sscanf(offset, "%d,%d", &x_off, &y_off); - *offset= 0; - } - - av_log(s1, AV_LOG_INFO, "device: %s -> display: %s x: %d y: %d width: %d height: %d\n", s1->filename, param, x_off, y_off, ap->width, ap->height); - - dpy = XOpenDisplay(param); - if(!dpy) { - av_log(s1, AV_LOG_ERROR, "Could not open X display.\n"); - return AVERROR_IO; - } - - if (!ap || ap->width <= 0 || ap->height <= 0 || ap->time_base.den <= 0) { - av_log(s1, AV_LOG_ERROR, "AVParameters don't have any video size. Use -s.\n"); - return AVERROR_IO; - } - - st = av_new_stream(s1, 0); - if (!st) { - return AVERROR(ENOMEM); - } - av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ - - use_shm = XShmQueryExtension(dpy); - av_log(s1, AV_LOG_INFO, "shared memory extension %s found\n", use_shm ? "" : "not"); - - if(use_shm) { - int scr = XDefaultScreen(dpy); - image = XShmCreateImage(dpy, - DefaultVisual(dpy, scr), - DefaultDepth(dpy, scr), - ZPixmap, - NULL, - &x11grab->shminfo, - ap->width, ap->height); - x11grab->shminfo.shmid = shmget(IPC_PRIVATE, - image->bytes_per_line * image->height, - IPC_CREAT|0777); - if (x11grab->shminfo.shmid == -1) { - av_log(s1, AV_LOG_ERROR, "Fatal: Can't get shared memory!\n"); - return AVERROR(ENOMEM); - } - x11grab->shminfo.shmaddr = image->data = shmat(x11grab->shminfo.shmid, 0, 0); - x11grab->shminfo.readOnly = False; - - if (!XShmAttach(dpy, &x11grab->shminfo)) { - av_log(s1, AV_LOG_ERROR, "Fatal: Failed to attach shared memory!\n"); - /* needs some better error subroutine :) */ - return AVERROR_IO; - } - } else { - image = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)), - x_off,y_off, - ap->width,ap->height, - AllPlanes, ZPixmap); - } - - switch (image->bits_per_pixel) { - case 8: - av_log (s1, AV_LOG_DEBUG, "8 bit palette\n"); - input_pixfmt = PIX_FMT_PAL8; - break; - case 16: - if ( image->red_mask == 0xf800 && - image->green_mask == 0x07e0 && - image->blue_mask == 0x001f ) { - av_log (s1, AV_LOG_DEBUG, "16 bit RGB565\n"); - input_pixfmt = PIX_FMT_RGB565; - } else if (image->red_mask == 0x7c00 && - image->green_mask == 0x03e0 && - image->blue_mask == 0x001f ) { - av_log(s1, AV_LOG_DEBUG, "16 bit RGB555\n"); - input_pixfmt = PIX_FMT_RGB555; - } else { - av_log(s1, AV_LOG_ERROR, "RGB ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel); - av_log(s1, AV_LOG_ERROR, "color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx\n", image->red_mask, image->green_mask, image->blue_mask); - return AVERROR_IO; - } - break; - case 24: - if ( image->red_mask == 0xff0000 && - image->green_mask == 0x00ff00 && - image->blue_mask == 0x0000ff ) { - input_pixfmt = PIX_FMT_BGR24; - } else if ( image->red_mask == 0x0000ff && - image->green_mask == 0x00ff00 && - image->blue_mask == 0xff0000 ) { - input_pixfmt = PIX_FMT_RGB24; - } else { - av_log(s1, AV_LOG_ERROR,"rgb ordering at image depth %i not supported ... aborting\n", image->bits_per_pixel); - av_log(s1, AV_LOG_ERROR, "color masks: r 0x%.6lx g 0x%.6lx b 0x%.6lx\n", image->red_mask, image->green_mask, image->blue_mask); - return AVERROR_IO; - } - break; - case 32: -#if 0 - GetColorInfo (image, &c_info); - if ( c_info.alpha_mask == 0xff000000 && image->green_mask == 0x0000ff00) { - /* byte order is relevant here, not endianness - * endianness is handled by avcodec, but atm no such thing - * as having ABGR, instead of ARGB in a word. Since we - * need this for Solaris/SPARC, but need to do the conversion - * for every frame we do it outside of this loop, cf. below - * this matches both ARGB32 and ABGR32 */ - input_pixfmt = PIX_FMT_ARGB32; - } else { - av_log(s1, AV_LOG_ERROR,"image depth %i not supported ... aborting\n", image->bits_per_pixel); - return AVERROR_IO; - } -#endif - input_pixfmt = PIX_FMT_RGB32; - break; - default: - av_log(s1, AV_LOG_ERROR, "image depth %i not supported ... aborting\n", image->bits_per_pixel); - return -1; - } - - x11grab->frame_size = ap->width * ap->height * image->bits_per_pixel/8; - x11grab->dpy = dpy; - x11grab->width = ap->width; - x11grab->height = ap->height; - x11grab->time_base = ap->time_base; - x11grab->time_frame = av_gettime() / av_q2d(ap->time_base); - x11grab->x_off = x_off; - x11grab->y_off = y_off; - x11grab->image = image; - x11grab->use_shm = use_shm; - x11grab->mouse_warning_shown = 0; - - st->codec->codec_type = CODEC_TYPE_VIDEO; - st->codec->codec_id = CODEC_ID_RAWVIDEO; - st->codec->width = ap->width; - st->codec->height = ap->height; - st->codec->pix_fmt = input_pixfmt; - st->codec->time_base = ap->time_base; - st->codec->bit_rate = x11grab->frame_size * 1/av_q2d(ap->time_base) * 8; - - return 0; -} - -/** - * Get pointer coordinates from X11. - * - * @param x Integer where horizontal coordinate will be returned - * @param y Integer where vertical coordinate will be returned - * @param dpy X11 display from where pointer coordinates are retrieved - * @param s1 Context used for logging errors if necessary - */ -static void -get_pointer_coordinates(int *x, int *y, Display *dpy, AVFormatContext *s1) -{ - Window mrootwindow, childwindow; - int dummy; - - mrootwindow = DefaultRootWindow(dpy); - - if (XQueryPointer(dpy, mrootwindow, &mrootwindow, &childwindow, - x, y, &dummy, &dummy, (unsigned int*)&dummy)) { - } else { - x11_grab_t *s = s1->priv_data; - if (!s->mouse_warning_shown) { - av_log(s1, AV_LOG_INFO, "couldn't find mouse pointer\n"); - s->mouse_warning_shown = 1; - } - *x = -1; - *y = -1; - } -} - -/** - * Mouse painting helper function that applies an 'and' and 'or' mask pair to - * '*dst' pixel. It actually draws a mouse pointer pixel to grabbed frame. - * - * @param dst Destination pixel - * @param and Part of the mask that must be applied using a bitwise 'and' - * operator - * @param or Part of the mask that must be applied using a bitwise 'or' - * operator - * @param bits_per_pixel Bits per pixel used in the grabbed image - */ -static void inline -apply_masks(uint8_t *dst, int and, int or, int bits_per_pixel) -{ - switch (bits_per_pixel) { - case 32: - *(uint32_t*)dst = (*(uint32_t*)dst & and) | or; - break; - case 16: - *(uint16_t*)dst = (*(uint16_t*)dst & and) | or; - break; - case 8: - *dst = !!or; - break; - } -} - -/** - * Paints a mouse pointer in an X11 image. - * - * @param image Image where to paint the mouse pointer - * @param s context used to retrieve original grabbing rectangle - * coordinates - * @param x Mouse pointer coordinate - * @param y Mouse pointer coordinate - */ -static void -paint_mouse_pointer(XImage *image, x11_grab_t *s, int x, int y) -{ - /* 16x20x1bpp bitmap for the black channel of the mouse pointer */ - static const uint16_t const mousePointerBlack[] = - { - 0x0000, 0x0003, 0x0005, 0x0009, 0x0011, - 0x0021, 0x0041, 0x0081, 0x0101, 0x0201, - 0x03c1, 0x0049, 0x0095, 0x0093, 0x0120, - 0x0120, 0x0240, 0x0240, 0x0380, 0x0000 - }; - - /* 16x20x1bpp bitmap for the white channel of the mouse pointer */ - static const uint16_t const mousePointerWhite[] = - { - 0x0000, 0x0000, 0x0002, 0x0006, 0x000e, - 0x001e, 0x003e, 0x007e, 0x00fe, 0x01fe, - 0x003e, 0x0036, 0x0062, 0x0060, 0x00c0, - 0x00c0, 0x0180, 0x0180, 0x0000, 0x0000 - }; - - int x_off = s->x_off; - int y_off = s->y_off; - int width = s->width; - int height = s->height; - - if ( x - x_off >= 0 && x < width + x_off - && y - y_off >= 0 && y < height + y_off) { - uint8_t *im_data = (uint8_t*)image->data; - int bytes_per_pixel; - int line; - int masks; - - /* Select correct masks and pixel size */ - if (image->bits_per_pixel == 8) { - masks = 1; - } else { - masks = (image->red_mask|image->green_mask|image->blue_mask); - } - bytes_per_pixel = image->bits_per_pixel>>3; - - /* Shift to right line */ - im_data += image->bytes_per_line * (y - y_off); - /* Shift to right pixel in the line */ - im_data += bytes_per_pixel * (x - x_off); - - /* Draw the cursor - proper loop */ - for (line = 0; line < FFMIN(20, (y_off + height) - y); line++) { - uint8_t *cursor = im_data; - int column; - uint16_t bm_b; - uint16_t bm_w; - - bm_b = mousePointerBlack[line]; - bm_w = mousePointerWhite[line]; - - for (column = 0; column < FFMIN(16, (x_off + width) - x); column++) { - apply_masks(cursor, ~(masks*(bm_b&1)), masks*(bm_w&1), - image->bits_per_pixel); - cursor += bytes_per_pixel; - bm_b >>= 1; - bm_w >>= 1; - } - im_data += image->bytes_per_line; - } - } -} - - -/** - * Reads new data in the image structure. - * - * @param dpy X11 display to grab from - * @param d - * @param image Image where the grab will be put - * @param x Top-Left grabbing rectangle horizontal coordinate - * @param y Top-Left grabbing rectangle vertical coordinate - * @return 0 if error, !0 if successful - */ -static int -xget_zpixmap(Display *dpy, Drawable d, XImage *image, int x, int y) -{ - xGetImageReply rep; - xGetImageReq *req; - long nbytes; - - if (!image) { - return 0; - } - - LockDisplay(dpy); - GetReq(GetImage, req); - - /* First set up the standard stuff in the request */ - req->drawable = d; - req->x = x; - req->y = y; - req->width = image->width; - req->height = image->height; - req->planeMask = (unsigned int)AllPlanes; - req->format = ZPixmap; - - if (!_XReply(dpy, (xReply *)&rep, 0, xFalse) || !rep.length) { - UnlockDisplay(dpy); - SyncHandle(); - return 0; - } - - nbytes = (long)rep.length << 2; - _XReadPad(dpy, image->data, nbytes); - - UnlockDisplay(dpy); - SyncHandle(); - return 1; -} - -/** - * Grabs a frame from x11 (public device demuxer API). - * - * @param s1 Context from avformat core - * @param pkt Packet holding the brabbed frame - * @return frame size in bytes - */ -static int -x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt) -{ - x11_grab_t *s = s1->priv_data; - Display *dpy = s->dpy; - XImage *image = s->image; - int x_off = s->x_off; - int y_off = s->y_off; - - int64_t curtime, delay; - struct timespec ts; - - /* Calculate the time of the next frame */ - s->time_frame += INT64_C(1000000); - - /* wait based on the frame rate */ - for(;;) { - curtime = av_gettime(); - delay = s->time_frame * av_q2d(s->time_base) - curtime; - if (delay <= 0) { - if (delay < INT64_C(-1000000) * av_q2d(s->time_base)) { - s->time_frame += INT64_C(1000000); - } - break; - } - ts.tv_sec = delay / 1000000; - ts.tv_nsec = (delay % 1000000) * 1000; - nanosleep(&ts, NULL); - } - - if (av_new_packet(pkt, s->frame_size) < 0) { - return AVERROR_IO; - } - - pkt->pts = curtime; - - if(s->use_shm) { - if (!XShmGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off, AllPlanes)) { - av_log (s1, AV_LOG_INFO, "XShmGetImage() failed\n"); - } - } else { - if (!xget_zpixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off)) { - av_log (s1, AV_LOG_INFO, "XGetZPixmap() failed\n"); - } - } - - { - int pointer_x, pointer_y; - get_pointer_coordinates(&pointer_x, &pointer_y, dpy, s1); - paint_mouse_pointer(image, s, pointer_x, pointer_y); - } - - - /* XXX: avoid memcpy */ - memcpy(pkt->data, image->data, s->frame_size); - return s->frame_size; -} - -/** - * Closes x11 frame grabber (public device demuxer API). - * - * @param s1 Context from avformat core - * @return 0 success, !0 failure - */ -static int -x11grab_read_close(AVFormatContext *s1) -{ - x11_grab_t *x11grab = s1->priv_data; - - /* Detach cleanly from shared mem */ - if (x11grab->use_shm) { - XShmDetach(x11grab->dpy, &x11grab->shminfo); - shmdt(x11grab->shminfo.shmaddr); - shmctl(x11grab->shminfo.shmid, IPC_RMID, NULL); - } - - /* Destroy X11 image */ - if (x11grab->image) { - XDestroyImage(x11grab->image); - x11grab->image = NULL; - } - - /* Free X11 display */ - XCloseDisplay(x11grab->dpy); - return 0; -} - -/** x11 grabber device demuxer declaration */ -AVInputFormat x11_grab_device_demuxer = -{ - "x11grab", - "X11grab", - sizeof(x11_grab_t), - NULL, - x11grab_read_header, - x11grab_read_packet, - x11grab_read_close, - .flags = AVFMT_NOFILE, -}; diff --git a/contrib/ffmpeg/libavformat/yuv4mpeg.c b/contrib/ffmpeg/libavformat/yuv4mpeg.c index 70214ae00..7913e417a 100644 --- a/contrib/ffmpeg/libavformat/yuv4mpeg.c +++ b/contrib/ffmpeg/libavformat/yuv4mpeg.c @@ -87,7 +87,7 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; AVPicture *picture; int* first_pkt = s->priv_data; int width, height, h_chroma_shift, v_chroma_shift; @@ -103,7 +103,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) *first_pkt = 0; if (yuv4_generate_header(s, buf2) < 0) { av_log(s, AV_LOG_ERROR, "Error. YUV4MPEG stream header write failed.\n"); - return AVERROR_IO; + return AVERROR(EIO); } else { put_buffer(pb, buf2, strlen(buf2)); } @@ -149,7 +149,7 @@ static int yuv4_write_header(AVFormatContext *s) int* first_pkt = s->priv_data; if (s->nb_streams != 1) - return AVERROR_IO; + return AVERROR(EIO); 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"); @@ -159,18 +159,13 @@ static int yuv4_write_header(AVFormatContext *s) (s->streams[0]->codec->pix_fmt != PIX_FMT_GRAY8) && (s->streams[0]->codec->pix_fmt != PIX_FMT_YUV444P)) { av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg only handles yuv444p, yuv422p, yuv420p, yuv411p and gray pixel formats. Use -pix_fmt to select one.\n"); - return AVERROR_IO; + return AVERROR(EIO); } *first_pkt = 1; return 0; } -static int yuv4_write_trailer(AVFormatContext *s) -{ - return 0; -} - #ifdef CONFIG_YUV4MPEGPIPE_MUXER AVOutputFormat yuv4mpegpipe_muxer = { "yuv4mpegpipe", @@ -182,7 +177,6 @@ AVOutputFormat yuv4mpegpipe_muxer = { CODEC_ID_RAWVIDEO, yuv4_write_header, yuv4_write_packet, - yuv4_write_trailer, .flags = AVFMT_RAWPICTURE, }; #endif @@ -196,7 +190,7 @@ static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap) char header[MAX_YUV4_HEADER+10]; // Include headroom for the longest option char *tokstart,*tokend,*header_end; int i; - ByteIOContext *pb = &s->pb; + ByteIOContext *pb = s->pb; int width=-1, height=-1, raten=0, rated=0, aspectn=0, aspectd=0; enum PixelFormat pix_fmt=PIX_FMT_NONE,alt_pix_fmt=PIX_FMT_NONE; AVStream *st; @@ -350,7 +344,7 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) struct frame_attributes *s1 = s->priv_data; for (i=0; i<MAX_FRAME_HEADER; i++) { - header[i] = get_byte(&s->pb); + header[i] = get_byte(s->pb); if (header[i] == '\n') { header[i+1] = 0; break; @@ -366,8 +360,8 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) if (packet_size < 0) return -1; - if (av_get_packet(&s->pb, pkt, packet_size) != packet_size) - return AVERROR_IO; + if (av_get_packet(s->pb, pkt, packet_size) != packet_size) + return AVERROR(EIO); if (s->streams[0]->codec->coded_frame) { s->streams[0]->codec->coded_frame->interlaced_frame = s1->interlaced_frame; @@ -386,8 +380,6 @@ static int yuv4_read_close(AVFormatContext *s) static int yuv4_probe(AVProbeData *pd) { /* check file header */ - if (pd->buf_size <= sizeof(Y4M_MAGIC)) - return 0; if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC)-1)==0) return AVPROBE_SCORE_MAX; else |