From 5e8280d177f694b29a4dce320303af0fa3a11944 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 11 Apr 2012 12:44:26 -0400 Subject: [PATCH 01/12] avutil: add better documentation for AVSampleFormat --- libavutil/samplefmt.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libavutil/samplefmt.h b/libavutil/samplefmt.h index 29a26f0b41..bb5ba5924a 100644 --- a/libavutil/samplefmt.h +++ b/libavutil/samplefmt.h @@ -22,7 +22,26 @@ #include "avutil.h" /** - * all in native-endian format + * Audio Sample Formats + * + * @par + * The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * @par + * The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * @par + * The data layout as used in av_samples_fill_arrays() and elsewhere in Libav + * (such as AVFrame in libavcodec) is as follows: + * + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. */ enum AVSampleFormat { AV_SAMPLE_FMT_NONE = -1, @@ -139,6 +158,9 @@ int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, * buffer for planar layout, or the aligned size of the buffer for all channels * for packed layout. * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * * @param[out] audio_data array to be filled with the pointer for each channel * @param[out] linesize calculated linesize, may be NULL * @param buf the pointer to a buffer containing the samples @@ -157,6 +179,9 @@ int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, uint8_t *buf, * linesize accordingly. * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * * @param[out] audio_data array to be filled with the pointer for each channel * @param[out] linesize aligned size for audio buffer(s), may be NULL * @param nb_channels number of audio channels From 6465562e130b6fcd153c2a5ca9c7bda228ee0ee3 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 15 Apr 2012 21:49:48 +0200 Subject: [PATCH 02/12] rtmp: Support 'rtmp_app', an option which overrides the name of application MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option is the name of application to connect on the RTMP server. Sometimes the URL parser cannot determine the app name automatically, so it must be given explicitly using this option (ie. -rtmp_app). Signed-off-by: Martin Storsjö --- libavformat/rtmpproto.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 76835592d3..1d27c6f8e8 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -28,6 +28,7 @@ #include "libavutil/avstring.h" #include "libavutil/intfloat.h" #include "libavutil/lfg.h" +#include "libavutil/opt.h" #include "libavutil/sha.h" #include "avformat.h" #include "internal.h" @@ -41,6 +42,8 @@ //#define DEBUG +#define APP_MAX_LENGTH 128 + /** RTMP protocol handler state */ typedef enum { STATE_START, ///< client has not done anything yet @@ -56,12 +59,13 @@ typedef enum { /** protocol handler context */ typedef struct RTMPContext { + const AVClass *class; URLContext* stream; ///< TCP stream used in interactions with RTMP server RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets int chunk_size; ///< size of the chunks RTMP packets are divided into int is_input; ///< input/output flag char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix) - char app[128]; ///< application + char *app; ///< name of application ClientState state; ///< current state int main_channel_id; ///< an additional channel ID which is used for some invocations uint8_t* flv_data; ///< buffer with data for demuxer @@ -822,6 +826,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) { RTMPContext *rt = s->priv_data; char proto[8], hostname[256], path[1024], *fname; + char *old_app; uint8_t buf[2048]; int port; int ret; @@ -847,6 +852,16 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) rt->chunk_size = 128; rt->state = STATE_HANDSHAKED; + + // Keep the application name when it has been defined by the user. + old_app = rt->app; + + rt->app = av_malloc(APP_MAX_LENGTH); + if (!rt->app) { + rtmp_close(s); + return AVERROR(ENOMEM); + } + //extract "app" part from path if (!strncmp(path, "/ondemand/", 10)) { fname = path + 10; @@ -868,6 +883,13 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) } } } + + if (old_app) { + // The name of application has been defined by the user, override it. + av_free(rt->app); + rt->app = old_app; + } + if (!strchr(fname, ':') && (!strcmp(fname + strlen(fname) - 4, ".f4v") || !strcmp(fname + strlen(fname) - 4, ".mp4"))) { @@ -1013,6 +1035,22 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) return size; } +#define OFFSET(x) offsetof(RTMPContext, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM +#define ENC AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption rtmp_options[] = { + {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + { NULL }, +}; + +static const AVClass rtmp_class = { + .class_name = "rtmp", + .item_name = av_default_item_name, + .option = rtmp_options, + .version = LIBAVUTIL_VERSION_INT, +}; + URLProtocol ff_rtmp_protocol = { .name = "rtmp", .url_open = rtmp_open, @@ -1021,4 +1059,5 @@ URLProtocol ff_rtmp_protocol = { .url_close = rtmp_close, .priv_data_size = sizeof(RTMPContext), .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class= &rtmp_class, }; From b3b175120151b9d39f05a7e24e322a70ab835138 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 15 Apr 2012 21:50:50 +0200 Subject: [PATCH 03/12] rtmp: Support 'rtmp_playpath', an option which overrides the stream identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option is the stream identifier to play or to publish. Sometimes the URL parser cannot determine the correct playpath automatically, so it must be given explicitly using this option (ie. -rtmp_playpath). Signed-off-by: Martin Storsjö --- libavformat/rtmpproto.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 1d27c6f8e8..9cdb6399fe 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -43,6 +43,7 @@ //#define DEBUG #define APP_MAX_LENGTH 128 +#define PLAYPATH_MAX_LENGTH 256 /** RTMP protocol handler state */ typedef enum { @@ -64,7 +65,7 @@ typedef struct RTMPContext { RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets int chunk_size; ///< size of the chunks RTMP packets are divided into int is_input; ///< input/output flag - char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix) + char *playpath; ///< stream identifier to play (with possible "mp4:" prefix) char *app; ///< name of application ClientState state; ///< current state int main_channel_id; ///< an additional channel ID which is used for some invocations @@ -890,14 +891,22 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) rt->app = old_app; } - if (!strchr(fname, ':') && - (!strcmp(fname + strlen(fname) - 4, ".f4v") || - !strcmp(fname + strlen(fname) - 4, ".mp4"))) { - memcpy(rt->playpath, "mp4:", 5); - } else { - rt->playpath[0] = 0; + if (!rt->playpath) { + rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH); + if (!rt->playpath) { + rtmp_close(s); + return AVERROR(ENOMEM); + } + + if (!strchr(fname, ':') && + (!strcmp(fname + strlen(fname) - 4, ".f4v") || + !strcmp(fname + strlen(fname) - 4, ".mp4"))) { + memcpy(rt->playpath, "mp4:", 5); + } else { + rt->playpath[0] = 0; + } + strncat(rt->playpath, fname, PLAYPATH_MAX_LENGTH - 5); } - strncat(rt->playpath, fname, sizeof(rt->playpath) - 5); rt->client_report_size = 1048576; rt->bytes_read = 0; @@ -1041,6 +1050,7 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) static const AVOption rtmp_options[] = { {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, + {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC}, { NULL }, }; From ca332b1d8c9d869c4dd98a6eae5e464d702948cc Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Mon, 16 Apr 2012 10:35:11 -0700 Subject: [PATCH 04/12] faac: Add .channel_layouts --- libavcodec/libfaac.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libavcodec/libfaac.c b/libavcodec/libfaac.c index bb19083142..66277949b0 100644 --- a/libavcodec/libfaac.c +++ b/libavcodec/libfaac.c @@ -29,6 +29,7 @@ #include "avcodec.h" #include "audio_frame_queue.h" #include "internal.h" +#include "libavutil/audioconvert.h" /* libfaac has an encoder delay of 1024 samples */ @@ -214,6 +215,16 @@ static const AVProfile profiles[] = { { FF_PROFILE_UNKNOWN }, }; +static const uint64_t faac_channel_layouts[] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + 0 +}; + AVCodec ff_libfaac_encoder = { .name = "libfaac", .type = AVMEDIA_TYPE_AUDIO, @@ -227,4 +238,5 @@ AVCodec ff_libfaac_encoder = { AV_SAMPLE_FMT_NONE }, .long_name = NULL_IF_CONFIG_SMALL("libfaac AAC (Advanced Audio Codec)"), .profiles = NULL_IF_CONFIG_SMALL(profiles), + .channel_layouts = faac_channel_layouts, }; From af2f655c02c69aa615eb2a06000a1aa35916967a Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Wed, 25 Jan 2012 02:51:49 +0100 Subject: [PATCH 05/12] faac: Fix multi-channel ordering Signed-off-by: Alex Converse --- libavcodec/libfaac.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libavcodec/libfaac.c b/libavcodec/libfaac.c index 66277949b0..e18e133bc7 100644 --- a/libavcodec/libfaac.c +++ b/libavcodec/libfaac.c @@ -57,6 +57,13 @@ static av_cold int Faac_encode_close(AVCodecContext *avctx) return 0; } +static const int channel_maps[][6] = { + { 2, 0, 1 }, //< C L R + { 2, 0, 1, 3 }, //< C L R Cs + { 2, 0, 1, 3, 4 }, //< C L R Ls Rs + { 2, 0, 1, 4, 5, 3 }, //< C L R Ls Rs LFE +}; + static av_cold int Faac_encode_init(AVCodecContext *avctx) { FaacAudioContext *s = avctx->priv_data; @@ -119,6 +126,9 @@ static av_cold int Faac_encode_init(AVCodecContext *avctx) } faac_cfg->outputFormat = 1; faac_cfg->inputFormat = FAAC_INPUT_16BIT; + if (avctx->channels > 2) + memcpy(faac_cfg->channel_map, channel_maps[avctx->channels-3], + avctx->channels * sizeof(int)); avctx->frame_size = samples_input / avctx->channels; From 9fb7e14635026989d9f3e157be9ff6019139b654 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Tue, 10 Apr 2012 16:27:28 -0700 Subject: [PATCH 06/12] aacdec: More robust output configuration. Save the old output configuration (if it has been used successfully) when trying a new configuration. If the new configuration fails to decode, restore the last successful configuration. --- libavcodec/aac.h | 15 ++- libavcodec/aacdec.c | 259 +++++++++++++++++++++++++++----------------- libavcodec/aacsbr.c | 12 +- 3 files changed, 173 insertions(+), 113 deletions(-) diff --git a/libavcodec/aac.h b/libavcodec/aac.h index 49def78979..1b6013e458 100644 --- a/libavcodec/aac.h +++ b/libavcodec/aac.h @@ -112,6 +112,15 @@ enum OCStatus { OC_LOCKED, ///< Output configuration locked in place }; +typedef struct { + MPEG4AudioConfig m4ac; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + int channels; + uint64_t channel_layout; + enum OCStatus status; +} OutputConfiguration; + /** * Predictor State */ @@ -254,8 +263,6 @@ typedef struct { AVCodecContext *avctx; AVFrame frame; - MPEG4AudioConfig m4ac; - int is_saved; ///< Set if elements have stored overlap from previous frame. DynamicRangeControl che_drc; @@ -263,8 +270,6 @@ typedef struct { * @name Channel element related data * @{ */ - uint8_t layout_map[MAX_ELEM_ID*4][3]; - int layout_map_tags; ChannelElement *che[4][MAX_ELEM_ID]; ChannelElement *tag_che_map[4][MAX_ELEM_ID]; int tags_mapped; @@ -299,7 +304,7 @@ typedef struct { DECLARE_ALIGNED(32, float, temp)[128]; - enum OCStatus output_configured; + OutputConfiguration oc[2]; } AACContext; #endif /* AVCODEC_AAC_H */ diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index e7c9423e4a..7cf21954c9 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -151,7 +151,7 @@ static av_cold int che_configure(AACContext *ac, if (type != TYPE_CCE) { ac->output_data[(*channels)++] = ac->che[type][id]->ch[0].ret; if (type == TYPE_CPE || - (type == TYPE_SCE && ac->m4ac.ps == 1)) { + (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) { ac->output_data[(*channels)++] = ac->che[type][id]->ch[1].ret; } } @@ -350,12 +350,34 @@ static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags) return layout; } +/** + * Save current output configuration if and only if it has been locked. + */ +static void push_output_configuration(AACContext *ac) { + if (ac->oc[1].status == OC_LOCKED) { + ac->oc[0] = ac->oc[1]; + } + ac->oc[1].status = OC_NONE; +} + +/** + * Restore the previous output configuration if and only if the current + * configuration is unlocked. + */ +static void pop_output_configuration(AACContext *ac) { + if (ac->oc[1].status != OC_LOCKED) { + ac->oc[1] = ac->oc[0]; + ac->avctx->channels = ac->oc[1].channels; + ac->avctx->channel_layout = ac->oc[1].channels; + } +} + /** * Configure output channel order based on the current program configuration element. * * @return Returns error status. 0 - OK, !0 - error */ -static av_cold int output_configure(AACContext *ac, +static int output_configure(AACContext *ac, uint8_t layout_map[MAX_ELEM_ID*4][3], int tags, int channel_config, enum OCStatus oc_type) { @@ -363,9 +385,9 @@ static av_cold int output_configure(AACContext *ac, int i, channels = 0, ret; uint64_t layout = 0; - if (ac->layout_map != layout_map) { - memcpy(ac->layout_map, layout_map, tags * sizeof(layout_map[0])); - ac->layout_map_tags = tags; + if (ac->oc[1].layout_map != layout_map) { + memcpy(ac->oc[1].layout_map, layout_map, tags * sizeof(layout_map[0])); + ac->oc[1].layout_map_tags = tags; } // Try to sniff a reasonable channel order, otherwise output the @@ -384,9 +406,9 @@ static av_cold int output_configure(AACContext *ac, } memcpy(ac->tag_che_map, ac->che, 4 * MAX_ELEM_ID * sizeof(ac->che[0][0])); - avctx->channel_layout = layout; - avctx->channels = channels; - ac->output_configured = oc_type; + avctx->channel_layout = ac->oc[1].channel_layout = layout; + avctx->channels = ac->oc[1].channels = channels; + ac->oc[1].status = oc_type; return 0; } @@ -397,7 +419,7 @@ static av_cold int output_configure(AACContext *ac, * * @return Returns error status. 0 - OK, !0 - error */ -static av_cold int set_default_channel_config(AVCodecContext *avctx, +static int set_default_channel_config(AVCodecContext *avctx, uint8_t (*layout_map)[3], int *tags, int channel_config) @@ -415,13 +437,14 @@ static av_cold int set_default_channel_config(AVCodecContext *avctx, static ChannelElement *get_che(AACContext *ac, int type, int elem_id) { // For PCE based channel configurations map the channels solely based on tags. - if (!ac->m4ac.chan_config) { + if (!ac->oc[1].m4ac.chan_config) { return ac->tag_che_map[type][elem_id]; } // Allow single CPE stereo files to be signalled with mono configuration. - if (!ac->tags_mapped && type == TYPE_CPE && ac->m4ac.chan_config == 1) { + if (!ac->tags_mapped && type == TYPE_CPE && ac->oc[1].m4ac.chan_config == 1) { uint8_t layout_map[MAX_ELEM_ID*4][3]; int layout_map_tags; + push_output_configuration(ac); if (set_default_channel_config(ac->avctx, layout_map, &layout_map_tags, 2) < 0) @@ -430,10 +453,25 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id) 2, OC_TRIAL_FRAME) < 0) return NULL; - ac->m4ac.chan_config = 2; + ac->oc[1].m4ac.chan_config = 2; + } + // And vice-versa + if (!ac->tags_mapped && type == TYPE_SCE && ac->oc[1].m4ac.chan_config == 2) { + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + push_output_configuration(ac); + + if (set_default_channel_config(ac->avctx, layout_map, &layout_map_tags, + 1) < 0) + return NULL; + if (output_configure(ac, layout_map, layout_map_tags, + 1, OC_TRIAL_FRAME) < 0) + return NULL; + + ac->oc[1].m4ac.chan_config = 1; } // For indexed channel configurations map the channels solely based on position. - switch (ac->m4ac.chan_config) { + switch (ac->oc[1].m4ac.chan_config) { case 7: if (ac->tags_mapped == 3 && type == TYPE_CPE) { ac->tags_mapped++; @@ -443,7 +481,7 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id) /* Some streams incorrectly code 5.1 audio as SCE[0] CPE[0] CPE[1] SCE[1] instead of SCE[0] CPE[0] CPE[1] LFE[0]. If we seem to have encountered such a stream, transfer the LFE[0] element to the SCE[1]'s mapping */ - if (ac->tags_mapped == tags_per_config[ac->m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) { + if (ac->tags_mapped == tags_per_config[ac->oc[1].m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) { ac->tags_mapped++; return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0]; } @@ -453,16 +491,16 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id) return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1]; } case 4: - if (ac->tags_mapped == 2 && ac->m4ac.chan_config == 4 && type == TYPE_SCE) { + if (ac->tags_mapped == 2 && ac->oc[1].m4ac.chan_config == 4 && type == TYPE_SCE) { ac->tags_mapped++; return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1]; } case 3: case 2: - if (ac->tags_mapped == (ac->m4ac.chan_config != 2) && type == TYPE_CPE) { + if (ac->tags_mapped == (ac->oc[1].m4ac.chan_config != 2) && type == TYPE_CPE) { ac->tags_mapped++; return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][0]; - } else if (ac->m4ac.chan_config == 2) { + } else if (ac->oc[1].m4ac.chan_config == 2) { return NULL; } case 1: @@ -758,10 +796,10 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) float output_scale_factor; ac->avctx = avctx; - ac->m4ac.sample_rate = avctx->sample_rate; + ac->oc[1].m4ac.sample_rate = avctx->sample_rate; if (avctx->extradata_size > 0) { - if (decode_audio_specific_config(ac, ac->avctx, &ac->m4ac, + if (decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, avctx->extradata, avctx->extradata_size*8, 1) < 0) return -1; @@ -771,10 +809,10 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) int layout_map_tags; sr = sample_rate_idx(avctx->sample_rate); - ac->m4ac.sampling_index = sr; - ac->m4ac.channels = avctx->channels; - ac->m4ac.sbr = -1; - ac->m4ac.ps = -1; + ac->oc[1].m4ac.sampling_index = sr; + ac->oc[1].m4ac.channels = avctx->channels; + ac->oc[1].m4ac.sbr = -1; + ac->oc[1].m4ac.ps = -1; for (i = 0; i < FF_ARRAY_ELEMS(ff_mpeg4audio_channels); i++) if (ff_mpeg4audio_channels[i] == avctx->channels) @@ -782,14 +820,14 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) if (i == FF_ARRAY_ELEMS(ff_mpeg4audio_channels)) { i = 0; } - ac->m4ac.chan_config = i; + ac->oc[1].m4ac.chan_config = i; - if (ac->m4ac.chan_config) { + if (ac->oc[1].m4ac.chan_config) { int ret = set_default_channel_config(avctx, layout_map, - &layout_map_tags, ac->m4ac.chan_config); + &layout_map_tags, ac->oc[1].m4ac.chan_config); if (!ret) output_configure(ac, layout_map, layout_map_tags, - ac->m4ac.chan_config, OC_GLOBAL_HDR); + ac->oc[1].m4ac.chan_config, OC_GLOBAL_HDR); else if (avctx->err_recognition & AV_EF_EXPLODE) return AVERROR_INVALIDDATA; } @@ -877,7 +915,7 @@ static int decode_prediction(AACContext *ac, IndividualChannelStream *ics, return -1; } } - for (sfb = 0; sfb < FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[ac->m4ac.sampling_index]); sfb++) { + for (sfb = 0; sfb < FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index]); sfb++) { ics->prediction_used[sfb] = get_bits1(gb); } return 0; @@ -925,24 +963,24 @@ static int decode_ics_info(AACContext *ac, IndividualChannelStream *ics, } } ics->num_windows = 8; - ics->swb_offset = ff_swb_offset_128[ac->m4ac.sampling_index]; - ics->num_swb = ff_aac_num_swb_128[ac->m4ac.sampling_index]; - ics->tns_max_bands = ff_tns_max_bands_128[ac->m4ac.sampling_index]; + ics->swb_offset = ff_swb_offset_128[ac->oc[1].m4ac.sampling_index]; + ics->num_swb = ff_aac_num_swb_128[ac->oc[1].m4ac.sampling_index]; + ics->tns_max_bands = ff_tns_max_bands_128[ac->oc[1].m4ac.sampling_index]; ics->predictor_present = 0; } else { ics->max_sfb = get_bits(gb, 6); ics->num_windows = 1; - ics->swb_offset = ff_swb_offset_1024[ac->m4ac.sampling_index]; - ics->num_swb = ff_aac_num_swb_1024[ac->m4ac.sampling_index]; - ics->tns_max_bands = ff_tns_max_bands_1024[ac->m4ac.sampling_index]; + ics->swb_offset = ff_swb_offset_1024[ac->oc[1].m4ac.sampling_index]; + ics->num_swb = ff_aac_num_swb_1024[ac->oc[1].m4ac.sampling_index]; + ics->tns_max_bands = ff_tns_max_bands_1024[ac->oc[1].m4ac.sampling_index]; ics->predictor_present = get_bits1(gb); ics->predictor_reset_group = 0; if (ics->predictor_present) { - if (ac->m4ac.object_type == AOT_AAC_MAIN) { + if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN) { if (decode_prediction(ac, ics, gb)) { return AVERROR_INVALIDDATA; } - } else if (ac->m4ac.object_type == AOT_AAC_LC) { + } else if (ac->oc[1].m4ac.object_type == AOT_AAC_LC) { av_log(ac->avctx, AV_LOG_ERROR, "Prediction is not allowed in AAC-LC.\n"); return AVERROR_INVALIDDATA; } else { @@ -1113,7 +1151,7 @@ static int decode_tns(AACContext *ac, TemporalNoiseShaping *tns, { int w, filt, i, coef_len, coef_res, coef_compress; const int is8 = ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE; - const int tns_max_order = is8 ? 7 : ac->m4ac.object_type == AOT_AAC_MAIN ? 20 : 12; + const int tns_max_order = is8 ? 7 : ac->oc[1].m4ac.object_type == AOT_AAC_MAIN ? 20 : 12; for (w = 0; w < ics->num_windows; w++) { if ((tns->n_filt[w] = get_bits(gb, 2 - is8))) { coef_res = get_bits1(gb); @@ -1524,7 +1562,7 @@ static void apply_prediction(AACContext *ac, SingleChannelElement *sce) } if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { - for (sfb = 0; sfb < ff_aac_pred_sfb_max[ac->m4ac.sampling_index]; sfb++) { + for (sfb = 0; sfb < ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index]; sfb++) { for (k = sce->ics.swb_offset[sfb]; k < sce->ics.swb_offset[sfb + 1]; k++) { predict(&sce->predictor_state[k], &sce->coeffs[k], sce->ics.predictor_present && sce->ics.prediction_used[sfb]); @@ -1593,7 +1631,7 @@ static int decode_ics(AACContext *ac, SingleChannelElement *sce, if (decode_spectrum_and_dequant(ac, out, gb, sce->sf, pulse_present, &pulse, ics, sce->band_type) < 0) return -1; - if (ac->m4ac.object_type == AOT_AAC_MAIN && !common_window) + if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN && !common_window) apply_prediction(ac, sce); return 0; @@ -1683,7 +1721,7 @@ static int decode_cpe(AACContext *ac, GetBitContext *gb, ChannelElement *cpe) i = cpe->ch[1].ics.use_kb_window[0]; cpe->ch[1].ics = cpe->ch[0].ics; cpe->ch[1].ics.use_kb_window[1] = i; - if (cpe->ch[1].ics.predictor_present && (ac->m4ac.object_type != AOT_AAC_MAIN)) + if (cpe->ch[1].ics.predictor_present && (ac->oc[1].m4ac.object_type != AOT_AAC_MAIN)) if ((cpe->ch[1].ics.ltp.present = get_bits(gb, 1))) decode_ltp(ac, &cpe->ch[1].ics.ltp, gb, cpe->ch[1].ics.max_sfb); ms_present = get_bits(gb, 2); @@ -1701,7 +1739,7 @@ static int decode_cpe(AACContext *ac, GetBitContext *gb, ChannelElement *cpe) if (common_window) { if (ms_present) apply_mid_side_stereo(ac, cpe); - if (ac->m4ac.object_type == AOT_AAC_MAIN) { + if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN) { apply_prediction(ac, &cpe->ch[0]); apply_prediction(ac, &cpe->ch[1]); } @@ -1882,21 +1920,21 @@ static int decode_extension_payload(AACContext *ac, GetBitContext *gb, int cnt, if (!che) { av_log(ac->avctx, AV_LOG_ERROR, "SBR was found before the first channel element.\n"); return res; - } else if (!ac->m4ac.sbr) { + } else if (!ac->oc[1].m4ac.sbr) { av_log(ac->avctx, AV_LOG_ERROR, "SBR signaled to be not-present but was found in the bitstream.\n"); skip_bits_long(gb, 8 * cnt - 4); return res; - } else if (ac->m4ac.sbr == -1 && ac->output_configured == OC_LOCKED) { + } else if (ac->oc[1].m4ac.sbr == -1 && ac->oc[1].status == OC_LOCKED) { av_log(ac->avctx, AV_LOG_ERROR, "Implicit SBR was found with a first occurrence after the first frame.\n"); skip_bits_long(gb, 8 * cnt - 4); return res; - } else if (ac->m4ac.ps == -1 && ac->output_configured < OC_LOCKED && ac->avctx->channels == 1) { - ac->m4ac.sbr = 1; - ac->m4ac.ps = 1; - output_configure(ac, ac->layout_map, ac->layout_map_tags, - ac->m4ac.chan_config, ac->output_configured); + } else if (ac->oc[1].m4ac.ps == -1 && ac->oc[1].status < OC_LOCKED && ac->avctx->channels == 1) { + ac->oc[1].m4ac.sbr = 1; + ac->oc[1].m4ac.ps = 1; + output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, + ac->oc[1].m4ac.chan_config, ac->oc[1].status); } else { - ac->m4ac.sbr = 1; + ac->oc[1].m4ac.sbr = 1; } res = ff_decode_sbr_extension(ac, &che->sbr, gb, crc_flag, cnt, elem_type); break; @@ -2142,7 +2180,7 @@ static void apply_dependent_coupling(AACContext *ac, float *dest = target->coeffs; const float *src = cce->ch[0].coeffs; int g, i, group, k, idx = 0; - if (ac->m4ac.object_type == AOT_AAC_LTP) { + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { av_log(ac->avctx, AV_LOG_ERROR, "Dependent coupling is not supported together with LTP\n"); return; @@ -2177,7 +2215,7 @@ static void apply_independent_coupling(AACContext *ac, const float gain = cce->coup.gain[index][0]; const float *src = cce->ch[0].ret; float *dest = target->ret; - const int len = 1024 << (ac->m4ac.sbr == 1); + const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); for (i = 0; i < len; i++) dest[i] += gain * src[i]; @@ -2230,7 +2268,7 @@ static void spectral_to_sample(AACContext *ac) if (che) { if (type <= TYPE_CPE) apply_channel_coupling(ac, che, type, i, BEFORE_TNS, apply_dependent_coupling); - if (ac->m4ac.object_type == AOT_AAC_LTP) { + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { if (che->ch[0].ics.predictor_present) { if (che->ch[0].ics.ltp.present) apply_ltp(ac, &che->ch[0]); @@ -2246,14 +2284,14 @@ static void spectral_to_sample(AACContext *ac) apply_channel_coupling(ac, che, type, i, BETWEEN_TNS_AND_IMDCT, apply_dependent_coupling); if (type != TYPE_CCE || che->coup.coupling_point == AFTER_IMDCT) { imdct_and_windowing(ac, &che->ch[0]); - if (ac->m4ac.object_type == AOT_AAC_LTP) + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) update_ltp(ac, &che->ch[0]); if (type == TYPE_CPE) { imdct_and_windowing(ac, &che->ch[1]); - if (ac->m4ac.object_type == AOT_AAC_LTP) + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) update_ltp(ac, &che->ch[1]); } - if (ac->m4ac.sbr > 0) { + if (ac->oc[1].m4ac.sbr > 0) { ff_sbr_apply(ac, &che->sbr, type, che->ch[0].ret, che->ch[1].ret); } } @@ -2273,35 +2311,34 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb) size = avpriv_aac_parse_header(gb, &hdr_info); if (size > 0) { + if (hdr_info.num_aac_frames != 1) { + av_log_missing_feature(ac->avctx, "More than one AAC RDB per ADTS frame is", 0); + return -1; + } + push_output_configuration(ac); if (hdr_info.chan_config) { - ac->m4ac.chan_config = hdr_info.chan_config; + ac->oc[1].m4ac.chan_config = hdr_info.chan_config; if (set_default_channel_config(ac->avctx, layout_map, &layout_map_tags, hdr_info.chan_config)) return -7; if (output_configure(ac, layout_map, layout_map_tags, hdr_info.chan_config, - FFMAX(ac->output_configured, OC_TRIAL_FRAME))) + FFMAX(ac->oc[1].status, OC_TRIAL_FRAME))) return -7; - } else if (ac->output_configured != OC_LOCKED) { - ac->m4ac.chan_config = 0; - ac->output_configured = OC_NONE; - } - if (ac->output_configured != OC_LOCKED) { - ac->m4ac.sbr = -1; - ac->m4ac.ps = -1; - ac->m4ac.sample_rate = hdr_info.sample_rate; - ac->m4ac.sampling_index = hdr_info.sampling_index; - ac->m4ac.object_type = hdr_info.object_type; - } - if (!ac->avctx->sample_rate) - ac->avctx->sample_rate = hdr_info.sample_rate; - if (hdr_info.num_aac_frames == 1) { - if (!hdr_info.crc_absent) - skip_bits(gb, 16); } else { - av_log_missing_feature(ac->avctx, "More than one AAC RDB per ADTS frame is", 0); - return -1; + ac->oc[1].m4ac.chan_config = 0; } + ac->oc[1].m4ac.sample_rate = hdr_info.sample_rate; + ac->oc[1].m4ac.sampling_index = hdr_info.sampling_index; + ac->oc[1].m4ac.object_type = hdr_info.object_type; + if (ac->oc[0].status != OC_LOCKED || + ac->oc[0].m4ac.chan_config != hdr_info.chan_config || + ac->oc[0].m4ac.sample_rate != hdr_info.sample_rate) { + ac->oc[1].m4ac.sbr = -1; + ac->oc[1].m4ac.ps = -1; + } + if (!hdr_info.crc_absent) + skip_bits(gb, 16); } return size; } @@ -2313,16 +2350,18 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, ChannelElement *che = NULL, *che_prev = NULL; enum RawDataBlockType elem_type, elem_type_prev = TYPE_END; int err, elem_id; - int samples = 0, multiplier, audio_found = 0; + int samples = 0, multiplier, audio_found = 0, pce_found = 0; if (show_bits(gb, 12) == 0xfff) { if (parse_adts_frame_header(ac, gb) < 0) { av_log(avctx, AV_LOG_ERROR, "Error decoding AAC frame header.\n"); - return -1; + err = -1; + goto fail; } - if (ac->m4ac.sampling_index > 12) { - av_log(ac->avctx, AV_LOG_ERROR, "invalid sampling rate index %d\n", ac->m4ac.sampling_index); - return -1; + if (ac->oc[1].m4ac.sampling_index > 12) { + av_log(ac->avctx, AV_LOG_ERROR, "invalid sampling rate index %d\n", ac->oc[1].m4ac.sampling_index); + err = -1; + goto fail; } } @@ -2335,7 +2374,8 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, if (!(che=get_che(ac, elem_type, elem_id))) { av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n", elem_type, elem_id); - return -1; + err = -1; + goto fail; } samples = 1024; } @@ -2368,16 +2408,20 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, case TYPE_PCE: { uint8_t layout_map[MAX_ELEM_ID*4][3]; int tags; - tags = decode_pce(avctx, &ac->m4ac, layout_map, gb); + push_output_configuration(ac); + tags = decode_pce(avctx, &ac->oc[1].m4ac, layout_map, gb); if (tags < 0) { err = tags; break; } - if (ac->output_configured > OC_TRIAL_PCE) + if (pce_found) { av_log(avctx, AV_LOG_ERROR, "Not evaluating a further program_config_element as this construct is dubious at best.\n"); - else + pop_output_configuration(ac); + } else { err = output_configure(ac, layout_map, tags, 0, OC_TRIAL_PCE); + pce_found = 1; + } break; } @@ -2386,7 +2430,8 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, elem_id += get_bits(gb, 8) - 1; if (get_bits_left(gb) < 8 * elem_id) { av_log(avctx, AV_LOG_ERROR, overread_err); - return -1; + err = -1; + goto fail; } while (elem_id > 0) elem_id -= decode_extension_payload(ac, gb, elem_id, che_prev, elem_type_prev); @@ -2402,29 +2447,27 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, elem_type_prev = elem_type; if (err) - return err; + goto fail; if (get_bits_left(gb) < 3) { av_log(avctx, AV_LOG_ERROR, overread_err); - return -1; + err = -1; + goto fail; } } spectral_to_sample(ac); - multiplier = (ac->m4ac.sbr == 1) ? ac->m4ac.ext_sample_rate > ac->m4ac.sample_rate : 0; + multiplier = (ac->oc[1].m4ac.sbr == 1) ? ac->oc[1].m4ac.ext_sample_rate > ac->oc[1].m4ac.sample_rate : 0; samples <<= multiplier; - if (ac->output_configured < OC_LOCKED) { - avctx->sample_rate = ac->m4ac.sample_rate << multiplier; - avctx->frame_size = samples; - } if (samples) { /* get output buffer */ ac->frame.nb_samples = samples; if ((err = avctx->get_buffer(avctx, &ac->frame)) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); - return err; + err = -1; + goto fail; } if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) @@ -2440,10 +2483,16 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, } *got_frame_ptr = !!samples; - if (ac->output_configured && audio_found) - ac->output_configured = OC_LOCKED; + if (ac->oc[1].status && audio_found) { + avctx->sample_rate = ac->oc[1].m4ac.sample_rate << multiplier; + avctx->frame_size = samples; + ac->oc[1].status = OC_LOCKED; + } return 0; +fail: + pop_output_configuration(ac); + return err; } static int aac_decode_frame(AVCodecContext *avctx, void *data, @@ -2469,10 +2518,13 @@ static int aac_decode_frame(AVCodecContext *avctx, void *data, return AVERROR(ENOMEM); avctx->extradata_size = new_extradata_size; memcpy(avctx->extradata, new_extradata, new_extradata_size); - if (decode_audio_specific_config(ac, ac->avctx, &ac->m4ac, + push_output_configuration(ac); + if (decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, avctx->extradata, - avctx->extradata_size*8, 1) < 0) + avctx->extradata_size*8, 1) < 0) { + pop_output_configuration(ac); return AVERROR_INVALIDDATA; + } } init_get_bits(&gb, buf, buf_size * 8); @@ -2532,7 +2584,7 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, { AACContext *ac = &latmctx->aac_ctx; AVCodecContext *avctx = ac->avctx; - MPEG4AudioConfig m4ac = {0}; + MPEG4AudioConfig m4ac = { 0 }; int config_start_bit = get_bits_count(gb); int sync_extension = 0; int bits_consumed, esize; @@ -2557,8 +2609,8 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, if (bits_consumed < 0) return AVERROR_INVALIDDATA; - if (ac->m4ac.sample_rate != m4ac.sample_rate || - ac->m4ac.chan_config != m4ac.chan_config) { + if (ac->oc[1].m4ac.sample_rate != m4ac.sample_rate || + ac->oc[1].m4ac.chan_config != m4ac.chan_config) { av_log(avctx, AV_LOG_INFO, "audio config changed\n"); latmctx->initialized = 0; @@ -2739,10 +2791,13 @@ static int latm_decode_frame(AVCodecContext *avctx, void *out, *got_frame_ptr = 0; return avpkt->size; } else { + push_output_configuration(&latmctx->aac_ctx); if ((err = decode_audio_specific_config( - &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.m4ac, - avctx->extradata, avctx->extradata_size*8, 1)) < 0) + &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.oc[1].m4ac, + avctx->extradata, avctx->extradata_size*8, 1)) < 0) { + pop_output_configuration(&latmctx->aac_ctx); return err; + } latmctx->initialized = 1; } } diff --git a/libavcodec/aacsbr.c b/libavcodec/aacsbr.c index c71cfa00e1..5eca1151ff 100644 --- a/libavcodec/aacsbr.c +++ b/libavcodec/aacsbr.c @@ -914,7 +914,7 @@ static void read_sbr_extension(AACContext *ac, SpectralBandReplication *sbr, { switch (bs_extension_id) { case EXTENSION_ID_PS: - if (!ac->m4ac.ps) { + if (!ac->oc[1].m4ac.ps) { av_log(ac->avctx, AV_LOG_ERROR, "Parametric Stereo signaled to be not-present but was found in the bitstream.\n"); skip_bits_long(gb, *num_bits_left); // bs_fill_bits *num_bits_left = 0; @@ -1071,9 +1071,9 @@ int ff_decode_sbr_extension(AACContext *ac, SpectralBandReplication *sbr, sbr->reset = 0; if (!sbr->sample_rate) - sbr->sample_rate = 2 * ac->m4ac.sample_rate; //TODO use the nominal sample rate for arbitrary sample rate support - if (!ac->m4ac.ext_sample_rate) - ac->m4ac.ext_sample_rate = 2 * ac->m4ac.sample_rate; + sbr->sample_rate = 2 * ac->oc[1].m4ac.sample_rate; //TODO use the nominal sample rate for arbitrary sample rate support + if (!ac->oc[1].m4ac.ext_sample_rate) + ac->oc[1].m4ac.ext_sample_rate = 2 * ac->oc[1].m4ac.sample_rate; if (crc) { skip_bits(gb, 10); // bs_sbr_crc_bits; TODO - implement CRC check @@ -1648,7 +1648,7 @@ static void sbr_hf_assemble(float Y1[38][64][2], void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac, float* L, float* R) { - int downsampled = ac->m4ac.ext_sample_rate < sbr->sample_rate; + int downsampled = ac->oc[1].m4ac.ext_sample_rate < sbr->sample_rate; int ch; int nch = (id_aac == TYPE_CPE) ? 2 : 1; int err; @@ -1695,7 +1695,7 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac, sbr->X_low, ch); } - if (ac->m4ac.ps == 1) { + if (ac->oc[1].m4ac.ps == 1) { if (sbr->ps.start) { ff_ps_apply(ac->avctx, &sbr->ps, sbr->X[0], sbr->X[1], sbr->kx[1] + sbr->m[1]); } else { From 6943fb47d3bd0bd46734cdd762ab2c4ee89b0a22 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Sun, 15 Apr 2012 23:08:45 -0700 Subject: [PATCH 07/12] avplay: update get_buffer to be inline with avconv The buffer must have its dimension, pixel format and aspect ratio set. --- avplay.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/avplay.c b/avplay.c index a11f952402..e9388fd4b8 100644 --- a/avplay.c +++ b/avplay.c @@ -1564,6 +1564,10 @@ static int input_get_buffer(AVCodecContext *codec, AVFrame *pic) pic->opaque = ref; pic->type = FF_BUFFER_TYPE_USER; pic->reordered_opaque = codec->reordered_opaque; + pic->width = codec->width; + pic->height = codec->height; + pic->format = codec->pix_fmt; + pic->sample_aspect_ratio = codec->sample_aspect_ratio; if (codec->pkt) pic->pkt_pts = codec->pkt->pts; else pic->pkt_pts = AV_NOPTS_VALUE; return 0; From b1041f80489b3fe428ef586e6d631fda40bef80e Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Mon, 16 Apr 2012 12:51:24 -0400 Subject: [PATCH 08/12] avconv: only set the "channels" option when it exists for the specified input format This allows the user to specify an input channel layout without avconv aborting because the "channels" option was not found. --- avconv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/avconv.c b/avconv.c index 347f80493d..48b4c6b70b 100644 --- a/avconv.c +++ b/avconv.c @@ -3627,8 +3627,16 @@ static int opt_input_file(OptionsContext *o, const char *opt, const char *filena av_dict_set(&format_opts, "sample_rate", buf, 0); } if (o->nb_audio_channels) { - snprintf(buf, sizeof(buf), "%d", o->audio_channels[o->nb_audio_channels - 1].u.i); - av_dict_set(&format_opts, "channels", buf, 0); + /* because we set audio_channels based on both the "ac" and + * "channel_layout" options, we need to check that the specified + * demuxer actually has the "channels" option before setting it */ + if (file_iformat && file_iformat->priv_class && + av_opt_find(&file_iformat->priv_class, "channels", NULL, 0, + AV_OPT_SEARCH_FAKE_OBJ)) { + snprintf(buf, sizeof(buf), "%d", + o->audio_channels[o->nb_audio_channels - 1].u.i); + av_dict_set(&format_opts, "channels", buf, 0); + } } if (o->nb_frame_rates) { av_dict_set(&format_opts, "framerate", o->frame_rates[o->nb_frame_rates - 1].u.str, 0); From 8099fc763bb071ba56e3de49a2104c57985fa3d1 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Mon, 16 Apr 2012 12:14:25 -0400 Subject: [PATCH 09/12] riff: use bps instead of bits_per_coded_sample in the WAVEFORMATEXTENSIBLE header This matches the value for the plain WAVEFORMATEX header. Also fixes stream copy to WAVE for non-16-bit raw pcm. --- libavformat/riff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/riff.c b/libavformat/riff.c index 2b6165e990..8a913452a7 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -482,7 +482,7 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc) if(waveformatextensible) { /* write WAVEFORMATEXTENSIBLE extensions */ hdrsize += 22; avio_wl16(pb, riff_extradata - riff_extradata_start + 22); /* 22 is WAVEFORMATEXTENSIBLE size */ - avio_wl16(pb, enc->bits_per_coded_sample); /* ValidBitsPerSample || SamplesPerBlock || Reserved */ + avio_wl16(pb, bps); /* ValidBitsPerSample || SamplesPerBlock || Reserved */ avio_wl32(pb, enc->channel_layout); /* dwChannelMask */ avio_wl32(pb, enc->codec_tag); /* GUID + next 3 */ avio_wl32(pb, 0x00100000); From 83632cbb1111f56cb3987c6c56b63dbd8b3fdce1 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sun, 15 Apr 2012 08:48:43 +0200 Subject: [PATCH 10/12] proresenc: multithreaded quantiser search --- libavcodec/proresenc.c | 167 +++++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 63 deletions(-) diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c index ca52f5db31..bee49ee60a 100644 --- a/libavcodec/proresenc.c +++ b/libavcodec/proresenc.c @@ -166,6 +166,13 @@ struct TrellisNode { #define MAX_STORED_Q 16 +typedef struct ProresThreadData { + DECLARE_ALIGNED(16, DCTELEM, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; + DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16]; + int16_t custom_q[64]; + struct TrellisNode *nodes; +} ProresThreadData; + typedef struct ProresContext { AVClass *class; DECLARE_ALIGNED(16, DCTELEM, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; @@ -194,13 +201,14 @@ typedef struct ProresContext { int profile; const struct prores_profile *profile_info; - struct TrellisNode *nodes; int *slice_q; + + ProresThreadData *tdata; } ProresContext; static void get_slice_data(ProresContext *ctx, const uint16_t *src, int linesize, int x, int y, int w, int h, - DCTELEM *blocks, + DCTELEM *blocks, uint16_t *emu_buf, int mbs_per_slice, int blocks_per_mb, int is_chroma) { const uint16_t *esrc; @@ -220,24 +228,24 @@ static void get_slice_data(ProresContext *ctx, const uint16_t *src, } else { int bw, bh, pix; - esrc = ctx->emu_buf; - elinesize = 16 * sizeof(*ctx->emu_buf); + esrc = emu_buf; + elinesize = 16 * sizeof(*emu_buf); bw = FFMIN(w - x, mb_width); bh = FFMIN(h - y, 16); for (j = 0; j < bh; j++) { - memcpy(ctx->emu_buf + j * 16, + memcpy(emu_buf + j * 16, (const uint8_t*)src + j * linesize, bw * sizeof(*src)); - pix = ctx->emu_buf[j * 16 + bw - 1]; + pix = emu_buf[j * 16 + bw - 1]; for (k = bw; k < mb_width; k++) - ctx->emu_buf[j * 16 + k] = pix; + emu_buf[j * 16 + k] = pix; } for (; j < 16; j++) - memcpy(ctx->emu_buf + j * 16, - ctx->emu_buf + (bh - 1) * 16, - mb_width * sizeof(*ctx->emu_buf)); + memcpy(emu_buf + j * 16, + emu_buf + (bh - 1) * 16, + mb_width * sizeof(*emu_buf)); } if (!is_chroma) { ctx->dsp.fdct(esrc, elinesize, blocks); @@ -427,7 +435,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, src = (const uint16_t*)(pic->data[i] + yp * pic->linesize[i]) + xp; get_slice_data(ctx, src, pic->linesize[i], xp, yp, - pwidth, avctx->height, ctx->blocks[0], + pwidth, avctx->height, ctx->blocks[0], ctx->emu_buf, mbs_per_slice, num_cblocks, is_chroma); sizes[i] = encode_slice_plane(ctx, pb, src, pic->linesize[i], mbs_per_slice, ctx->blocks[0], @@ -531,22 +539,23 @@ static int estimate_slice_plane(ProresContext *ctx, int *error, int plane, const uint16_t *src, int linesize, int mbs_per_slice, int blocks_per_mb, int plane_size_factor, - const int16_t *qmat) + const int16_t *qmat, ProresThreadData *td) { int blocks_per_slice; int bits; blocks_per_slice = mbs_per_slice * blocks_per_mb; - bits = estimate_dcs(error, ctx->blocks[plane], blocks_per_slice, qmat[0]); - bits += estimate_acs(error, ctx->blocks[plane], blocks_per_slice, + bits = estimate_dcs(error, td->blocks[plane], blocks_per_slice, qmat[0]); + bits += estimate_acs(error, td->blocks[plane], blocks_per_slice, plane_size_factor, ctx->scantable.permutated, qmat); return FFALIGN(bits, 8); } static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, - int trellis_node, int x, int y, int mbs_per_slice) + int trellis_node, int x, int y, int mbs_per_slice, + ProresThreadData *td) { ProresContext *ctx = avctx->priv_data; int i, q, pq, xp, yp; @@ -583,13 +592,13 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, src = (const uint16_t*)(pic->data[i] + yp * pic->linesize[i]) + xp; get_slice_data(ctx, src, pic->linesize[i], xp, yp, - pwidth, avctx->height, ctx->blocks[i], + pwidth, avctx->height, td->blocks[i], td->emu_buf, mbs_per_slice, num_cblocks[i], is_chroma[i]); } for (q = min_quant; q < max_quant + 2; q++) { - ctx->nodes[trellis_node + q].prev_node = -1; - ctx->nodes[trellis_node + q].quant = q; + td->nodes[trellis_node + q].prev_node = -1; + td->nodes[trellis_node + q].quant = q; } // todo: maybe perform coarser quantising to fit into frame size when needed @@ -601,7 +610,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, src, pic->linesize[i], mbs_per_slice, num_cblocks[i], plane_factor[i], - ctx->quants[q]); + ctx->quants[q], td); } if (bits > 65000 * 8) { error = SCORE_LIMIT; @@ -621,7 +630,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, if (q < MAX_STORED_Q) { qmat = ctx->quants[q]; } else { - qmat = ctx->custom_q; + qmat = td->custom_q; for (i = 0; i < 64; i++) qmat[i] = ctx->quant_mat[i] * q; } @@ -630,7 +639,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, src, pic->linesize[i], mbs_per_slice, num_cblocks[i], plane_factor[i], - qmat); + qmat, td); } if (bits <= ctx->bits_per_mb * mbs_per_slice) break; @@ -640,7 +649,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, slice_score[max_quant + 1] = error; overquant = q; } - ctx->nodes[trellis_node + max_quant + 1].quant = overquant; + td->nodes[trellis_node + max_quant + 1].quant = overquant; bits_limit = mbs * ctx->bits_per_mb; for (pq = min_quant; pq < max_quant + 2; pq++) { @@ -649,30 +658,30 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, for (q = min_quant; q < max_quant + 2; q++) { cur = trellis_node + q; - bits = ctx->nodes[prev].bits + slice_bits[q]; + bits = td->nodes[prev].bits + slice_bits[q]; error = slice_score[q]; if (bits > bits_limit) error = SCORE_LIMIT; - if (ctx->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT) - new_score = ctx->nodes[prev].score + error; + if (td->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT) + new_score = td->nodes[prev].score + error; else new_score = SCORE_LIMIT; - if (ctx->nodes[cur].prev_node == -1 || - ctx->nodes[cur].score >= new_score) { + if (td->nodes[cur].prev_node == -1 || + td->nodes[cur].score >= new_score) { - ctx->nodes[cur].bits = bits; - ctx->nodes[cur].score = new_score; - ctx->nodes[cur].prev_node = prev; + td->nodes[cur].bits = bits; + td->nodes[cur].score = new_score; + td->nodes[cur].prev_node = prev; } } } - error = ctx->nodes[trellis_node + min_quant].score; + error = td->nodes[trellis_node + min_quant].score; pq = trellis_node + min_quant; for (q = min_quant + 1; q < max_quant + 2; q++) { - if (ctx->nodes[trellis_node + q].score <= error) { - error = ctx->nodes[trellis_node + q].score; + if (td->nodes[trellis_node + q].score <= error) { + error = td->nodes[trellis_node + q].score; pq = trellis_node + q; } } @@ -680,6 +689,30 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, return pq; } +static int find_quant_thread(AVCodecContext *avctx, void *arg, + int jobnr, int threadnr) +{ + ProresContext *ctx = avctx->priv_data; + ProresThreadData *td = ctx->tdata + threadnr; + int mbs_per_slice = ctx->mbs_per_slice; + int x, y = jobnr, mb, q = 0; + + for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) { + while (ctx->mb_width - x < mbs_per_slice) + mbs_per_slice >>= 1; + q = find_slice_quant(avctx, avctx->coded_frame, + (mb + 1) * TRELLIS_WIDTH, x, y, + mbs_per_slice, td); + } + + for (x = ctx->slices_width - 1; x >= 0; x--) { + ctx->slice_q[x + y * ctx->slices_width] = td->nodes[q].quant; + q = td->nodes[q].prev_node; + } + + return 0; +} + static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic, int *got_packet) { @@ -751,25 +784,18 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, buf += ctx->num_slices * 2; // slices + if (!ctx->force_quant) { + ret = avctx->execute2(avctx, find_quant_thread, NULL, NULL, + ctx->mb_height); + if (ret) + return ret; + } + for (y = 0; y < ctx->mb_height; y++) { - mbs_per_slice = ctx->mbs_per_slice; - if (!ctx->force_quant) { - for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) { - while (ctx->mb_width - x < mbs_per_slice) - mbs_per_slice >>= 1; - q = find_slice_quant(avctx, pic, (mb + 1) * TRELLIS_WIDTH, x, y, - mbs_per_slice); - } - - for (x = ctx->slices_width - 1; x >= 0; x--) { - ctx->slice_q[x] = ctx->nodes[q].quant; - q = ctx->nodes[q].prev_node; - } - } - mbs_per_slice = ctx->mbs_per_slice; for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) { - q = ctx->force_quant ? ctx->force_quant : ctx->slice_q[mb]; + q = ctx->force_quant ? ctx->force_quant + : ctx->slice_q[mb + y * ctx->slices_width]; while (ctx->mb_width - x < mbs_per_slice) mbs_per_slice >>= 1; @@ -807,13 +833,18 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, static av_cold int encode_close(AVCodecContext *avctx) { ProresContext *ctx = avctx->priv_data; + int i; if (avctx->coded_frame->data[0]) avctx->release_buffer(avctx, avctx->coded_frame); av_freep(&avctx->coded_frame); - av_freep(&ctx->nodes); + if (ctx->tdata) { + for (i = 0; i < avctx->thread_count; i++) + av_free(ctx->tdata[i].nodes); + } + av_freep(&ctx->tdata); av_freep(&ctx->slice_q); return 0; @@ -883,23 +914,32 @@ static av_cold int encode_init(AVCodecContext *avctx) ctx->quants[i][j] = ctx->quant_mat[j] * i; } - ctx->nodes = av_malloc((ctx->slices_width + 1) * TRELLIS_WIDTH - * sizeof(*ctx->nodes)); - if (!ctx->nodes) { - encode_close(avctx); - return AVERROR(ENOMEM); - } - for (i = min_quant; i < max_quant + 2; i++) { - ctx->nodes[i].prev_node = -1; - ctx->nodes[i].bits = 0; - ctx->nodes[i].score = 0; - } - - ctx->slice_q = av_malloc(ctx->slices_width * sizeof(*ctx->slice_q)); + ctx->slice_q = av_malloc(ctx->num_slices * sizeof(*ctx->slice_q)); if (!ctx->slice_q) { encode_close(avctx); return AVERROR(ENOMEM); } + + ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata)); + if (!ctx->tdata) { + encode_close(avctx); + return AVERROR(ENOMEM); + } + + for (j = 0; j < avctx->thread_count; j++) { + ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1) + * TRELLIS_WIDTH + * sizeof(*ctx->tdata->nodes)); + if (!ctx->tdata[j].nodes) { + encode_close(avctx); + return AVERROR(ENOMEM); + } + for (i = min_quant; i < max_quant + 2; i++) { + ctx->tdata[j].nodes[i].prev_node = -1; + ctx->tdata[j].nodes[i].bits = 0; + ctx->tdata[j].nodes[i].score = 0; + } + } } else { int ls = 0; @@ -987,6 +1027,7 @@ AVCodec ff_prores_encoder = { .init = encode_init, .close = encode_close, .encode2 = encode_frame, + .capabilities = CODEC_CAP_SLICE_THREADS, .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"), .pix_fmts = (const enum PixelFormat[]) { PIX_FMT_YUV422P10, PIX_FMT_YUV444P10, PIX_FMT_NONE From db6e26d70c371f069075d11f40d38924f3a45b65 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Mon, 16 Apr 2012 18:58:11 +0200 Subject: [PATCH 11/12] dv_tablegen: Drop unnecessary av_unused attribute from dv_vlc_map_tableinit(). --- libavcodec/dv_tablegen.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libavcodec/dv_tablegen.h b/libavcodec/dv_tablegen.h index 8164acd417..05831ea431 100644 --- a/libavcodec/dv_tablegen.h +++ b/libavcodec/dv_tablegen.h @@ -25,7 +25,6 @@ #include -#include "libavutil/attributes.h" #include "dv_vlc_data.h" #if CONFIG_SMALL @@ -48,7 +47,7 @@ typedef struct dv_vlc_pair { #else static struct dv_vlc_pair dv_vlc_map[DV_VLC_MAP_RUN_SIZE][DV_VLC_MAP_LEV_SIZE]; -static void av_unused dv_vlc_map_tableinit(void) +static void dv_vlc_map_tableinit(void) { int i, j; for (i = 0; i < NB_DV_VLC - 1; i++) { From 0f96f0d9968a767ead3aec823fcdfb78f26f7be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Fri, 6 Apr 2012 15:25:05 +0200 Subject: [PATCH 12/12] aacenc: Fix issues with huge values of bit_rate. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not pointlessly call ff_alloc_packet multiple times, and fix an infinite loop by clamping the maximum number of bits to target in the algorithm that does not use lambda. Signed-off-by: Reimar Döffinger Signed-off-by: Derek Buitenhuis --- libavcodec/aaccoder.c | 3 +++ libavcodec/aacenc.c | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c index 36a49a7538..c2b0e241a9 100644 --- a/libavcodec/aaccoder.c +++ b/libavcodec/aaccoder.c @@ -721,6 +721,9 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, int allz = 0; float minthr = INFINITY; + // for values above this the decoder might end up in an endless loop + // due to always having more bits than what can be encoded. + destbits = FFMIN(destbits, 5800); //XXX: some heuristic to determine initial quantizers will reduce search time //determine zero bands and upper limits for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 503a4a5f40..6021c375bb 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -571,13 +571,14 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } start_ch += chans; } + if ((ret = ff_alloc_packet(avpkt, 768 * s->channels))) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); + return ret; + } + do { int frame_bits; - if ((ret = ff_alloc_packet(avpkt, 768 * s->channels))) { - av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); - return ret; - } init_put_bits(&s->pb, avpkt->data, avpkt->size); if ((avctx->frame_number & 0xFF)==1 && !(avctx->flags & CODEC_FLAG_BITEXACT))