ffmpeg | branch: master | James Almer <jamr...@gmail.com> | Fri Oct 27 13:52:19 2017 -0300| [e0250cf3651e6417e0117486a7816b45fb2d34cd] | committer: James Almer
Merge commit '50a1c66cf6ab7eb683daaa9e2da3869fa3a54609' * commit '50a1c66cf6ab7eb683daaa9e2da3869fa3a54609': ac3_parser: add a public function for parsing the data required by the demuxer avpriv_ac3_parse_header() is left in place but without the GetBitContext parameter, as the mov muxer requires a lot more fields than just bitstream_id and frame_size from the AC3HeaderInfo struct. Merged-by: James Almer <jamr...@gmail.com> > http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=e0250cf3651e6417e0117486a7816b45fb2d34cd --- libavcodec/Makefile | 9 ++--- libavcodec/ac3_parser.c | 72 ++++++++++++++++++++++++++++++++++------ libavcodec/ac3_parser.h | 18 ++++------ libavcodec/ac3_parser_internal.h | 42 +++++++++++++++++++++++ libavcodec/ac3dec.c | 6 ++-- libavcodec/audiotoolboxdec.c | 4 +-- libavcodec/eac3dec.c | 1 - libavformat/ac3dec.c | 34 +++++++++++-------- libavformat/movenc.c | 17 +++++----- 9 files changed, 149 insertions(+), 54 deletions(-) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index bc4d7dab27..8c878c3699 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1,7 +1,8 @@ NAME = avcodec DESC = FFmpeg codec library -HEADERS = avcodec.h \ +HEADERS = ac3_parser.h \ + avcodec.h \ avdct.h \ avfft.h \ d3d11va.h \ @@ -18,7 +19,8 @@ HEADERS = avcodec.h \ vorbis_parser.h \ xvmc.h \ -OBJS = allcodecs.o \ +OBJS = ac3_parser.o \ + allcodecs.o \ avdct.o \ avpacket.o \ avpicture.o \ @@ -955,8 +957,7 @@ OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o ass.o OBJS-$(CONFIG_AAC_LATM_PARSER) += latm_parser.o OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \ aacadtsdec.o mpeg4audio.o -OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o \ - aac_ac3_parser.o +OBJS-$(CONFIG_AC3_PARSER) += ac3tab.o aac_ac3_parser.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o OBJS-$(CONFIG_BMP_PARSER) += bmp_parser.o OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c index 83dd90ff67..1015245a90 100644 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@ -20,15 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" + #include "libavutil/channel_layout.h" #include "parser.h" #include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "aac_ac3_parser.h" #include "get_bits.h" #define AC3_HEADER_SIZE 7 +#if CONFIG_AC3_PARSER static const uint8_t eac3_blocks[4] = { 1, 2, 3, 6 @@ -47,16 +51,9 @@ static const uint8_t center_levels[4] = { 4, 5, 6, 5 }; static const uint8_t surround_levels[4] = { 4, 6, 7, 6 }; -int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **phdr) +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) { int frame_size_code; - AC3HeaderInfo *hdr; - - if (!*phdr) - *phdr = av_mallocz(sizeof(AC3HeaderInfo)); - if (!*phdr) - return AVERROR(ENOMEM); - hdr = *phdr; memset(hdr, 0, sizeof(*hdr)); @@ -151,6 +148,46 @@ int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **phdr) return 0; } +// TODO: Better way to pass AC3HeaderInfo fields to mov muxer. +int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, + size_t size) +{ + GetBitContext gb; + AC3HeaderInfo *hdr; + int err; + + if (!*phdr) + *phdr = av_mallocz(sizeof(AC3HeaderInfo)); + if (!*phdr) + return AVERROR(ENOMEM); + hdr = *phdr; + + init_get_bits8(&gb, buf, size); + err = ff_ac3_parse_header(&gb, hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + return get_bits_count(&gb); +} + +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) +{ + GetBitContext gb; + AC3HeaderInfo hdr; + int err; + + init_get_bits8(&gb, buf, size); + err = ff_ac3_parse_header(&gb, &hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + *bitstream_id = hdr.bitstream_id; + *frame_size = hdr.frame_size; + + return 0; +} + static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, int *need_next_header, int *new_frame_start) { @@ -159,11 +196,11 @@ static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, uint64_t u64; uint8_t u8[8 + AV_INPUT_BUFFER_PADDING_SIZE]; } tmp = { av_be2ne64(state) }; - AC3HeaderInfo hdr, *phdr = &hdr; + AC3HeaderInfo hdr; GetBitContext gbc; init_get_bits(&gbc, tmp.u8+8-AC3_HEADER_SIZE, 54); - err = avpriv_ac3_parse_header(&gbc, &phdr); + err = ff_ac3_parse_header(&gbc, &hdr); if(err < 0) return 0; @@ -202,3 +239,18 @@ AVCodecParser ff_ac3_parser = { .parser_parse = ff_aac_ac3_parse, .parser_close = ff_parse_close, }; + +#else + +int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, + size_t size) +{ + return AVERROR(ENOSYS); +} + +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) +{ + return AVERROR(ENOSYS); +} +#endif diff --git a/libavcodec/ac3_parser.h b/libavcodec/ac3_parser.h index dc5d035e11..ff8cc4cf09 100644 --- a/libavcodec/ac3_parser.h +++ b/libavcodec/ac3_parser.h @@ -23,20 +23,14 @@ #ifndef AVCODEC_AC3_PARSER_H #define AVCODEC_AC3_PARSER_H -#include "ac3.h" -#include "get_bits.h" +#include <stddef.h> +#include <stdint.h> /** - * Parse AC-3 frame header. - * Parse the header up to the lfeon element, which is the first 52 or 54 bits - * depending on the audio coding mode. - * @param[in] gbc BitContext containing the first 54 bits of the frame. - * @param[out] hdr Pointer to Pointer to struct where header info is written. - * will be allocated if NULL - * @return Returns 0 on success, -1 if there is a sync word mismatch, - * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) - * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + * Extract the bitstream ID and the frame size from AC-3 data. */ -int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **hdr); +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size); + #endif /* AVCODEC_AC3_PARSER_H */ diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h new file mode 100644 index 0000000000..3648802a73 --- /dev/null +++ b/libavcodec/ac3_parser_internal.h @@ -0,0 +1,42 @@ +/* + * AC-3 parser internal code + * + * 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 AVCODEC_AC3_PARSER_INTERNAL_H +#define AVCODEC_AC3_PARSER_INTERNAL_H + +#include "ac3.h" +#include "get_bits.h" + +/** + * Parse AC-3 frame header. + * Parse the header up to the lfeon element, which is the first 52 or 54 bits + * depending on the audio coding mode. + * @param[in] gbc BitContext containing the first 54 bits of the frame. + * @param[out] hdr Pointer to struct where header info is written. + * @return Returns 0 on success, -1 if there is a sync word mismatch, + * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) + * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + */ +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr); + +int avpriv_ac3_parse_header(AC3HeaderInfo **hdr, const uint8_t *buf, + size_t size); + +#endif /* AVCODEC_AC3_PARSER_INTERNAL_H */ diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index c393076aec..244a18323f 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -36,7 +36,7 @@ #include "bswapdsp.h" #include "internal.h" #include "aac_ac3_parser.h" -#include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "kbdwin.h" @@ -297,10 +297,10 @@ static int ac3_parse_header(AC3DecodeContext *s) */ static int parse_frame_header(AC3DecodeContext *s) { - AC3HeaderInfo hdr, *phdr=&hdr; + AC3HeaderInfo hdr; int err; - err = avpriv_ac3_parse_header(&s->gbc, &phdr); + err = ff_ac3_parse_header(&s->gbc, &hdr); if (err) return err; diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c index 607d3ba4d4..a149949aba 100644 --- a/libavcodec/audiotoolboxdec.c +++ b/libavcodec/audiotoolboxdec.c @@ -350,10 +350,10 @@ static av_cold int ffat_create_decoder(AVCodecContext *avctx, AVPacket *pkt) } else if (pkt && pkt->size >= 7 && (avctx->codec_id == AV_CODEC_ID_AC3 || avctx->codec_id == AV_CODEC_ID_EAC3)) { - AC3HeaderInfo hdr, *phdr = &hdr; + AC3HeaderInfo hdr; GetBitContext gbc; init_get_bits(&gbc, pkt->data, pkt->size); - if (avpriv_ac3_parse_header(&gbc, &phdr) < 0) + if (ff_ac3_parse_header(&gbc, &hdr) < 0) return AVERROR_INVALIDDATA; in_format.mSampleRate = hdr.sample_rate; in_format.mChannelsPerFrame = hdr.channels; diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index c971879b2d..6f6309f179 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -48,7 +48,6 @@ #include "internal.h" #include "aac_ac3_parser.h" #include "ac3.h" -#include "ac3_parser.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "eac3_data.h" diff --git a/libavformat/ac3dec.c b/libavformat/ac3dec.c index e85b0ac7c9..8ea73824a6 100644 --- a/libavformat/ac3dec.c +++ b/libavformat/ac3dec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/crc.h" #include "libavcodec/ac3_parser.h" #include "avformat.h" @@ -28,8 +29,6 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) { int max_frames, first_frames = 0, frames; const uint8_t *buf, *buf2, *end; - AC3HeaderInfo *phdr = NULL; - GetBitContext gbc; enum AVCodecID codec_id = AV_CODEC_ID_AC3; max_frames = 0; @@ -44,7 +43,10 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) for(frames = 0; buf2 < end; frames++) { uint8_t buf3[4096]; - int i; + uint8_t bitstream_id; + uint16_t frame_size; + int i, ret; + if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) buf2+=16; if (buf[0] == 0x77 && buf[1] == 0x0B) { @@ -52,31 +54,35 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) buf3[i ] = buf2[i+1]; buf3[i+1] = buf2[i ]; } - init_get_bits(&gbc, buf3, 54); + ret = av_ac3_parse_header(buf3, 8, &bitstream_id, + &frame_size); }else - init_get_bits(&gbc, buf2, 54); - if(avpriv_ac3_parse_header(&gbc, &phdr) < 0) + ret = av_ac3_parse_header(buf2, end - buf2, &bitstream_id, + &frame_size); + if (ret < 0) break; - if(buf2 + phdr->frame_size > end) + if(buf2 + frame_size > end) break; if (buf[0] == 0x77 && buf[1] == 0x0B) { - av_assert0(phdr->frame_size <= sizeof(buf3)); - for(i=8; i<phdr->frame_size; i+=2) { + av_assert0(frame_size <= sizeof(buf3)); + for(i = 8; i < frame_size; i += 2) { buf3[i ] = buf2[i+1]; buf3[i+1] = buf2[i ]; } + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf3 + 2, frame_size - 2)) + break; + } else { + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, frame_size - 2)) + break; } - if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, phdr->frame_size - 2)) - break; - if (phdr->bitstream_id > 10) + if (bitstream_id > 10) codec_id = AV_CODEC_ID_EAC3; - buf2 += phdr->frame_size; + buf2 += frame_size; } max_frames = FFMAX(max_frames, frames); if(buf == p->buf) first_frames = frames; } - av_freep(&phdr); if(codec_id != expected_codec_id) return 0; // keep this in sync with mp3 probe, both need to avoid // issues with MPEG-files! diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 2838286141..a34987a7dc 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -31,7 +31,7 @@ #include "avio.h" #include "isom.h" #include "avc.h" -#include "libavcodec/ac3_parser.h" +#include "libavcodec/ac3_parser_internal.h" #include "libavcodec/dnxhddata.h" #include "libavcodec/flac.h" #include "libavcodec/get_bits.h" @@ -345,7 +345,6 @@ struct eac3_info { #if CONFIG_AC3_PARSER static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) { - GetBitContext gbc; AC3HeaderInfo tmp, *hdr = &tmp; struct eac3_info *info; int num_blocks; @@ -354,8 +353,7 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) return AVERROR(ENOMEM); info = track->eac3_priv; - init_get_bits(&gbc, pkt->data, pkt->size * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) { + if (avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size) < 0) { /* drop the packets until we see a good one */ if (!track->entry) { av_log(mov, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n"); @@ -403,16 +401,18 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) int parent = hdr->substreamid; while (cumul_size != pkt->size) { - int i; - init_get_bits(&gbc, pkt->data + cumul_size, (pkt->size - cumul_size) * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) + GetBitContext gbc; + int i, ret; + ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size); + if (ret < 0) return AVERROR_INVALIDDATA; if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) return AVERROR(EINVAL); - cumul_size += hdr->frame_size; info->substream[parent].num_dep_sub++; + ret /= 8; /* header is parsed up to lfeon, but custom channel map may be needed */ + init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret); /* skip bsid */ skip_bits(&gbc, 5); /* skip volume control params */ @@ -427,6 +427,7 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f; else info->substream[parent].chan_loc |= hdr->channel_mode; + cumul_size += hdr->frame_size; } } } ====================================================================== diff --cc libavcodec/Makefile index bc4d7dab27,a82210d89f..8c878c3699 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@@ -1,25 -1,22 +1,27 @@@ NAME = avcodec -DESC = Libav codec library +DESC = FFmpeg codec library - HEADERS = avcodec.h \ + HEADERS = ac3_parser.h \ + avcodec.h \ + avdct.h \ avfft.h \ d3d11va.h \ dirac.h \ dv_profile.h \ dxva2.h \ + jni.h \ + mediacodec.h \ qsv.h \ vaapi.h \ - vda.h \ vdpau.h \ version.h \ + videotoolbox.h \ vorbis_parser.h \ + xvmc.h \ - OBJS = allcodecs.o \ + OBJS = ac3_parser.o \ + allcodecs.o \ + avdct.o \ avpacket.o \ avpicture.o \ bitstream.o \ diff --cc libavcodec/ac3_parser.c index 83dd90ff67,53189e0d4e..1015245a90 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@@ -151,6 -148,24 +148,46 @@@ int ff_ac3_parse_header(GetBitContext * return 0; } ++// TODO: Better way to pass AC3HeaderInfo fields to mov muxer. ++int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, ++ size_t size) ++{ ++ GetBitContext gb; ++ AC3HeaderInfo *hdr; ++ int err; ++ ++ if (!*phdr) ++ *phdr = av_mallocz(sizeof(AC3HeaderInfo)); ++ if (!*phdr) ++ return AVERROR(ENOMEM); ++ hdr = *phdr; ++ ++ init_get_bits8(&gb, buf, size); ++ err = ff_ac3_parse_header(&gb, hdr); ++ if (err < 0) ++ return AVERROR_INVALIDDATA; ++ ++ return get_bits_count(&gb); ++} ++ + int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) + { + GetBitContext gb; + AC3HeaderInfo hdr; + int err; + + init_get_bits8(&gb, buf, size); + err = ff_ac3_parse_header(&gb, &hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + *bitstream_id = hdr.bitstream_id; + *frame_size = hdr.frame_size; + + return 0; + } + static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, int *need_next_header, int *new_frame_start) { @@@ -202,3 -217,12 +239,18 @@@ AVCodecParser ff_ac3_parser = .parser_parse = ff_aac_ac3_parse, .parser_close = ff_parse_close, }; + + #else + ++int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, ++ size_t size) ++{ ++ return AVERROR(ENOSYS); ++} ++ + int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) + { + return AVERROR(ENOSYS); + } + #endif diff --cc libavcodec/ac3_parser_internal.h index 0000000000,5e305e8352..3648802a73 mode 000000,100644..100644 --- a/libavcodec/ac3_parser_internal.h +++ b/libavcodec/ac3_parser_internal.h @@@ -1,0 -1,39 +1,42 @@@ + /* + * AC-3 parser internal code + * - * This file is part of Libav. ++ * This file is part of FFmpeg. + * - * Libav is free software; you can redistribute it and/or ++ * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * - * Libav is distributed in the hope that it will be useful, ++ * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software ++ * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + #ifndef AVCODEC_AC3_PARSER_INTERNAL_H + #define AVCODEC_AC3_PARSER_INTERNAL_H + + #include "ac3.h" + #include "get_bits.h" + + /** + * Parse AC-3 frame header. + * Parse the header up to the lfeon element, which is the first 52 or 54 bits + * depending on the audio coding mode. + * @param[in] gbc BitContext containing the first 54 bits of the frame. + * @param[out] hdr Pointer to struct where header info is written. + * @return Returns 0 on success, -1 if there is a sync word mismatch, + * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) + * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + */ + int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr); + ++int avpriv_ac3_parse_header(AC3HeaderInfo **hdr, const uint8_t *buf, ++ size_t size); ++ + #endif /* AVCODEC_AC3_PARSER_INTERNAL_H */ diff --cc libavcodec/audiotoolboxdec.c index 607d3ba4d4,0000000000..a149949aba mode 100644,000000..100644 --- a/libavcodec/audiotoolboxdec.c +++ b/libavcodec/audiotoolboxdec.c @@@ -1,616 -1,0 +1,616 @@@ +/* + * Audio Toolbox system codecs + * + * copyright (c) 2016 Rodger Combs + * + * 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 <AudioToolbox/AudioToolbox.h> + +#include "config.h" +#include "avcodec.h" +#include "ac3_parser.h" +#include "bytestream.h" +#include "internal.h" +#include "mpegaudiodecheader.h" +#include "libavutil/avassert.h" +#include "libavutil/opt.h" +#include "libavutil/log.h" + +#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101100 +#define kAudioFormatEnhancedAC3 'ec-3' +#endif + +typedef struct ATDecodeContext { + AVClass *av_class; + + AudioConverterRef converter; + AudioStreamPacketDescription pkt_desc; + AVPacket in_pkt; + AVPacket new_in_pkt; + char *decoded_data; + int channel_map[64]; + + uint8_t *extradata; + int extradata_size; + + int64_t last_pts; + int eof; +} ATDecodeContext; + +static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) +{ + switch (codec) { + case AV_CODEC_ID_AAC: + return kAudioFormatMPEG4AAC; + case AV_CODEC_ID_AC3: + return kAudioFormatAC3; + case AV_CODEC_ID_ADPCM_IMA_QT: + return kAudioFormatAppleIMA4; + case AV_CODEC_ID_ALAC: + return kAudioFormatAppleLossless; + case AV_CODEC_ID_AMR_NB: + return kAudioFormatAMR; + case AV_CODEC_ID_EAC3: + return kAudioFormatEnhancedAC3; + case AV_CODEC_ID_GSM_MS: + return kAudioFormatMicrosoftGSM; + case AV_CODEC_ID_ILBC: + return kAudioFormatiLBC; + case AV_CODEC_ID_MP1: + return kAudioFormatMPEGLayer1; + case AV_CODEC_ID_MP2: + return kAudioFormatMPEGLayer2; + case AV_CODEC_ID_MP3: + return kAudioFormatMPEGLayer3; + case AV_CODEC_ID_PCM_ALAW: + return kAudioFormatALaw; + case AV_CODEC_ID_PCM_MULAW: + return kAudioFormatULaw; + case AV_CODEC_ID_QDMC: + return kAudioFormatQDesign; + case AV_CODEC_ID_QDM2: + return kAudioFormatQDesign2; + default: + av_assert0(!"Invalid codec ID!"); + return 0; + } +} + +static int ffat_get_channel_id(AudioChannelLabel label) +{ + if (label == 0) + return -1; + else if (label <= kAudioChannelLabel_LFEScreen) + return label - 1; + else if (label <= kAudioChannelLabel_RightSurround) + return label + 4; + else if (label <= kAudioChannelLabel_CenterSurround) + return label + 1; + else if (label <= kAudioChannelLabel_RightSurroundDirect) + return label + 23; + else if (label <= kAudioChannelLabel_TopBackRight) + return label - 1; + else if (label < kAudioChannelLabel_RearSurroundLeft) + return -1; + else if (label <= kAudioChannelLabel_RearSurroundRight) + return label - 29; + else if (label <= kAudioChannelLabel_RightWide) + return label - 4; + else if (label == kAudioChannelLabel_LFE2) + return ff_ctzll(AV_CH_LOW_FREQUENCY_2); + else if (label == kAudioChannelLabel_Mono) + return ff_ctzll(AV_CH_FRONT_CENTER); + else + return -1; +} + +static int ffat_compare_channel_descriptions(const void* a, const void* b) +{ + const AudioChannelDescription* da = a; + const AudioChannelDescription* db = b; + return ffat_get_channel_id(da->mChannelLabel) - ffat_get_channel_id(db->mChannelLabel); +} + +static AudioChannelLayout *ffat_convert_layout(AudioChannelLayout *layout, UInt32* size) +{ + AudioChannelLayoutTag tag = layout->mChannelLayoutTag; + AudioChannelLayout *new_layout; + if (tag == kAudioChannelLayoutTag_UseChannelDescriptions) + return layout; + else if (tag == kAudioChannelLayoutTag_UseChannelBitmap) + AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForBitmap, + sizeof(UInt32), &layout->mChannelBitmap, size); + else + AudioFormatGetPropertyInfo(kAudioFormatProperty_ChannelLayoutForTag, + sizeof(AudioChannelLayoutTag), &tag, size); + new_layout = av_malloc(*size); + if (!new_layout) { + av_free(layout); + return NULL; + } + if (tag == kAudioChannelLayoutTag_UseChannelBitmap) + AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap, + sizeof(UInt32), &layout->mChannelBitmap, size, new_layout); + else + AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag, + sizeof(AudioChannelLayoutTag), &tag, size, new_layout); + new_layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; + av_free(layout); + return new_layout; +} + +static int ffat_update_ctx(AVCodecContext *avctx) +{ + ATDecodeContext *at = avctx->priv_data; + AudioStreamBasicDescription format; + UInt32 size = sizeof(format); + if (!AudioConverterGetProperty(at->converter, + kAudioConverterCurrentInputStreamDescription, + &size, &format)) { + if (format.mSampleRate) + avctx->sample_rate = format.mSampleRate; + avctx->channels = format.mChannelsPerFrame; + avctx->channel_layout = av_get_default_channel_layout(avctx->channels); + avctx->frame_size = format.mFramesPerPacket; + } + + if (!AudioConverterGetProperty(at->converter, + kAudioConverterCurrentOutputStreamDescription, + &size, &format)) { + format.mSampleRate = avctx->sample_rate; + format.mChannelsPerFrame = avctx->channels; + AudioConverterSetProperty(at->converter, + kAudioConverterCurrentOutputStreamDescription, + size, &format); + } + + if (!AudioConverterGetPropertyInfo(at->converter, kAudioConverterOutputChannelLayout, + &size, NULL) && size) { + AudioChannelLayout *layout = av_malloc(size); + uint64_t layout_mask = 0; + int i; + if (!layout) + return AVERROR(ENOMEM); + AudioConverterGetProperty(at->converter, kAudioConverterOutputChannelLayout, + &size, layout); + if (!(layout = ffat_convert_layout(layout, &size))) + return AVERROR(ENOMEM); + for (i = 0; i < layout->mNumberChannelDescriptions; i++) { + int id = ffat_get_channel_id(layout->mChannelDescriptions[i].mChannelLabel); + if (id < 0) + goto done; + if (layout_mask & (1 << id)) + goto done; + layout_mask |= 1 << id; + layout->mChannelDescriptions[i].mChannelFlags = i; // Abusing flags as index + } + avctx->channel_layout = layout_mask; + qsort(layout->mChannelDescriptions, layout->mNumberChannelDescriptions, + sizeof(AudioChannelDescription), &ffat_compare_channel_descriptions); + for (i = 0; i < layout->mNumberChannelDescriptions; i++) + at->channel_map[i] = layout->mChannelDescriptions[i].mChannelFlags; +done: + av_free(layout); + } + + if (!avctx->frame_size) + avctx->frame_size = 2048; + + return 0; +} + +static void put_descr(PutByteContext *pb, int tag, unsigned int size) +{ + int i = 3; + bytestream2_put_byte(pb, tag); + for (; i > 0; i--) + bytestream2_put_byte(pb, (size >> (7 * i)) | 0x80); + bytestream2_put_byte(pb, size & 0x7F); +} + +static uint8_t* ffat_get_magic_cookie(AVCodecContext *avctx, UInt32 *cookie_size) +{ + ATDecodeContext *at = avctx->priv_data; + if (avctx->codec_id == AV_CODEC_ID_AAC) { + char *extradata; + PutByteContext pb; + *cookie_size = 5 + 3 + 5+13 + 5+at->extradata_size; + if (!(extradata = av_malloc(*cookie_size))) + return NULL; + + bytestream2_init_writer(&pb, extradata, *cookie_size); + + // ES descriptor + put_descr(&pb, 0x03, 3 + 5+13 + 5+at->extradata_size); + bytestream2_put_be16(&pb, 0); + bytestream2_put_byte(&pb, 0x00); // flags (= no flags) + + // DecoderConfig descriptor + put_descr(&pb, 0x04, 13 + 5+at->extradata_size); + + // Object type indication + bytestream2_put_byte(&pb, 0x40); + + bytestream2_put_byte(&pb, 0x15); // flags (= Audiostream) + + bytestream2_put_be24(&pb, 0); // Buffersize DB + + bytestream2_put_be32(&pb, 0); // maxbitrate + bytestream2_put_be32(&pb, 0); // avgbitrate + + // DecoderSpecific info descriptor + put_descr(&pb, 0x05, at->extradata_size); + bytestream2_put_buffer(&pb, at->extradata, at->extradata_size); + return extradata; + } else { + *cookie_size = at->extradata_size; + return at->extradata; + } +} + +static av_cold int ffat_usable_extradata(AVCodecContext *avctx) +{ + ATDecodeContext *at = avctx->priv_data; + return at->extradata_size && + (avctx->codec_id == AV_CODEC_ID_ALAC || + avctx->codec_id == AV_CODEC_ID_QDM2 || + avctx->codec_id == AV_CODEC_ID_QDMC || + avctx->codec_id == AV_CODEC_ID_AAC); +} + +static int ffat_set_extradata(AVCodecContext *avctx) +{ + ATDecodeContext *at = avctx->priv_data; + if (ffat_usable_extradata(avctx)) { + OSStatus status; + UInt32 cookie_size; + uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size); + if (!cookie) + return AVERROR(ENOMEM); + + status = AudioConverterSetProperty(at->converter, + kAudioConverterDecompressionMagicCookie, + cookie_size, cookie); + if (status != 0) + av_log(avctx, AV_LOG_WARNING, "AudioToolbox cookie error: %i\n", (int)status); + + if (cookie != at->extradata) + av_free(cookie); + } + return 0; +} + +static av_cold int ffat_create_decoder(AVCodecContext *avctx, AVPacket *pkt) +{ + ATDecodeContext *at = avctx->priv_data; + OSStatus status; + int i; + + enum AVSampleFormat sample_fmt = (avctx->bits_per_raw_sample == 32) ? + AV_SAMPLE_FMT_S32 : AV_SAMPLE_FMT_S16; + + AudioStreamBasicDescription in_format = { + .mFormatID = ffat_get_format_id(avctx->codec_id, avctx->profile), + .mBytesPerPacket = (avctx->codec_id == AV_CODEC_ID_ILBC) ? avctx->block_align : 0, + }; + AudioStreamBasicDescription out_format = { + .mFormatID = kAudioFormatLinearPCM, + .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked, + .mFramesPerPacket = 1, + .mBitsPerChannel = av_get_bytes_per_sample(sample_fmt) * 8, + }; + + avctx->sample_fmt = sample_fmt; + + if (ffat_usable_extradata(avctx)) { + UInt32 format_size = sizeof(in_format); + UInt32 cookie_size; + uint8_t *cookie = ffat_get_magic_cookie(avctx, &cookie_size); + if (!cookie) + return AVERROR(ENOMEM); + status = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, + cookie_size, cookie, &format_size, &in_format); + if (cookie != at->extradata) + av_free(cookie); + if (status != 0) { + av_log(avctx, AV_LOG_ERROR, "AudioToolbox header-parse error: %i\n", (int)status); + return AVERROR_UNKNOWN; + } +#if CONFIG_MP1_AT_DECODER || CONFIG_MP2_AT_DECODER || CONFIG_MP3_AT_DECODER + } else if (pkt && pkt->size >= 4 && + (avctx->codec_id == AV_CODEC_ID_MP1 || + avctx->codec_id == AV_CODEC_ID_MP2 || + avctx->codec_id == AV_CODEC_ID_MP3)) { + enum AVCodecID codec_id; + int bit_rate; + if (ff_mpa_decode_header(AV_RB32(pkt->data), &avctx->sample_rate, + &in_format.mChannelsPerFrame, &avctx->frame_size, + &bit_rate, &codec_id) < 0) + return AVERROR_INVALIDDATA; + avctx->bit_rate = bit_rate; + in_format.mSampleRate = avctx->sample_rate; +#endif +#if CONFIG_AC3_AT_DECODER || CONFIG_EAC3_AT_DECODER + } else if (pkt && pkt->size >= 7 && + (avctx->codec_id == AV_CODEC_ID_AC3 || + avctx->codec_id == AV_CODEC_ID_EAC3)) { - AC3HeaderInfo hdr, *phdr = &hdr; ++ AC3HeaderInfo hdr; + GetBitContext gbc; + init_get_bits(&gbc, pkt->data, pkt->size); - if (avpriv_ac3_parse_header(&gbc, &phdr) < 0) ++ if (ff_ac3_parse_header(&gbc, &hdr) < 0) + return AVERROR_INVALIDDATA; + in_format.mSampleRate = hdr.sample_rate; + in_format.mChannelsPerFrame = hdr.channels; + avctx->frame_size = hdr.num_blocks * 256; + avctx->bit_rate = hdr.bit_rate; +#endif + } else { + in_format.mSampleRate = avctx->sample_rate ? avctx->sample_rate : 44100; + in_format.mChannelsPerFrame = avctx->channels ? avctx->channels : 1; + } + + avctx->sample_rate = out_format.mSampleRate = in_format.mSampleRate; + avctx->channels = out_format.mChannelsPerFrame = in_format.mChannelsPerFrame; + + if (avctx->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) + in_format.mFramesPerPacket = 64; + + status = AudioConverterNew(&in_format, &out_format, &at->converter); + + if (status != 0) { + av_log(avctx, AV_LOG_ERROR, "AudioToolbox init error: %i\n", (int)status); + return AVERROR_UNKNOWN; + } + + if ((status = ffat_set_extradata(avctx)) < 0) + return status; + + for (i = 0; i < (sizeof(at->channel_map) / sizeof(at->channel_map[0])); i++) + at->channel_map[i] = i; + + ffat_update_ctx(avctx); + + if(!(at->decoded_data = av_malloc(av_get_bytes_per_sample(avctx->sample_fmt) + * avctx->frame_size * avctx->channels))) + return AVERROR(ENOMEM); + + at->last_pts = AV_NOPTS_VALUE; + + return 0; +} + +static av_cold int ffat_init_decoder(AVCodecContext *avctx) +{ + ATDecodeContext *at = avctx->priv_data; + if (avctx->extradata_size) { + at->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!at->extradata) + return AVERROR(ENOMEM); + at->extradata_size = avctx->extradata_size; + memcpy(at->extradata, avctx->extradata, avctx->extradata_size); + } + + if ((avctx->channels && avctx->sample_rate) || ffat_usable_extradata(avctx)) + return ffat_create_decoder(avctx, NULL); + else + return 0; +} + +static OSStatus ffat_decode_callback(AudioConverterRef converter, UInt32 *nb_packets, + AudioBufferList *data, + AudioStreamPacketDescription **packets, + void *inctx) +{ + AVCodecContext *avctx = inctx; + ATDecodeContext *at = avctx->priv_data; + + if (at->eof) { + *nb_packets = 0; + if (packets) { + *packets = &at->pkt_desc; + at->pkt_desc.mDataByteSize = 0; + } + return 0; + } + + av_packet_unref(&at->in_pkt); + av_packet_move_ref(&at->in_pkt, &at->new_in_pkt); + + if (!at->in_pkt.data) { + *nb_packets = 0; + return 1; + } + + data->mNumberBuffers = 1; + data->mBuffers[0].mNumberChannels = 0; + data->mBuffers[0].mDataByteSize = at->in_pkt.size; + data->mBuffers[0].mData = at->in_pkt.data; + *nb_packets = 1; + + if (packets) { + *packets = &at->pkt_desc; + at->pkt_desc.mDataByteSize = at->in_pkt.size; + } + + return 0; +} + +#define COPY_SAMPLES(type) \ + type *in_ptr = (type*)at->decoded_data; \ + type *end_ptr = in_ptr + frame->nb_samples * avctx->channels; \ + type *out_ptr = (type*)frame->data[0]; \ + for (; in_ptr < end_ptr; in_ptr += avctx->channels, out_ptr += avctx->channels) { \ + int c; \ + for (c = 0; c < avctx->channels; c++) \ + out_ptr[c] = in_ptr[at->channel_map[c]]; \ + } + +static void ffat_copy_samples(AVCodecContext *avctx, AVFrame *frame) +{ + ATDecodeContext *at = avctx->priv_data; + if (avctx->sample_fmt == AV_SAMPLE_FMT_S32) { + COPY_SAMPLES(int32_t); + } else { + COPY_SAMPLES(int16_t); + } +} + +static int ffat_decode(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + ATDecodeContext *at = avctx->priv_data; + AVFrame *frame = data; + int pkt_size = avpkt->size; + OSStatus ret; + AudioBufferList out_buffers; + + if (avctx->codec_id == AV_CODEC_ID_AAC) { + if (!at->extradata_size) { + uint8_t *side_data; + int side_data_size = 0; + + side_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, + &side_data_size); + if (side_data_size) { + at->extradata = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!at->extradata) + return AVERROR(ENOMEM); + at->extradata_size = side_data_size; + memcpy(at->extradata, side_data, side_data_size); + } + } + } + + if (!at->converter) { + if ((ret = ffat_create_decoder(avctx, avpkt)) < 0) { + return ret; + } + } + + out_buffers = (AudioBufferList){ + .mNumberBuffers = 1, + .mBuffers = { + { + .mNumberChannels = avctx->channels, + .mDataByteSize = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->frame_size + * avctx->channels, + } + } + }; + + av_packet_unref(&at->new_in_pkt); + + if (avpkt->size) { + if ((ret = av_packet_ref(&at->new_in_pkt, avpkt)) < 0) { + return ret; + } + } else { + at->eof = 1; + } + + frame->sample_rate = avctx->sample_rate; + + frame->nb_samples = avctx->frame_size; + + out_buffers.mBuffers[0].mData = at->decoded_data; + + ret = AudioConverterFillComplexBuffer(at->converter, ffat_decode_callback, avctx, + &frame->nb_samples, &out_buffers, NULL); + if ((!ret || ret == 1) && frame->nb_samples) { + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + ffat_copy_samples(avctx, frame); + *got_frame_ptr = 1; + if (at->last_pts != AV_NOPTS_VALUE) { + frame->pts = at->last_pts; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + frame->pkt_pts = at->last_pts; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + at->last_pts = avpkt->pts; + } + } else if (ret && ret != 1) { + av_log(avctx, AV_LOG_WARNING, "Decode error: %i\n", ret); + } else { + at->last_pts = avpkt->pts; + } + + return pkt_size; +} + +static av_cold void ffat_decode_flush(AVCodecContext *avctx) +{ + ATDecodeContext *at = avctx->priv_data; + AudioConverterReset(at->converter); + av_packet_unref(&at->new_in_pkt); + av_packet_unref(&at->in_pkt); +} + +static av_cold int ffat_close_decoder(AVCodecContext *avctx) +{ + ATDecodeContext *at = avctx->priv_data; + if (at->converter) + AudioConverterDispose(at->converter); + av_packet_unref(&at->new_in_pkt); + av_packet_unref(&at->in_pkt); + av_freep(&at->decoded_data); + av_freep(&at->extradata); + return 0; +} + +#define FFAT_DEC_CLASS(NAME) \ + static const AVClass ffat_##NAME##_dec_class = { \ + .class_name = "at_" #NAME "_dec", \ + .version = LIBAVUTIL_VERSION_INT, \ + }; + +#define FFAT_DEC(NAME, ID, bsf_name) \ + FFAT_DEC_CLASS(NAME) \ + AVCodec ff_##NAME##_at_decoder = { \ + .name = #NAME "_at", \ + .long_name = NULL_IF_CONFIG_SMALL(#NAME " (AudioToolbox)"), \ + .type = AVMEDIA_TYPE_AUDIO, \ + .id = ID, \ + .priv_data_size = sizeof(ATDecodeContext), \ + .init = ffat_init_decoder, \ + .close = ffat_close_decoder, \ + .decode = ffat_decode, \ + .flush = ffat_decode_flush, \ + .priv_class = &ffat_##NAME##_dec_class, \ + .bsfs = bsf_name, \ + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, \ + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, \ + }; + +FFAT_DEC(aac, AV_CODEC_ID_AAC, "aac_adtstoasc") +FFAT_DEC(ac3, AV_CODEC_ID_AC3, NULL) +FFAT_DEC(adpcm_ima_qt, AV_CODEC_ID_ADPCM_IMA_QT, NULL) +FFAT_DEC(alac, AV_CODEC_ID_ALAC, NULL) +FFAT_DEC(amr_nb, AV_CODEC_ID_AMR_NB, NULL) +FFAT_DEC(eac3, AV_CODEC_ID_EAC3, NULL) +FFAT_DEC(gsm_ms, AV_CODEC_ID_GSM_MS, NULL) +FFAT_DEC(ilbc, AV_CODEC_ID_ILBC, NULL) +FFAT_DEC(mp1, AV_CODEC_ID_MP1, NULL) +FFAT_DEC(mp2, AV_CODEC_ID_MP2, NULL) +FFAT_DEC(mp3, AV_CODEC_ID_MP3, NULL) +FFAT_DEC(pcm_alaw, AV_CODEC_ID_PCM_ALAW, NULL) +FFAT_DEC(pcm_mulaw, AV_CODEC_ID_PCM_MULAW, NULL) +FFAT_DEC(qdmc, AV_CODEC_ID_QDMC, NULL) +FFAT_DEC(qdm2, AV_CODEC_ID_QDM2, NULL) diff --cc libavformat/ac3dec.c index e85b0ac7c9,7a868056c7..8ea73824a6 --- a/libavformat/ac3dec.c +++ b/libavformat/ac3dec.c @@@ -19,6 -19,6 +19,7 @@@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ ++#include "libavutil/avassert.h" #include "libavutil/crc.h" #include "libavcodec/ac3_parser.h" #include "avformat.h" @@@ -27,9 -27,7 +28,7 @@@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) { int max_frames, first_frames = 0, frames; - uint8_t *buf, *buf2, *end; + const uint8_t *buf, *buf2, *end; - AC3HeaderInfo *phdr = NULL; - GetBitContext gbc; enum AVCodecID codec_id = AV_CODEC_ID_AC3; max_frames = 0; @@@ -43,34 -38,20 +42,42 @@@ buf2 = buf; for(frames = 0; buf2 < end; frames++) { + uint8_t buf3[4096]; - int i; + uint8_t bitstream_id; + uint16_t frame_size; - int ret; ++ int i, ret; + - ret = av_ac3_parse_header(buf2, end - buf2, &bitstream_id, - &frame_size); + if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) + buf2+=16; + if (buf[0] == 0x77 && buf[1] == 0x0B) { + for(i=0; i<8; i+=2) { + buf3[i ] = buf2[i+1]; + buf3[i+1] = buf2[i ]; + } - init_get_bits(&gbc, buf3, 54); ++ ret = av_ac3_parse_header(buf3, 8, &bitstream_id, ++ &frame_size); + }else - init_get_bits(&gbc, buf2, 54); - if(avpriv_ac3_parse_header(&gbc, &phdr) < 0) ++ ret = av_ac3_parse_header(buf2, end - buf2, &bitstream_id, ++ &frame_size); + if (ret < 0) break; - if(buf2 + phdr->frame_size > end) - if (buf2 + frame_size > end || - av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, frame_size - 2)) ++ if(buf2 + frame_size > end) break; + if (buf[0] == 0x77 && buf[1] == 0x0B) { - av_assert0(phdr->frame_size <= sizeof(buf3)); - for(i=8; i<phdr->frame_size; i+=2) { ++ av_assert0(frame_size <= sizeof(buf3)); ++ for(i = 8; i < frame_size; i += 2) { + buf3[i ] = buf2[i+1]; + buf3[i+1] = buf2[i ]; + } ++ if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf3 + 2, frame_size - 2)) ++ break; ++ } else { ++ if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, frame_size - 2)) ++ break; + } - if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, phdr->frame_size - 2)) - break; - if (phdr->bitstream_id > 10) + if (bitstream_id > 10) codec_id = AV_CODEC_ID_EAC3; - buf2 += phdr->frame_size; + buf2 += frame_size; } max_frames = FFMAX(max_frames, frames); if(buf == p->buf) diff --cc libavformat/movenc.c index 2838286141,840190dbfa..a34987a7dc --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@@ -31,15 -31,10 +31,15 @@@ #include "avio.h" #include "isom.h" #include "avc.h" - #include "libavcodec/ac3_parser.h" ++#include "libavcodec/ac3_parser_internal.h" +#include "libavcodec/dnxhddata.h" +#include "libavcodec/flac.h" +#include "libavcodec/get_bits.h" -#include "libavcodec/bitstream.h" +#include "libavcodec/internal.h" #include "libavcodec/put_bits.h" #include "libavcodec/vc1_common.h" +#include "libavcodec/raw.h" #include "internal.h" #include "libavutil/avstring.h" #include "libavutil/intfloat.h" @@@ -310,215 -283,6 +310,216 @@@ static int mov_write_ac3_tag(AVIOContex return 11; } +struct eac3_info { + AVPacket pkt; + uint8_t ec3_done; + uint8_t num_blocks; + + /* Layout of the EC3SpecificBox */ + /* maximum bitrate */ + uint16_t data_rate; + /* number of independent substreams */ + uint8_t num_ind_sub; + struct { + /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */ + uint8_t fscod; + /* bit stream identification 5 bits */ + uint8_t bsid; + /* one bit reserved */ + /* audio service mixing (not supported yet) 1 bit */ + /* bit stream mode 3 bits */ + uint8_t bsmod; + /* audio coding mode 3 bits */ + uint8_t acmod; + /* sub woofer on 1 bit */ + uint8_t lfeon; + /* 3 bits reserved */ + /* number of dependent substreams associated with this substream 4 bits */ + uint8_t num_dep_sub; + /* channel locations of the dependent substream(s), if any, 9 bits */ + uint16_t chan_loc; + /* if there is no dependent substream, then one bit reserved instead */ + } substream[1]; /* TODO: support 8 independent substreams */ +}; + +#if CONFIG_AC3_PARSER +static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) +{ - GetBitContext gbc; + AC3HeaderInfo tmp, *hdr = &tmp; + struct eac3_info *info; + int num_blocks; + + if (!track->eac3_priv && !(track->eac3_priv = av_mallocz(sizeof(*info)))) + return AVERROR(ENOMEM); + info = track->eac3_priv; + - init_get_bits(&gbc, pkt->data, pkt->size * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) { ++ if (avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size) < 0) { + /* drop the packets until we see a good one */ + if (!track->entry) { + av_log(mov, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n"); + return 0; + } + return AVERROR_INVALIDDATA; + } + + info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000); + num_blocks = hdr->num_blocks; + + if (!info->ec3_done) { + /* AC-3 substream must be the first one */ + if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) + return AVERROR(EINVAL); + + /* this should always be the case, given that our AC-3 parser + * concatenates dependent frames to their independent parent */ + if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { + /* substream ids must be incremental */ + if (hdr->substreamid > info->num_ind_sub + 1) + return AVERROR(EINVAL); + + if (hdr->substreamid == info->num_ind_sub + 1) { + //info->num_ind_sub++; + avpriv_request_sample(track->par, "Multiple independent substreams"); + return AVERROR_PATCHWELCOME; + } else if (hdr->substreamid < info->num_ind_sub || + hdr->substreamid == 0 && info->substream[0].bsid) { + info->ec3_done = 1; + goto concatenate; + } + } + + /* fill the info needed for the "dec3" atom */ + info->substream[hdr->substreamid].fscod = hdr->sr_code; + info->substream[hdr->substreamid].bsid = hdr->bitstream_id; + info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode; + info->substream[hdr->substreamid].acmod = hdr->channel_mode; + info->substream[hdr->substreamid].lfeon = hdr->lfe_on; + + /* Parse dependent substream(s), if any */ + if (pkt->size != hdr->frame_size) { + int cumul_size = hdr->frame_size; + int parent = hdr->substreamid; + + while (cumul_size != pkt->size) { - int i; - init_get_bits(&gbc, pkt->data + cumul_size, (pkt->size - cumul_size) * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) ++ GetBitContext gbc; ++ int i, ret; ++ ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size); ++ if (ret < 0) + return AVERROR_INVALIDDATA; + if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) + return AVERROR(EINVAL); - cumul_size += hdr->frame_size; + info->substream[parent].num_dep_sub++; ++ ret /= 8; + + /* header is parsed up to lfeon, but custom channel map may be needed */ ++ init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret); + /* skip bsid */ + skip_bits(&gbc, 5); + /* skip volume control params */ + for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) { + skip_bits(&gbc, 5); // skip dialog normalization + if (get_bits1(&gbc)) { + skip_bits(&gbc, 8); // skip compression gain word + } + } + /* get the dependent stream channel map, if exists */ + if (get_bits1(&gbc)) + info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f; + else + info->substream[parent].chan_loc |= hdr->channel_mode; ++ cumul_size += hdr->frame_size; + } + } + } + +concatenate: + if (!info->num_blocks && num_blocks == 6) + return pkt->size; + else if (info->num_blocks + num_blocks > 6) + return AVERROR_INVALIDDATA; + + if (!info->num_blocks) { + int ret = av_packet_ref(&info->pkt, pkt); + if (ret < 0) + return ret; + info->num_blocks = num_blocks; + return 0; + } else { + int ret; + if ((ret = av_grow_packet(&info->pkt, pkt->size)) < 0) + return ret; + memcpy(info->pkt.data + info->pkt.size - pkt->size, pkt->data, pkt->size); + info->num_blocks += num_blocks; + info->pkt.duration += pkt->duration; + if ((ret = av_copy_packet_side_data(&info->pkt, pkt)) < 0) + return ret; + if (info->num_blocks != 6) + return 0; + av_packet_unref(pkt); + ret = av_packet_ref(pkt, &info->pkt); + if (ret < 0) + return ret; + av_packet_unref(&info->pkt); + info->num_blocks = 0; + } + + return pkt->size; +} +#endif + +static int mov_write_eac3_tag(AVIOContext *pb, MOVTrack *track) +{ + PutBitContext pbc; + uint8_t *buf; + struct eac3_info *info; + int size, i; + + if (!track->eac3_priv) + return AVERROR(EINVAL); + + info = track->eac3_priv; + size = 2 + 4 * (info->num_ind_sub + 1); + buf = av_malloc(size); + if (!buf) { + size = AVERROR(ENOMEM); + goto end; + } + + init_put_bits(&pbc, buf, size); + put_bits(&pbc, 13, info->data_rate); + put_bits(&pbc, 3, info->num_ind_sub); + for (i = 0; i <= info->num_ind_sub; i++) { + put_bits(&pbc, 2, info->substream[i].fscod); + put_bits(&pbc, 5, info->substream[i].bsid); + put_bits(&pbc, 1, 0); /* reserved */ + put_bits(&pbc, 1, 0); /* asvc */ + put_bits(&pbc, 3, info->substream[i].bsmod); + put_bits(&pbc, 3, info->substream[i].acmod); + put_bits(&pbc, 1, info->substream[i].lfeon); + put_bits(&pbc, 5, 0); /* reserved */ + put_bits(&pbc, 4, info->substream[i].num_dep_sub); + if (!info->substream[i].num_dep_sub) { + put_bits(&pbc, 1, 0); /* reserved */ + size--; + } else { + put_bits(&pbc, 9, info->substream[i].chan_loc); + } + } + flush_put_bits(&pbc); + + avio_wb32(pb, size + 8); + ffio_wfourcc(pb, "dec3"); + avio_write(pb, buf, size); + + av_free(buf); + +end: + av_packet_unref(&info->pkt); + av_freep(&track->eac3_priv); + + return size; +} + /** * This function writes extradata "as is". * Extradata must be formatted like a valid atom (with size and tag). _______________________________________________ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog