* qatar/master: wmaenc: use float planar sample format (e)ac3enc: use planar sample format aacenc: use planar sample format adpcmenc: use planar sample format for adpcm_ima_wav and adpcm_ima_qt adpcmenc: move 'ch' variable to higher scope adpcmenc: fix 3 instances of variable shadowing adpcm_ima_wav: simplify encoding libvorbis: use planar sample format libmp3lame: use planar sample formats vorbisenc: use float planar sample format ffm: do not write or read the audio sample format parseutils: fix parsing of invalid alpha values doc/RELEASE_NOTES: update for the 9 release. smoothstreamingenc: Add a more verbose error message smoothstreamingenc: Ignore the return value from mkdir smoothstreamingenc: Try writing a manifest when opening the muxer smoothstreamingenc: Move the output_chunk_list and write_manifest functions up smoothstreamingenc: Properly return errors from ism_flush to the caller smoothstreamingenc: Check the output UrlContext before accessing it Conflicts: doc/RELEASE_NOTES libavcodec/aacenc.c libavcodec/ac3enc_template.c libavcodec/wmaenc.c tests/ref/lavf/ffm Merged-by: Michael Niedermayer <michaelni@gmx.at>tags/n1.1
| @@ -479,31 +479,28 @@ static void put_bitstream_info(AVCodecContext *avctx, AACEncContext *s, | |||
| } | |||
| /* | |||
| * Deinterleave input samples. | |||
| * Copy input samples. | |||
| * Channels are reordered from libavcodec's default order to AAC order. | |||
| */ | |||
| static void deinterleave_input_samples(AACEncContext *s, const AVFrame *frame) | |||
| static void copy_input_samples(AACEncContext *s, const AVFrame *frame) | |||
| { | |||
| int ch, i; | |||
| const int sinc = s->channels; | |||
| const uint8_t *channel_map = aac_chan_maps[sinc - 1]; | |||
| int ch; | |||
| int end = 2048 + (frame ? frame->nb_samples : 0); | |||
| const uint8_t *channel_map = aac_chan_maps[s->channels - 1]; | |||
| /* deinterleave and remap input samples */ | |||
| for (ch = 0; ch < sinc; ch++) { | |||
| /* copy and remap input samples */ | |||
| for (ch = 0; ch < s->channels; ch++) { | |||
| /* copy last 1024 samples of previous frame to the start of the current frame */ | |||
| memcpy(&s->planar_samples[ch][1024], &s->planar_samples[ch][2048], 1024 * sizeof(s->planar_samples[0][0])); | |||
| /* deinterleave */ | |||
| i = 2048; | |||
| /* copy new samples and zero any remaining samples */ | |||
| if (frame) { | |||
| const float *sptr = ((const float *)frame->data[0]) + channel_map[ch]; | |||
| for (; i < 2048 + frame->nb_samples; i++) { | |||
| s->planar_samples[ch][i] = *sptr; | |||
| sptr += sinc; | |||
| } | |||
| memcpy(&s->planar_samples[ch][2048], | |||
| frame->extended_data[channel_map[ch]], | |||
| frame->nb_samples * sizeof(s->planar_samples[0][0])); | |||
| } | |||
| memset(&s->planar_samples[ch][i], 0, | |||
| (3072 - i) * sizeof(s->planar_samples[0][0])); | |||
| memset(&s->planar_samples[ch][end], 0, | |||
| (3072 - end) * sizeof(s->planar_samples[0][0])); | |||
| } | |||
| } | |||
| @@ -526,7 +523,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| return ret; | |||
| } | |||
| deinterleave_input_samples(s, frame); | |||
| copy_input_samples(s, frame); | |||
| if (s->psypp) | |||
| ff_psy_preprocess(s->psypp, s->planar_samples, s->channels); | |||
| @@ -827,7 +824,7 @@ AVCodec ff_aac_encoder = { | |||
| .supported_samplerates = avpriv_mpeg4audio_sample_rates, | |||
| .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY | | |||
| CODEC_CAP_EXPERIMENTAL, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), | |||
| .priv_class = &aacenc_class, | |||
| @@ -160,7 +160,7 @@ AVCodec ff_ac3_fixed_encoder = { | |||
| .init = ac3_fixed_encode_init, | |||
| .encode2 = ff_ac3_fixed_encode_frame, | |||
| .close = ff_ac3_encode_close, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), | |||
| .priv_class = &ac3enc_class, | |||
| @@ -158,7 +158,7 @@ AVCodec ff_ac3_encoder = { | |||
| .init = ff_ac3_encode_init, | |||
| .encode2 = ff_ac3_float_encode_frame, | |||
| .close = ff_ac3_encode_close, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), | |||
| .priv_class = &ac3enc_class, | |||
| @@ -4,20 +4,20 @@ | |||
| * Copyright (c) 2006-2011 Justin Ruggles <justin.ruggles@gmail.com> | |||
| * Copyright (c) 2006-2010 Prakash Punnoor <prakash@punnoor.de> | |||
| * | |||
| * This file is part of Libav. | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * Libav is free software; you can redistribute it and/or | |||
| * FFmpeg is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * Libav is distributed in the hope that it will be useful, | |||
| * FFmpeg is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with Libav; if not, write to the Free Software | |||
| * License along with FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| @@ -68,30 +68,23 @@ alloc_fail: | |||
| /* | |||
| * Deinterleave input samples. | |||
| * Copy input samples. | |||
| * Channels are reordered from FFmpeg's default order to AC-3 order. | |||
| */ | |||
| static void deinterleave_input_samples(AC3EncodeContext *s, | |||
| const SampleType *samples) | |||
| static void copy_input_samples(AC3EncodeContext *s, SampleType **samples) | |||
| { | |||
| int ch, i; | |||
| int ch; | |||
| /* deinterleave and remap input samples */ | |||
| /* copy and remap input samples */ | |||
| for (ch = 0; ch < s->channels; ch++) { | |||
| const SampleType *sptr; | |||
| int sinc; | |||
| /* copy last 256 samples of previous frame to the start of the current frame */ | |||
| memcpy(&s->planar_samples[ch][0], &s->planar_samples[ch][AC3_BLOCK_SIZE * s->num_blocks], | |||
| AC3_BLOCK_SIZE * sizeof(s->planar_samples[0][0])); | |||
| /* deinterleave */ | |||
| sinc = s->channels; | |||
| sptr = samples + s->channel_map[ch]; | |||
| for (i = AC3_BLOCK_SIZE; i < AC3_BLOCK_SIZE * (s->num_blocks + 1); i++) { | |||
| s->planar_samples[ch][i] = *sptr; | |||
| sptr += sinc; | |||
| } | |||
| /* copy new samples for current frame */ | |||
| memcpy(&s->planar_samples[ch][AC3_BLOCK_SIZE], | |||
| samples[s->channel_map[ch]], | |||
| AC3_BLOCK_SIZE * s->num_blocks * sizeof(s->planar_samples[0][0])); | |||
| } | |||
| } | |||
| @@ -395,7 +388,6 @@ int AC3_NAME(encode_frame)(AVCodecContext *avctx, AVPacket *avpkt, | |||
| const AVFrame *frame, int *got_packet_ptr) | |||
| { | |||
| AC3EncodeContext *s = avctx->priv_data; | |||
| const SampleType *samples = (const SampleType *)frame->data[0]; | |||
| int ret; | |||
| if (s->options.allow_per_frame_metadata) { | |||
| @@ -407,7 +399,7 @@ int AC3_NAME(encode_frame)(AVCodecContext *avctx, AVPacket *avpkt, | |||
| if (s->bit_alloc.sr_code == 1 || s->eac3) | |||
| ff_ac3_adjust_frame_size(s); | |||
| deinterleave_input_samples(s, samples); | |||
| copy_input_samples(s, (SampleType **)frame->extended_data); | |||
| apply_mdct(s); | |||
| @@ -274,12 +274,11 @@ static inline uint8_t adpcm_yamaha_compress_sample(ADPCMChannelStatus *c, | |||
| static void adpcm_compress_trellis(AVCodecContext *avctx, | |||
| const int16_t *samples, uint8_t *dst, | |||
| ADPCMChannelStatus *c, int n) | |||
| ADPCMChannelStatus *c, int n, int stride) | |||
| { | |||
| //FIXME 6% faster if frontier is a compile-time constant | |||
| ADPCMEncodeContext *s = avctx->priv_data; | |||
| const int frontier = 1 << avctx->trellis; | |||
| const int stride = avctx->channels; | |||
| const int version = avctx->codec->id; | |||
| TrellisPath *paths = s->paths, *p; | |||
| TrellisNode *node_buf = s->node_buf; | |||
| @@ -481,13 +480,15 @@ static void adpcm_compress_trellis(AVCodecContext *avctx, | |||
| static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| const AVFrame *frame, int *got_packet_ptr) | |||
| { | |||
| int n, i, st, pkt_size, ret; | |||
| int n, i, ch, st, pkt_size, ret; | |||
| const int16_t *samples; | |||
| int16_t **samples_p; | |||
| uint8_t *dst; | |||
| ADPCMEncodeContext *c = avctx->priv_data; | |||
| uint8_t *buf; | |||
| samples = (const int16_t *)frame->data[0]; | |||
| samples_p = (int16_t **)frame->extended_data; | |||
| st = avctx->channels == 2; | |||
| if (avctx->codec_id == AV_CODEC_ID_ADPCM_SWF) | |||
| @@ -500,91 +501,71 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| switch(avctx->codec->id) { | |||
| case AV_CODEC_ID_ADPCM_IMA_WAV: | |||
| n = frame->nb_samples / 8; | |||
| c->status[0].prev_sample = samples[0]; | |||
| /* c->status[0].step_index = 0; | |||
| XXX: not sure how to init the state machine */ | |||
| bytestream_put_le16(&dst, c->status[0].prev_sample); | |||
| *dst++ = c->status[0].step_index; | |||
| *dst++ = 0; /* unknown */ | |||
| samples++; | |||
| if (avctx->channels == 2) { | |||
| c->status[1].prev_sample = samples[0]; | |||
| /* c->status[1].step_index = 0; */ | |||
| bytestream_put_le16(&dst, c->status[1].prev_sample); | |||
| *dst++ = c->status[1].step_index; | |||
| *dst++ = 0; | |||
| samples++; | |||
| { | |||
| int blocks, j; | |||
| blocks = (frame->nb_samples - 1) / 8; | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| ADPCMChannelStatus *status = &c->status[ch]; | |||
| status->prev_sample = samples_p[ch][0]; | |||
| /* status->step_index = 0; | |||
| XXX: not sure how to init the state machine */ | |||
| bytestream_put_le16(&dst, status->prev_sample); | |||
| *dst++ = status->step_index; | |||
| *dst++ = 0; /* unknown */ | |||
| } | |||
| /* stereo: 4 bytes (8 samples) for left, | |||
| 4 bytes for right, 4 bytes left, ... */ | |||
| /* stereo: 4 bytes (8 samples) for left, 4 bytes for right */ | |||
| if (avctx->trellis > 0) { | |||
| FF_ALLOC_OR_GOTO(avctx, buf, 2 * n * 8, error); | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n * 8); | |||
| if (avctx->channels == 2) | |||
| adpcm_compress_trellis(avctx, samples + 1, buf + n * 8, | |||
| &c->status[1], n * 8); | |||
| for (i = 0; i < n; i++) { | |||
| *dst++ = buf[8 * i + 0] | (buf[8 * i + 1] << 4); | |||
| *dst++ = buf[8 * i + 2] | (buf[8 * i + 3] << 4); | |||
| *dst++ = buf[8 * i + 4] | (buf[8 * i + 5] << 4); | |||
| *dst++ = buf[8 * i + 6] | (buf[8 * i + 7] << 4); | |||
| if (avctx->channels == 2) { | |||
| uint8_t *buf1 = buf + n * 8; | |||
| *dst++ = buf1[8 * i + 0] | (buf1[8 * i + 1] << 4); | |||
| *dst++ = buf1[8 * i + 2] | (buf1[8 * i + 3] << 4); | |||
| *dst++ = buf1[8 * i + 4] | (buf1[8 * i + 5] << 4); | |||
| *dst++ = buf1[8 * i + 6] | (buf1[8 * i + 7] << 4); | |||
| FF_ALLOC_OR_GOTO(avctx, buf, avctx->channels * blocks * 8, error); | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| adpcm_compress_trellis(avctx, &samples_p[ch][1], | |||
| buf + ch * blocks * 8, &c->status[ch], | |||
| blocks * 8, 1); | |||
| } | |||
| for (i = 0; i < blocks; i++) { | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| uint8_t *buf1 = buf + ch * blocks * 8 + i * 8; | |||
| for (j = 0; j < 8; j += 2) | |||
| *dst++ = buf1[j] | (buf1[j + 1] << 4); | |||
| } | |||
| } | |||
| av_free(buf); | |||
| } else { | |||
| for (; n > 0; n--) { | |||
| *dst = adpcm_ima_compress_sample(&c->status[0], samples[0]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels ]) << 4; | |||
| *dst = adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels * 2]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels * 3]) << 4; | |||
| *dst = adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels * 4]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels * 5]) << 4; | |||
| *dst = adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels * 6]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[0], samples[avctx->channels * 7]) << 4; | |||
| /* right channel */ | |||
| if (avctx->channels == 2) { | |||
| *dst = adpcm_ima_compress_sample(&c->status[1], samples[1 ]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[1], samples[3 ]) << 4; | |||
| *dst = adpcm_ima_compress_sample(&c->status[1], samples[5 ]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[1], samples[7 ]) << 4; | |||
| *dst = adpcm_ima_compress_sample(&c->status[1], samples[9 ]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[1], samples[11]) << 4; | |||
| *dst = adpcm_ima_compress_sample(&c->status[1], samples[13]); | |||
| *dst++ |= adpcm_ima_compress_sample(&c->status[1], samples[15]) << 4; | |||
| for (i = 0; i < blocks; i++) { | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| ADPCMChannelStatus *status = &c->status[ch]; | |||
| const int16_t *smp = &samples_p[ch][1 + i * 8]; | |||
| for (j = 0; j < 8; j += 2) { | |||
| *dst++ = adpcm_ima_compress_sample(status, smp[j ]) | | |||
| (adpcm_ima_compress_sample(status, smp[j + 1]) << 4); | |||
| } | |||
| } | |||
| samples += 8 * avctx->channels; | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| case AV_CODEC_ID_ADPCM_IMA_QT: | |||
| { | |||
| int ch, i; | |||
| PutBitContext pb; | |||
| init_put_bits(&pb, dst, pkt_size * 8); | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| put_bits(&pb, 9, (c->status[ch].prev_sample & 0xFFFF) >> 7); | |||
| put_bits(&pb, 7, c->status[ch].step_index); | |||
| ADPCMChannelStatus *status = &c->status[ch]; | |||
| put_bits(&pb, 9, (status->prev_sample & 0xFFFF) >> 7); | |||
| put_bits(&pb, 7, status->step_index); | |||
| if (avctx->trellis > 0) { | |||
| uint8_t buf[64]; | |||
| adpcm_compress_trellis(avctx, samples+ch, buf, &c->status[ch], 64); | |||
| adpcm_compress_trellis(avctx, &samples_p[ch][1], buf, status, | |||
| 64, 1); | |||
| for (i = 0; i < 64; i++) | |||
| put_bits(&pb, 4, buf[i ^ 1]); | |||
| } else { | |||
| for (i = 0; i < 64; i += 2) { | |||
| int t1, t2; | |||
| t1 = adpcm_ima_qt_compress_sample(&c->status[ch], | |||
| samples[avctx->channels * (i + 0) + ch]); | |||
| t2 = adpcm_ima_qt_compress_sample(&c->status[ch], | |||
| samples[avctx->channels * (i + 1) + ch]); | |||
| t1 = adpcm_ima_qt_compress_sample(status, samples_p[ch][i ]); | |||
| t2 = adpcm_ima_qt_compress_sample(status, samples_p[ch][i + 1]); | |||
| put_bits(&pb, 4, t2); | |||
| put_bits(&pb, 4, t1); | |||
| } | |||
| @@ -596,7 +577,6 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| } | |||
| case AV_CODEC_ID_ADPCM_SWF: | |||
| { | |||
| int i; | |||
| PutBitContext pb; | |||
| init_put_bits(&pb, dst, pkt_size * 8); | |||
| @@ -617,10 +597,11 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| if (avctx->trellis > 0) { | |||
| FF_ALLOC_OR_GOTO(avctx, buf, 2 * n, error); | |||
| adpcm_compress_trellis(avctx, samples + avctx->channels, buf, | |||
| &c->status[0], n); | |||
| &c->status[0], n, avctx->channels); | |||
| if (avctx->channels == 2) | |||
| adpcm_compress_trellis(avctx, samples + avctx->channels + 1, | |||
| buf + n, &c->status[1], n); | |||
| buf + n, &c->status[1], n, | |||
| avctx->channels); | |||
| for (i = 0; i < n; i++) { | |||
| put_bits(&pb, 4, buf[i]); | |||
| if (avctx->channels == 2) | |||
| @@ -661,15 +642,18 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| bytestream_put_le16(&dst, c->status[i].sample2); | |||
| if (avctx->trellis > 0) { | |||
| int n = avctx->block_align - 7 * avctx->channels; | |||
| n = avctx->block_align - 7 * avctx->channels; | |||
| FF_ALLOC_OR_GOTO(avctx, buf, 2 * n, error); | |||
| if (avctx->channels == 1) { | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n); | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n, | |||
| avctx->channels); | |||
| for (i = 0; i < n; i += 2) | |||
| *dst++ = (buf[i] << 4) | buf[i + 1]; | |||
| } else { | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n); | |||
| adpcm_compress_trellis(avctx, samples + 1, buf + n, &c->status[1], n); | |||
| adpcm_compress_trellis(avctx, samples, buf, | |||
| &c->status[0], n, avctx->channels); | |||
| adpcm_compress_trellis(avctx, samples + 1, buf + n, | |||
| &c->status[1], n, avctx->channels); | |||
| for (i = 0; i < n; i++) | |||
| *dst++ = (buf[i] << 4) | buf[n + i]; | |||
| } | |||
| @@ -689,12 +673,15 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| FF_ALLOC_OR_GOTO(avctx, buf, 2 * n * 2, error); | |||
| n *= 2; | |||
| if (avctx->channels == 1) { | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n); | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n, | |||
| avctx->channels); | |||
| for (i = 0; i < n; i += 2) | |||
| *dst++ = buf[i] | (buf[i + 1] << 4); | |||
| } else { | |||
| adpcm_compress_trellis(avctx, samples, buf, &c->status[0], n); | |||
| adpcm_compress_trellis(avctx, samples + 1, buf + n, &c->status[1], n); | |||
| adpcm_compress_trellis(avctx, samples, buf, | |||
| &c->status[0], n, avctx->channels); | |||
| adpcm_compress_trellis(avctx, samples + 1, buf + n, | |||
| &c->status[1], n, avctx->channels); | |||
| for (i = 0; i < n; i++) | |||
| *dst++ = buf[i] | (buf[n + i] << 4); | |||
| } | |||
| @@ -722,7 +709,11 @@ static const enum AVSampleFormat sample_fmts[] = { | |||
| AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE | |||
| }; | |||
| #define ADPCM_ENCODER(id_, name_, long_name_) \ | |||
| static const enum AVSampleFormat sample_fmts_p[] = { | |||
| AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_NONE | |||
| }; | |||
| #define ADPCM_ENCODER(id_, name_, sample_fmts_, long_name_) \ | |||
| AVCodec ff_ ## name_ ## _encoder = { \ | |||
| .name = #name_, \ | |||
| .type = AVMEDIA_TYPE_AUDIO, \ | |||
| @@ -731,12 +722,12 @@ AVCodec ff_ ## name_ ## _encoder = { \ | |||
| .init = adpcm_encode_init, \ | |||
| .encode2 = adpcm_encode_frame, \ | |||
| .close = adpcm_encode_close, \ | |||
| .sample_fmts = sample_fmts, \ | |||
| .sample_fmts = sample_fmts_, \ | |||
| .long_name = NULL_IF_CONFIG_SMALL(long_name_), \ | |||
| } | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt, "ADPCM IMA QuickTime"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav, "ADPCM IMA WAV"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_MS, adpcm_ms, "ADPCM Microsoft"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_SWF, adpcm_swf, "ADPCM Shockwave Flash"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha, "ADPCM Yamaha"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt, sample_fmts_p, "ADPCM IMA QuickTime"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav, sample_fmts_p, "ADPCM IMA WAV"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_MS, adpcm_ms, sample_fmts, "ADPCM Microsoft"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_SWF, adpcm_swf, sample_fmts, "ADPCM Shockwave Flash"); | |||
| ADPCM_ENCODER(AV_CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha, sample_fmts, "ADPCM Yamaha"); | |||
| @@ -258,7 +258,7 @@ AVCodec ff_eac3_encoder = { | |||
| .init = ff_ac3_encode_init, | |||
| .encode2 = ff_ac3_float_encode_frame, | |||
| .close = ff_ac3_encode_close, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52 E-AC-3"), | |||
| .priv_class = &eac3enc_class, | |||
| @@ -33,6 +33,7 @@ | |||
| #include "libavutil/opt.h" | |||
| #include "avcodec.h" | |||
| #include "audio_frame_queue.h" | |||
| #include "dsputil.h" | |||
| #include "internal.h" | |||
| #include "mpegaudio.h" | |||
| #include "mpegaudiodecheader.h" | |||
| @@ -46,8 +47,9 @@ typedef struct LAMEContext { | |||
| uint8_t buffer[BUFFER_SIZE]; | |||
| int buffer_index; | |||
| int reservoir; | |||
| void *planar_samples[2]; | |||
| float *samples_flt[2]; | |||
| AudioFrameQueue afq; | |||
| DSPContext dsp; | |||
| } LAMEContext; | |||
| @@ -58,8 +60,8 @@ static av_cold int mp3lame_encode_close(AVCodecContext *avctx) | |||
| #if FF_API_OLD_ENCODE_AUDIO | |||
| av_freep(&avctx->coded_frame); | |||
| #endif | |||
| av_freep(&s->planar_samples[0]); | |||
| av_freep(&s->planar_samples[1]); | |||
| av_freep(&s->samples_flt[0]); | |||
| av_freep(&s->samples_flt[1]); | |||
| ff_af_queue_close(&s->afq); | |||
| @@ -127,93 +129,63 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx) | |||
| } | |||
| #endif | |||
| /* sample format */ | |||
| if (avctx->sample_fmt == AV_SAMPLE_FMT_S32 || | |||
| avctx->sample_fmt == AV_SAMPLE_FMT_FLT) { | |||
| /* allocate float sample buffers */ | |||
| if (avctx->sample_fmt == AV_SAMPLE_FMT_FLTP) { | |||
| int ch; | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| s->planar_samples[ch] = av_malloc(avctx->frame_size * | |||
| av_get_bytes_per_sample(avctx->sample_fmt)); | |||
| if (!s->planar_samples[ch]) { | |||
| s->samples_flt[ch] = av_malloc(avctx->frame_size * | |||
| sizeof(*s->samples_flt[ch])); | |||
| if (!s->samples_flt[ch]) { | |||
| ret = AVERROR(ENOMEM); | |||
| goto error; | |||
| } | |||
| } | |||
| } | |||
| ff_dsputil_init(&s->dsp, avctx); | |||
| return 0; | |||
| error: | |||
| mp3lame_encode_close(avctx); | |||
| return ret; | |||
| } | |||
| #define DEINTERLEAVE(type, scale) do { \ | |||
| int ch, i; \ | |||
| for (ch = 0; ch < s->avctx->channels; ch++) { \ | |||
| const type *input = samples; \ | |||
| type *output = s->planar_samples[ch]; \ | |||
| input += ch; \ | |||
| for (i = 0; i < nb_samples; i++) { \ | |||
| output[i] = *input * scale; \ | |||
| input += s->avctx->channels; \ | |||
| } \ | |||
| } \ | |||
| #define ENCODE_BUFFER(func, buf_type, buf_name) do { \ | |||
| lame_result = func(s->gfp, \ | |||
| (const buf_type *)buf_name[0], \ | |||
| (const buf_type *)buf_name[1], frame->nb_samples, \ | |||
| s->buffer + s->buffer_index, \ | |||
| BUFFER_SIZE - s->buffer_index); \ | |||
| } while (0) | |||
| static int encode_frame_int16(LAMEContext *s, void *samples, int nb_samples) | |||
| { | |||
| if (s->avctx->channels > 1) { | |||
| return lame_encode_buffer_interleaved(s->gfp, samples, | |||
| nb_samples, | |||
| s->buffer + s->buffer_index, | |||
| BUFFER_SIZE - s->buffer_index); | |||
| } else { | |||
| return lame_encode_buffer(s->gfp, samples, NULL, nb_samples, | |||
| s->buffer + s->buffer_index, | |||
| BUFFER_SIZE - s->buffer_index); | |||
| } | |||
| } | |||
| static int encode_frame_int32(LAMEContext *s, void *samples, int nb_samples) | |||
| { | |||
| DEINTERLEAVE(int32_t, 1); | |||
| return lame_encode_buffer_int(s->gfp, | |||
| s->planar_samples[0], s->planar_samples[1], | |||
| nb_samples, | |||
| s->buffer + s->buffer_index, | |||
| BUFFER_SIZE - s->buffer_index); | |||
| } | |||
| static int encode_frame_float(LAMEContext *s, void *samples, int nb_samples) | |||
| { | |||
| DEINTERLEAVE(float, 32768.0f); | |||
| return lame_encode_buffer_float(s->gfp, | |||
| s->planar_samples[0], s->planar_samples[1], | |||
| nb_samples, | |||
| s->buffer + s->buffer_index, | |||
| BUFFER_SIZE - s->buffer_index); | |||
| } | |||
| static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| const AVFrame *frame, int *got_packet_ptr) | |||
| { | |||
| LAMEContext *s = avctx->priv_data; | |||
| MPADecodeHeader hdr; | |||
| int len, ret; | |||
| int len, ret, ch; | |||
| int lame_result; | |||
| if (frame) { | |||
| switch (avctx->sample_fmt) { | |||
| case AV_SAMPLE_FMT_S16: | |||
| lame_result = encode_frame_int16(s, frame->data[0], frame->nb_samples); | |||
| case AV_SAMPLE_FMT_S16P: | |||
| ENCODE_BUFFER(lame_encode_buffer, int16_t, frame->data); | |||
| break; | |||
| case AV_SAMPLE_FMT_S32: | |||
| lame_result = encode_frame_int32(s, frame->data[0], frame->nb_samples); | |||
| case AV_SAMPLE_FMT_S32P: | |||
| ENCODE_BUFFER(lame_encode_buffer_int, int32_t, frame->data); | |||
| break; | |||
| case AV_SAMPLE_FMT_FLT: | |||
| lame_result = encode_frame_float(s, frame->data[0], frame->nb_samples); | |||
| case AV_SAMPLE_FMT_FLTP: | |||
| if (frame->linesize[0] < 4 * FFALIGN(frame->nb_samples, 8)) { | |||
| av_log(avctx, AV_LOG_ERROR, "inadequate AVFrame plane padding\n"); | |||
| return AVERROR(EINVAL); | |||
| } | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| s->dsp.vector_fmul_scalar(s->samples_flt[ch], | |||
| (const float *)frame->data[ch], | |||
| 32768.0f, | |||
| FFALIGN(frame->nb_samples, 8)); | |||
| } | |||
| ENCODE_BUFFER(lame_encode_buffer_float, float, s->samples_flt); | |||
| break; | |||
| default: | |||
| return AVERROR_BUG; | |||
| @@ -299,9 +271,9 @@ AVCodec ff_libmp3lame_encoder = { | |||
| .encode2 = mp3lame_encode_frame, | |||
| .close = mp3lame_encode_close, | |||
| .capabilities = CODEC_CAP_DELAY | CODEC_CAP_SMALL_LAST_FRAME, | |||
| .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32, | |||
| AV_SAMPLE_FMT_FLT, | |||
| AV_SAMPLE_FMT_S16, | |||
| .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, | |||
| AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_S16P, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .supported_samplerates = libmp3lame_sample_rates, | |||
| .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, | |||
| @@ -290,18 +290,16 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |||
| /* send samples to libvorbis */ | |||
| if (frame) { | |||
| const float *audio = (const float *)frame->data[0]; | |||
| const int samples = frame->nb_samples; | |||
| float **buffer; | |||
| int c, channels = s->vi.channels; | |||
| buffer = vorbis_analysis_buffer(&s->vd, samples); | |||
| for (c = 0; c < channels; c++) { | |||
| int i; | |||
| int co = (channels > 8) ? c : | |||
| ff_vorbis_encoding_channel_layout_offsets[channels - 1][c]; | |||
| for (i = 0; i < samples; i++) | |||
| buffer[c][i] = audio[i * channels + co]; | |||
| memcpy(buffer[c], frame->extended_data[co], | |||
| samples * sizeof(*buffer[c])); | |||
| } | |||
| if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) { | |||
| av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n"); | |||
| @@ -383,7 +381,7 @@ AVCodec ff_libvorbis_encoder = { | |||
| .encode2 = oggvorbis_encode_frame, | |||
| .close = oggvorbis_encode_close, | |||
| .capabilities = CODEC_CAP_DELAY, | |||
| .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, | |||
| .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("libvorbis"), | |||
| .priv_class = &class, | |||
| @@ -963,10 +963,10 @@ static int residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc, | |||
| return 0; | |||
| } | |||
| static int apply_window_and_mdct(vorbis_enc_context *venc, const signed short *audio, | |||
| int samples) | |||
| static int apply_window_and_mdct(vorbis_enc_context *venc, | |||
| float **audio, int samples) | |||
| { | |||
| int i, j, channel; | |||
| int i, channel; | |||
| const float * win = venc->win[0]; | |||
| int window_len = 1 << (venc->log2_blocksize[0] - 1); | |||
| float n = (float)(1 << venc->log2_blocksize[0]) / 4.; | |||
| @@ -988,9 +988,8 @@ static int apply_window_and_mdct(vorbis_enc_context *venc, const signed short *a | |||
| if (samples) { | |||
| for (channel = 0; channel < venc->channels; channel++) { | |||
| float * offset = venc->samples + channel*window_len*2 + window_len; | |||
| j = channel; | |||
| for (i = 0; i < samples; i++, j += venc->channels) | |||
| offset[i] = audio[j] / 32768. / n * win[window_len - i - 1]; | |||
| for (i = 0; i < samples; i++) | |||
| offset[i] = audio[channel][i] / n * win[window_len - i - 1]; | |||
| } | |||
| } else { | |||
| for (channel = 0; channel < venc->channels; channel++) | |||
| @@ -1005,9 +1004,8 @@ static int apply_window_and_mdct(vorbis_enc_context *venc, const signed short *a | |||
| if (samples) { | |||
| for (channel = 0; channel < venc->channels; channel++) { | |||
| float *offset = venc->saved + channel * window_len; | |||
| j = channel; | |||
| for (i = 0; i < samples; i++, j += venc->channels) | |||
| offset[i] = audio[j] / 32768. / n * win[i]; | |||
| for (i = 0; i < samples; i++) | |||
| offset[i] = audio[channel][i] / n * win[i]; | |||
| } | |||
| venc->have_saved = 1; | |||
| } else { | |||
| @@ -1020,7 +1018,7 @@ static int vorbis_encode_frame(AVCodecContext *avccontext, AVPacket *avpkt, | |||
| const AVFrame *frame, int *got_packet_ptr) | |||
| { | |||
| vorbis_enc_context *venc = avccontext->priv_data; | |||
| const int16_t *audio = frame ? (const int16_t *)frame->data[0] : NULL; | |||
| float **audio = frame ? (float **)frame->extended_data : NULL; | |||
| int samples = frame ? frame->nb_samples : 0; | |||
| vorbis_enc_mode *mode; | |||
| vorbis_enc_mapping *mapping; | |||
| @@ -1213,7 +1211,7 @@ AVCodec ff_vorbis_encoder = { | |||
| .encode2 = vorbis_encode_frame, | |||
| .close = vorbis_encode_close, | |||
| .capabilities = CODEC_CAP_DELAY | CODEC_CAP_EXPERIMENTAL, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("Vorbis"), | |||
| }; | |||
| @@ -89,6 +89,7 @@ int ff_wma_init(AVCodecContext *avctx, int flags2) | |||
| ff_dsputil_init(&s->dsp, avctx); | |||
| ff_fmt_convert_init(&s->fmt_conv, avctx); | |||
| avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT); | |||
| if (avctx->codec->id == AV_CODEC_ID_WMAV1) { | |||
| s->version = 1; | |||
| @@ -22,6 +22,7 @@ | |||
| #ifndef AVCODEC_WMA_H | |||
| #define AVCODEC_WMA_H | |||
| #include "libavutil/float_dsp.h" | |||
| #include "get_bits.h" | |||
| #include "put_bits.h" | |||
| #include "dsputil.h" | |||
| @@ -137,6 +138,7 @@ typedef struct WMACodecContext { | |||
| float lsp_pow_m_table2[(1 << LSP_POW_BITS)]; | |||
| DSPContext dsp; | |||
| FmtConvertContext fmt_conv; | |||
| AVFloatDSPContext fdsp; | |||
| #ifdef TRACE | |||
| int frame_count; | |||
| @@ -93,23 +93,24 @@ static int encode_init(AVCodecContext * avctx){ | |||
| } | |||
| static void apply_window_and_mdct(AVCodecContext * avctx, const signed short * audio, int len) { | |||
| static void apply_window_and_mdct(AVCodecContext * avctx, const AVFrame *frame) | |||
| { | |||
| WMACodecContext *s = avctx->priv_data; | |||
| float **audio = (float **)frame->extended_data; | |||
| int len = frame->nb_samples; | |||
| int window_index= s->frame_len_bits - s->block_len_bits; | |||
| FFTContext *mdct = &s->mdct_ctx[window_index]; | |||
| int i, j, channel; | |||
| int ch; | |||
| const float * win = s->windows[window_index]; | |||
| int window_len = 1 << s->block_len_bits; | |||
| float n = window_len/2; | |||
| for (channel = 0; channel < avctx->channels; channel++) { | |||
| memcpy(s->output, s->frame_out[channel], sizeof(float)*window_len); | |||
| j = channel; | |||
| for (i = 0; i < len; i++, j += avctx->channels){ | |||
| s->output[i+window_len] = audio[j] / n * win[window_len - i - 1]; | |||
| s->frame_out[channel][i] = audio[j] / n * win[i]; | |||
| } | |||
| mdct->mdct_calc(mdct, s->coefs[channel], s->output); | |||
| float n = 2.0 * 32768.0 / window_len; | |||
| for (ch = 0; ch < avctx->channels; ch++) { | |||
| memcpy(s->output, s->frame_out[ch], window_len * sizeof(*s->output)); | |||
| s->dsp.vector_fmul_scalar(s->frame_out[ch], audio[ch], n, len); | |||
| s->dsp.vector_fmul_reverse(&s->output[window_len], s->frame_out[ch], win, len); | |||
| s->fdsp.vector_fmul(s->frame_out[ch], s->frame_out[ch], win, len); | |||
| mdct->mdct_calc(mdct, s->coefs[ch], s->output); | |||
| } | |||
| } | |||
| @@ -345,13 +346,12 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt, | |||
| const AVFrame *frame, int *got_packet_ptr) | |||
| { | |||
| WMACodecContext *s = avctx->priv_data; | |||
| const int16_t *samples = (const int16_t *)frame->data[0]; | |||
| int i, total_gain, ret, error; | |||
| s->block_len_bits= s->frame_len_bits; //required by non variable block len | |||
| s->block_len = 1 << s->block_len_bits; | |||
| apply_window_and_mdct(avctx, samples, frame->nb_samples); | |||
| apply_window_and_mdct(avctx, frame); | |||
| if (s->ms_stereo) { | |||
| float a, b; | |||
| @@ -404,7 +404,7 @@ AVCodec ff_wmav1_encoder = { | |||
| .init = encode_init, | |||
| .encode2 = encode_superframe, | |||
| .close = ff_wma_end, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 1"), | |||
| }; | |||
| @@ -418,7 +418,7 @@ AVCodec ff_wmav2_encoder = { | |||
| .init = encode_init, | |||
| .encode2 = encode_superframe, | |||
| .close = ff_wma_end, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, | |||
| .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, | |||
| AV_SAMPLE_FMT_NONE }, | |||
| .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 2"), | |||
| }; | |||
| @@ -360,7 +360,6 @@ static int ffm_read_header(AVFormatContext *s) | |||
| codec->sample_rate = avio_rb32(pb); | |||
| codec->channels = avio_rl16(pb); | |||
| codec->frame_size = avio_rl16(pb); | |||
| codec->sample_fmt = (int16_t) avio_rl16(pb); | |||
| break; | |||
| default: | |||
| goto fail; | |||
| @@ -169,7 +169,6 @@ static int ffm_write_header(AVFormatContext *s) | |||
| avio_wb32(pb, codec->sample_rate); | |||
| avio_wl16(pb, codec->channels); | |||
| avio_wl16(pb, codec->frame_size); | |||
| avio_wl16(pb, codec->sample_fmt); | |||
| break; | |||
| default: | |||
| return -1; | |||
| @@ -108,7 +108,8 @@ static int64_t ism_seek(void *opaque, int64_t offset, int whence) | |||
| os->tail_out = NULL; | |||
| } | |||
| if (offset >= os->cur_start_pos) { | |||
| ffurl_seek(os->out, offset - os->cur_start_pos, SEEK_SET); | |||
| if (os->out) | |||
| ffurl_seek(os->out, offset - os->cur_start_pos, SEEK_SET); | |||
| os->cur_pos = offset; | |||
| return offset; | |||
| } | |||
| @@ -185,18 +186,108 @@ static void ism_free(AVFormatContext *s) | |||
| av_freep(&c->streams); | |||
| } | |||
| static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size) | |||
| { | |||
| int removed = 0, i, start = 0; | |||
| if (os->nb_fragments <= 0) | |||
| return; | |||
| if (os->fragments[0]->n > 0) | |||
| removed = 1; | |||
| if (final) | |||
| skip = 0; | |||
| if (window_size) | |||
| start = FFMAX(os->nb_fragments - skip - window_size, 0); | |||
| for (i = start; i < os->nb_fragments - skip; i++) { | |||
| Fragment *frag = os->fragments[i]; | |||
| if (!final || removed) | |||
| avio_printf(out, "<c t=\"%"PRIu64"\" d=\"%"PRIu64"\" />\n", frag->start_time, frag->duration); | |||
| else | |||
| avio_printf(out, "<c n=\"%d\" d=\"%"PRIu64"\" />\n", frag->n, frag->duration); | |||
| } | |||
| } | |||
| static int write_manifest(AVFormatContext *s, int final) | |||
| { | |||
| SmoothStreamingContext *c = s->priv_data; | |||
| AVIOContext *out; | |||
| char filename[1024]; | |||
| int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0; | |||
| int64_t duration = 0; | |||
| snprintf(filename, sizeof(filename), "%s/Manifest", s->filename); | |||
| ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); | |||
| if (ret < 0) { | |||
| av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", filename); | |||
| return ret; | |||
| } | |||
| avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); | |||
| for (i = 0; i < s->nb_streams; i++) { | |||
| OutputStream *os = &c->streams[i]; | |||
| if (os->nb_fragments > 0) { | |||
| Fragment *last = os->fragments[os->nb_fragments - 1]; | |||
| duration = last->start_time + last->duration; | |||
| } | |||
| if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | |||
| video_chunks = os->nb_fragments; | |||
| video_streams++; | |||
| } else { | |||
| audio_chunks = os->nb_fragments; | |||
| audio_streams++; | |||
| } | |||
| } | |||
| if (!final) { | |||
| duration = 0; | |||
| video_chunks = audio_chunks = 0; | |||
| } | |||
| if (c->window_size) { | |||
| video_chunks = FFMIN(video_chunks, c->window_size); | |||
| audio_chunks = FFMIN(audio_chunks, c->window_size); | |||
| } | |||
| avio_printf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"%"PRIu64"\"", duration); | |||
| if (!final) | |||
| avio_printf(out, " IsLive=\"true\" LookAheadFragmentCount=\"%d\" DVRWindowLength=\"0\"", c->lookahead_count); | |||
| avio_printf(out, ">\n"); | |||
| if (c->has_video) { | |||
| int last = -1, index = 0; | |||
| avio_printf(out, "<StreamIndex Type=\"video\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n", video_streams, video_chunks); | |||
| for (i = 0; i < s->nb_streams; i++) { | |||
| OutputStream *os = &c->streams[i]; | |||
| if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_VIDEO) | |||
| continue; | |||
| last = i; | |||
| avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codec->bit_rate, os->fourcc, s->streams[i]->codec->width, s->streams[i]->codec->height, os->private_str); | |||
| index++; | |||
| } | |||
| output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size); | |||
| avio_printf(out, "</StreamIndex>\n"); | |||
| } | |||
| if (c->has_audio) { | |||
| int last = -1, index = 0; | |||
| avio_printf(out, "<StreamIndex Type=\"audio\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n", audio_streams, audio_chunks); | |||
| for (i = 0; i < s->nb_streams; i++) { | |||
| OutputStream *os = &c->streams[i]; | |||
| if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) | |||
| continue; | |||
| last = i; | |||
| avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codec->bit_rate, os->fourcc, s->streams[i]->codec->sample_rate, s->streams[i]->codec->channels, os->packet_size, os->audio_tag, os->private_str); | |||
| index++; | |||
| } | |||
| output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size); | |||
| avio_printf(out, "</StreamIndex>\n"); | |||
| } | |||
| avio_printf(out, "</SmoothStreamingMedia>\n"); | |||
| avio_flush(out); | |||
| avio_close(out); | |||
| return 0; | |||
| } | |||
| static int ism_write_header(AVFormatContext *s) | |||
| { | |||
| SmoothStreamingContext *c = s->priv_data; | |||
| int ret = 0, i; | |||
| AVOutputFormat *oformat; | |||
| ret = mkdir(s->filename, 0777); | |||
| if (ret) { | |||
| av_log(s, AV_LOG_ERROR, "mkdir(%s): %s\n", s->filename, strerror(errno)); | |||
| return AVERROR(errno); | |||
| } | |||
| ret = 0; | |||
| mkdir(s->filename, 0777); | |||
| oformat = av_guess_format("ismv", NULL, NULL); | |||
| if (!oformat) { | |||
| @@ -292,6 +383,7 @@ static int ism_write_header(AVFormatContext *s) | |||
| av_log(s, AV_LOG_WARNING, "no video stream and no min frag duration set\n"); | |||
| ret = AVERROR(EINVAL); | |||
| } | |||
| ret = write_manifest(s, 0); | |||
| fail: | |||
| if (ret) | |||
| @@ -400,99 +492,6 @@ static int copy_moof(AVFormatContext *s, const char* infile, const char *outfile | |||
| return ret; | |||
| } | |||
| static void output_chunk_list(OutputStream *os, AVIOContext *out, int final, int skip, int window_size) | |||
| { | |||
| int removed = 0, i, start = 0; | |||
| if (os->nb_fragments <= 0) | |||
| return; | |||
| if (os->fragments[0]->n > 0) | |||
| removed = 1; | |||
| if (final) | |||
| skip = 0; | |||
| if (window_size) | |||
| start = FFMAX(os->nb_fragments - skip - window_size, 0); | |||
| for (i = start; i < os->nb_fragments - skip; i++) { | |||
| Fragment *frag = os->fragments[i]; | |||
| if (!final || removed) | |||
| avio_printf(out, "<c t=\"%"PRIu64"\" d=\"%"PRIu64"\" />\n", frag->start_time, frag->duration); | |||
| else | |||
| avio_printf(out, "<c n=\"%d\" d=\"%"PRIu64"\" />\n", frag->n, frag->duration); | |||
| } | |||
| } | |||
| static int write_manifest(AVFormatContext *s, int final) | |||
| { | |||
| SmoothStreamingContext *c = s->priv_data; | |||
| AVIOContext *out; | |||
| char filename[1024]; | |||
| int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0; | |||
| int64_t duration = 0; | |||
| snprintf(filename, sizeof(filename), "%s/Manifest", s->filename); | |||
| ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL); | |||
| if (ret < 0) | |||
| return ret; | |||
| avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); | |||
| for (i = 0; i < s->nb_streams; i++) { | |||
| OutputStream *os = &c->streams[i]; | |||
| if (os->nb_fragments > 0) { | |||
| Fragment *last = os->fragments[os->nb_fragments - 1]; | |||
| duration = last->start_time + last->duration; | |||
| } | |||
| if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | |||
| video_chunks = os->nb_fragments; | |||
| video_streams++; | |||
| } else { | |||
| audio_chunks = os->nb_fragments; | |||
| audio_streams++; | |||
| } | |||
| } | |||
| if (!final) { | |||
| duration = 0; | |||
| video_chunks = audio_chunks = 0; | |||
| } | |||
| if (c->window_size) { | |||
| video_chunks = FFMIN(video_chunks, c->window_size); | |||
| audio_chunks = FFMIN(audio_chunks, c->window_size); | |||
| } | |||
| avio_printf(out, "<SmoothStreamingMedia MajorVersion=\"2\" MinorVersion=\"0\" Duration=\"%"PRIu64"\"", duration); | |||
| if (!final) | |||
| avio_printf(out, " IsLive=\"true\" LookAheadFragmentCount=\"%d\" DVRWindowLength=\"0\"", c->lookahead_count); | |||
| avio_printf(out, ">\n"); | |||
| if (c->has_video) { | |||
| int last = -1, index = 0; | |||
| avio_printf(out, "<StreamIndex Type=\"video\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(video={start time})\">\n", video_streams, video_chunks); | |||
| for (i = 0; i < s->nb_streams; i++) { | |||
| OutputStream *os = &c->streams[i]; | |||
| if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_VIDEO) | |||
| continue; | |||
| last = i; | |||
| avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" MaxWidth=\"%d\" MaxHeight=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codec->bit_rate, os->fourcc, s->streams[i]->codec->width, s->streams[i]->codec->height, os->private_str); | |||
| index++; | |||
| } | |||
| output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size); | |||
| avio_printf(out, "</StreamIndex>\n"); | |||
| } | |||
| if (c->has_audio) { | |||
| int last = -1, index = 0; | |||
| avio_printf(out, "<StreamIndex Type=\"audio\" QualityLevels=\"%d\" Chunks=\"%d\" Url=\"QualityLevels({bitrate})/Fragments(audio={start time})\">\n", audio_streams, audio_chunks); | |||
| for (i = 0; i < s->nb_streams; i++) { | |||
| OutputStream *os = &c->streams[i]; | |||
| if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO) | |||
| continue; | |||
| last = i; | |||
| avio_printf(out, "<QualityLevel Index=\"%d\" Bitrate=\"%d\" FourCC=\"%s\" SamplingRate=\"%d\" Channels=\"%d\" BitsPerSample=\"16\" PacketSize=\"%d\" AudioTag=\"%d\" CodecPrivateData=\"%s\" />\n", index, s->streams[i]->codec->bit_rate, os->fourcc, s->streams[i]->codec->sample_rate, s->streams[i]->codec->channels, os->packet_size, os->audio_tag, os->private_str); | |||
| index++; | |||
| } | |||
| output_chunk_list(&c->streams[last], out, final, c->lookahead_count, c->window_size); | |||
| avio_printf(out, "</StreamIndex>\n"); | |||
| } | |||
| avio_printf(out, "</SmoothStreamingMedia>\n"); | |||
| avio_flush(out); | |||
| avio_close(out); | |||
| return 0; | |||
| } | |||
| static int ism_flush(AVFormatContext *s, int final) | |||
| { | |||
| SmoothStreamingContext *c = s->priv_data; | |||
| @@ -550,7 +549,8 @@ static int ism_flush(AVFormatContext *s, int final) | |||
| } | |||
| } | |||
| write_manifest(s, final); | |||
| if (ret >= 0) | |||
| ret = write_manifest(s, final); | |||
| return ret; | |||
| } | |||
| @@ -560,13 +560,15 @@ static int ism_write_packet(AVFormatContext *s, AVPacket *pkt) | |||
| AVStream *st = s->streams[pkt->stream_index]; | |||
| OutputStream *os = &c->streams[pkt->stream_index]; | |||
| int64_t end_pts = (c->nb_fragments + 1) * c->min_frag_duration; | |||
| int ret; | |||
| if ((!c->has_video || st->codec->codec_type == AVMEDIA_TYPE_VIDEO) && | |||
| av_compare_ts(pkt->pts, st->time_base, | |||
| end_pts, AV_TIME_BASE_Q) >= 0 && | |||
| pkt->flags & AV_PKT_FLAG_KEY && os->packets_written) { | |||
| ism_flush(s, 0); | |||
| if ((ret = ism_flush(s, 0)) < 0) | |||
| return ret; | |||
| c->nb_fragments++; | |||
| } | |||
| @@ -389,7 +389,7 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, | |||
| } | |||
| if (tail) { | |||
| unsigned long int alpha; | |||
| double alpha; | |||
| const char *alpha_string = tail; | |||
| if (!strncmp(alpha_string, "0x", 2)) { | |||
| alpha = strtoul(alpha_string, &tail, 16); | |||
| @@ -401,7 +401,7 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, | |||
| alpha = 255 * norm_alpha; | |||
| } | |||
| if (tail == alpha_string || *tail || alpha > 255) { | |||
| if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) { | |||
| av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n", | |||
| alpha_string, color_string); | |||
| return AVERROR(EINVAL); | |||
| @@ -1,3 +1,3 @@ | |||
| e6d8254af2b1ad1f58d60da4d80c6e96 *./tests/data/lavf/lavf.ffm | |||
| c76e8f9a9bcd04379dfa3239e272d049 *./tests/data/lavf/lavf.ffm | |||
| 376832 ./tests/data/lavf/lavf.ffm | |||
| ./tests/data/lavf/lavf.ffm CRC=0x5b136bb1 | |||