From e218c10caacaeb661c4b2027920cd3466b70a525 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 15 May 2014 03:40:17 +0700 Subject: multimedia/ffmpeg2theora: Applied upstream fix for ffmpeg. Signed-off-by: Willy Sudiarto Raharjo --- multimedia/ffmpeg2theora/ffmpeg2theora.SlackBuild | 10 +- .../patches/10-avcodec_max_audio_frame_size.diff | 42 +++ .../20-dont_print_uninitialized_memory.diff | 22 ++ .../patches/30-avcodec_decode_audio4.diff | 405 +++++++++++++++++++++ 4 files changed, 477 insertions(+), 2 deletions(-) create mode 100644 multimedia/ffmpeg2theora/patches/10-avcodec_max_audio_frame_size.diff create mode 100644 multimedia/ffmpeg2theora/patches/20-dont_print_uninitialized_memory.diff create mode 100644 multimedia/ffmpeg2theora/patches/30-avcodec_decode_audio4.diff (limited to 'multimedia') diff --git a/multimedia/ffmpeg2theora/ffmpeg2theora.SlackBuild b/multimedia/ffmpeg2theora/ffmpeg2theora.SlackBuild index 7080fef483..aae5c080f8 100644 --- a/multimedia/ffmpeg2theora/ffmpeg2theora.SlackBuild +++ b/multimedia/ffmpeg2theora/ffmpeg2theora.SlackBuild @@ -29,7 +29,7 @@ PRGNAM="ffmpeg2theora" VERSION=${VERSION:-0.29} -BUILD=${BUILD:-2} +BUILD=${BUILD:-3} TAG=${TAG:-_SBo} if [ -z "$ARCH" ]; then @@ -67,7 +67,13 @@ find -L . \ \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \ -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \; -echo "#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000" >> src/ffmpeg2theora.h +# include some patches cherry-picked from upstream's git. +# two of them are ffmpeg API fixes and one is a small bugfix. +for diff in $CWD/patches/*.diff; do + echo $diff + patch -p1 < $diff +done + scons install APPEND_CCFLAGS="$SLKCFLAGS" prefix=/usr destdir=$PKG find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \ diff --git a/multimedia/ffmpeg2theora/patches/10-avcodec_max_audio_frame_size.diff b/multimedia/ffmpeg2theora/patches/10-avcodec_max_audio_frame_size.diff new file mode 100644 index 0000000000..c8d10b81a9 --- /dev/null +++ b/multimedia/ffmpeg2theora/patches/10-avcodec_max_audio_frame_size.diff @@ -0,0 +1,42 @@ +From: Jan Gerber +Date: Sun, 26 May 2013 13:25:42 +0000 (+0200) +Subject: don't use deprecated AVCODEC_MAX_AUDIO_FRAME_SIZE +X-Git-Url: http://git.xiph.org/?p=ffmpeg2theora.git;a=commitdiff_plain;h=d3435a6a83dc656379de9e6523ecf8d565da6ca6 + +don't use deprecated AVCODEC_MAX_AUDIO_FRAME_SIZE +--- + +diff --git a/src/ffmpeg2theora.c b/src/ffmpeg2theora.c +index cde63b9..8bebf28 100644 +--- a/src/ffmpeg2theora.c ++++ b/src/ffmpeg2theora.c +@@ -47,6 +47,9 @@ + #include "ffmpeg2theora.h" + #include "avinfo.h" + ++#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio ++ ++ + #define LENGTH(x) (sizeof(x) / sizeof(*x)) + + enum { +@@ -1069,8 +1072,8 @@ void ff2theora_output(ff2theora this) { + int first = 1; + int audio_eos = 0, video_eos = 0, audio_done = 0, video_done = 0; + int ret; +- int16_t *audio_buf=av_malloc(4*AVCODEC_MAX_AUDIO_FRAME_SIZE); +- int16_t *resampled=av_malloc(4*AVCODEC_MAX_AUDIO_FRAME_SIZE); ++ int16_t *audio_buf=av_malloc(4*MAX_AUDIO_FRAME_SIZE); ++ int16_t *resampled=av_malloc(4*MAX_AUDIO_FRAME_SIZE); + int16_t *audio_p=NULL; + int no_frames; + int no_samples; +@@ -1531,7 +1534,7 @@ void ff2theora_output(ff2theora this) { + while((audio_eos && !audio_done) || avpkt.size > 0 ) { + int samples=0; + int samples_out=0; +- int data_size = 4*AVCODEC_MAX_AUDIO_FRAME_SIZE; ++ int data_size = 4*MAX_AUDIO_FRAME_SIZE; + int bytes_per_sample = av_get_bytes_per_sample(aenc->sample_fmt); + + if (avpkt.size > 0) { diff --git a/multimedia/ffmpeg2theora/patches/20-dont_print_uninitialized_memory.diff b/multimedia/ffmpeg2theora/patches/20-dont_print_uninitialized_memory.diff new file mode 100644 index 0000000000..ef57b82e41 --- /dev/null +++ b/multimedia/ffmpeg2theora/patches/20-dont_print_uninitialized_memory.diff @@ -0,0 +1,22 @@ +From: Jan Gerber +Date: Fri, 16 Aug 2013 08:40:53 +0000 (+0200) +Subject: print error instead of printing uninitialized memory to terminal if no input is specified +X-Git-Url: http://git.xiph.org/?p=ffmpeg2theora.git;a=commitdiff_plain;h=d462b50fa8d9462b847a4e574b2d50fc4d191352 + +print error instead of printing uninitialized memory to terminal if no input is specified +--- + +diff --git a/src/ffmpeg2theora.c b/src/ffmpeg2theora.c +index 8bebf28..410d502 100644 +--- a/src/ffmpeg2theora.c ++++ b/src/ffmpeg2theora.c +@@ -2773,6 +2773,9 @@ int main(int argc, char **argv) { + outputfile_set=1; + } + optind++; ++ } else { ++ fprintf(stderr, "ERROR: no input specified\n"); ++ exit(1); + } + if(optindstart_time == 0.0; + AVRational display_aspect_ratio, sample_aspect_ratio; + ++ struct SwrContext *swr_ctx; ++ uint8_t **dst_audio_data = NULL; ++ int dst_linesize; ++ int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples; ++ + if (this->audiostream >= 0 && this->context->nb_streams > this->audiostream) { + AVCodecContext *enc = this->context->streams[this->audiostream]->codec; + if (enc->codec_type == AVMEDIA_TYPE_AUDIO) { +@@ -961,22 +971,43 @@ + if (acodec != NULL && avcodec_open2 (aenc, acodec, NULL) >= 0) { + if (this->sample_rate != sample_rate + || this->channels != aenc->channels +- || aenc->sample_fmt != AV_SAMPLE_FMT_S16) { +- // values take from libavcodec/resample.c +- this->audio_resample_ctx = av_audio_resample_init(this->channels, aenc->channels, +- this->sample_rate, sample_rate, +- AV_SAMPLE_FMT_S16, aenc->sample_fmt, +- 16, 10, 0, 0.8); +- if (!this->audio_resample_ctx) { +- this->channels = aenc->channels; ++ || aenc->sample_fmt != AV_SAMPLE_FMT_FLTP) { ++ swr_ctx = swr_alloc(); ++ /* set options */ ++ if (aenc->channel_layout) { ++ av_opt_set_int(swr_ctx, "in_channel_layout", aenc->channel_layout, 0); ++ } else { ++ av_opt_set_int(swr_ctx, "in_channel_layout", av_get_default_channel_layout(aenc->channels), 0); ++ } ++ av_opt_set_int(swr_ctx, "in_sample_rate", aenc->sample_rate, 0); ++ av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", aenc->sample_fmt, 0); ++ ++ av_opt_set_int(swr_ctx, "out_channel_layout", av_get_default_channel_layout(this->channels), 0); ++ av_opt_set_int(swr_ctx, "out_sample_rate", this->sample_rate, 0); ++ av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); ++ ++ /* initialize the resampling context */ ++ if (swr_init(swr_ctx) < 0) { ++ fprintf(stderr, "Failed to initialize the resampling context\n"); ++ exit(1); + } ++ ++ max_dst_nb_samples = dst_nb_samples = ++ av_rescale_rnd(src_nb_samples, this->sample_rate, sample_rate, AV_ROUND_UP); ++ ++ if (av_samples_alloc_array_and_samples(&dst_audio_data, &dst_linesize, this->channels, ++ dst_nb_samples, AV_SAMPLE_FMT_FLTP, 0) < 0) { ++ fprintf(stderr, "Could not allocate destination samples\n"); ++ exit(1); ++ } ++ + if (!info.frontend && this->sample_rate!=sample_rate) + fprintf(stderr, " Resample: %dHz => %dHz\n", sample_rate,this->sample_rate); + if (!info.frontend && this->channels!=aenc->channels) + fprintf(stderr, " Channels: %d => %d\n",aenc->channels,this->channels); + } + else{ +- this->audio_resample_ctx=NULL; ++ swr_ctx = NULL; + } + } + else{ +@@ -1067,13 +1098,12 @@ + AVPacket pkt; + AVPacket avpkt; + int len1; +- int got_picture; ++ int got_frame; + int first = 1; + int audio_eos = 0, video_eos = 0, audio_done = 0, video_done = 0; + int ret; +- int16_t *audio_buf=av_malloc(4*MAX_AUDIO_FRAME_SIZE); +- int16_t *resampled=av_malloc(4*MAX_AUDIO_FRAME_SIZE); +- int16_t *audio_p=NULL; ++ AVFrame *audio_frame = NULL; ++ uint8_t **audio_p = NULL; + int no_frames; + int no_samples; + +@@ -1369,7 +1399,7 @@ + first frame decodec in case its not a keyframe + */ + if (pkt.stream_index == this->video_index) { +- avcodec_decode_video2(venc, frame, &got_picture, &pkt); ++ avcodec_decode_video2(venc, frame, &got_frame, &pkt); + } + av_free_packet (&pkt); + continue; +@@ -1388,9 +1418,9 @@ + while(video_eos || avpkt.size > 0) { + int dups = 0; + static th_ycbcr_buffer ycbcr; +- len1 = avcodec_decode_video2(venc, frame, &got_picture, &avpkt); ++ len1 = avcodec_decode_video2(venc, frame, &got_frame, &avpkt); + if (len1>=0) { +- if (got_picture) { ++ if (got_frame) { + // this is disabled by default since it does not work + // for all input formats the way it should. + if (this->sync == 1 && pkt.dts != AV_NOPTS_VALUE) { +@@ -1427,7 +1457,7 @@ + + if (venc_pix_fmt != this->pix_fmt) { + sws_scale(this->sws_colorspace_ctx, +- frame->data, frame->linesize, 0, display_height, ++ (const uint8_t * const*)frame->data, frame->linesize, 0, display_height, + output_tmp->data, output_tmp->linesize); + } + else{ +@@ -1471,7 +1501,7 @@ + } + if (this->sws_scale_ctx) { + sws_scale(this->sws_scale_ctx, +- output_cropped->data, ++ (const uint8_t * const*)output_cropped->data, + output_cropped->linesize, 0, + display_height - (this->frame_topBand + this->frame_bottomBand), + output_resized->data, +@@ -1499,7 +1529,7 @@ + //now output_resized + + if (!first) { +- if (got_picture || video_eos) { ++ if (got_frame || video_eos) { + prepare_ycbcr_buffer(this, ycbcr, output_buffered); + if(dups>0) { + //this only works if dups < keyint, +@@ -1519,11 +1549,11 @@ + info.videotime = this->frame_count / av_q2d(this->framerate); + } + } +- if (got_picture) { ++ if (got_frame) { + first=0; + av_picture_copy((AVPicture *)output_buffered, (AVPicture *)output_padded, this->pix_fmt, this->frame_width, this->frame_height); + } +- if (!got_picture) { ++ if (!got_frame) { + break; + } + } +@@ -1531,42 +1561,62 @@ + if (info.passno!=1) + if ((audio_eos && !audio_done) || (ret >= 0 && pkt.stream_index == this->audio_index)) { + while((audio_eos && !audio_done) || avpkt.size > 0 ) { +- int samples=0; +- int samples_out=0; +- int data_size = 4*MAX_AUDIO_FRAME_SIZE; + int bytes_per_sample = av_get_bytes_per_sample(aenc->sample_fmt); + + if (avpkt.size > 0) { +- len1 = avcodec_decode_audio3(astream->codec, audio_buf, &data_size, &avpkt); ++ if (!audio_frame && !(audio_frame = avcodec_alloc_frame())) { ++ fprintf(stderr, "Failed to allocate memory\n"); ++ exit(1); ++ } ++ len1 = avcodec_decode_audio4(astream->codec, audio_frame, &got_frame, &avpkt); + if (len1 < 0) { + /* if error, we skip the frame */ + break; + } +- avpkt.size -= len1; +- avpkt.data += len1; +- if (data_size >0) { +- samples = data_size / (aenc->channels * bytes_per_sample); +- samples_out = samples; +- if (this->audio_resample_ctx) { +- samples_out = audio_resample(this->audio_resample_ctx, resampled, audio_buf, samples); +- audio_p = resampled; ++ /* Some audio decoders decode only part of the packet, and have to be ++ * called again with the remainder of the packet data. ++ * Sample: http://fate-suite.libav.org/lossless-audio/luckynight-partial.shn ++ * Also, some decoders might over-read the packet. */ ++ len1 = FFMIN(len1, avpkt.size); ++ if (got_frame) { ++ dst_nb_samples = audio_frame->nb_samples; ++ if (swr_ctx) { ++ dst_nb_samples = av_rescale_rnd(audio_frame->nb_samples, ++ this->sample_rate, aenc->sample_rate, AV_ROUND_UP); ++ if (dst_nb_samples > max_dst_nb_samples) { ++ av_free(dst_audio_data[0]); ++ if (av_samples_alloc(dst_audio_data, &dst_linesize, this->channels, ++ dst_nb_samples, AV_SAMPLE_FMT_FLTP, 1) < 0) { ++ fprintf(stderr, "Error while converting audio\n"); ++ exit(1); ++ } ++ max_dst_nb_samples = dst_nb_samples; ++ } ++ if (swr_convert(swr_ctx, dst_audio_data, dst_nb_samples, ++ (const uint8_t**)audio_frame->extended_data, audio_frame->nb_samples) < 0) { ++ fprintf(stderr, "Error while converting audio\n"); ++ exit(1); ++ } ++ audio_p = dst_audio_data; ++ } else { ++ audio_p = audio_frame->extended_data; + } +- else +- audio_p = audio_buf; + } ++ avpkt.size -= len1; ++ avpkt.data += len1; + } +- +- if (no_samples > 0 && this->sample_count + samples_out > no_samples) { +- audio_eos = 1; +- samples_out = no_samples - this->sample_count; +- if (samples_out <= 0) { +- break; ++ if(got_frame || audio_eos) { ++ if (no_samples > 0 && this->sample_count + dst_nb_samples > no_samples) { ++ audio_eos = 1; ++ dst_nb_samples = no_samples - this->sample_count; ++ if (dst_nb_samples <= 0) { ++ break; ++ } + } ++ oggmux_add_audio(&info, audio_p, dst_nb_samples, audio_eos); ++ avcodec_free_frame(&audio_frame); ++ this->sample_count += dst_nb_samples; + } +- +- oggmux_add_audio(&info, audio_p, +- samples_out * (this->channels), samples_out, audio_eos); +- this->sample_count += samples_out; + if(audio_eos) { + audio_done = 1; + } +@@ -1751,8 +1801,8 @@ + avcodec_close(venc); + } + if (this->audio_index >= 0) { +- if (this->audio_resample_ctx) +- audio_resample_close(this->audio_resample_ctx); ++ if (swr_ctx) ++ swr_free(&swr_ctx); + avcodec_close(aenc); + } + +@@ -1773,8 +1823,12 @@ + frame_dealloc(output_cropped_p); + frame_dealloc(output_padded_p); + } +- av_free(audio_buf); +- av_free(resampled); ++ if (dst_audio_data) ++ av_freep(&dst_audio_data[0]); ++ av_freep(&dst_audio_data); ++ if(swr_ctx) { ++ swr_close(swr_ctx); ++ } + } + else{ + fprintf(stderr, "No video or audio stream found.\n"); +diff -Naur ffmpeg2theora-0.29/src/ffmpeg2theora.c.orig ffmpeg2theora-0.29.patched/src/ffmpeg2theora.c.orig +--- ffmpeg2theora-0.29/src/ffmpeg2theora.c.orig 2014-05-14 14:57:25.000000000 -0400 ++++ ffmpeg2theora-0.29.patched/src/ffmpeg2theora.c.orig 2014-05-14 14:57:30.000000000 -0400 +@@ -2772,6 +2772,9 @@ + outputfile_set=1; + } + optind++; ++ } else { ++ fprintf(stderr, "ERROR: no input specified\n"); ++ exit(1); + } + if(optind ++ ++ //swr does not have the equivalent so this does nothing ++ void swr_close(SwrContext *ctx) {}; ++ ++#else ++ ++ #include ++ ++ #define SwrContext AVAudioResampleContext ++ #define swr_init(ctx) avresample_open(ctx) ++ #define swr_close(ctx) avresample_close(ctx) ++ #define swr_free(ctx) avresample_free(ctx) ++ #define swr_alloc() avresample_alloc_context() ++ #define swr_get_delay(ctx, ...) avresample_get_delay(ctx) ++ #define swr_convert(ctx, out, out_count, in, in_count) \ ++ avresample_convert(ctx, out, 0, out_count, (uint8_t **)in, 0, in_count) ++ ++#endif +diff -Naur ffmpeg2theora-0.29/src/theorautils.c ffmpeg2theora-0.29.patched/src/theorautils.c +--- ffmpeg2theora-0.29/src/theorautils.c 2012-06-21 17:36:01.000000000 -0400 ++++ ffmpeg2theora-0.29.patched/src/theorautils.c 2014-05-14 14:59:43.000000000 -0400 +@@ -1219,17 +1219,16 @@ + /** + * adds audio samples to encoding sink + * @param buffer pointer to buffer +- * @param bytes bytes in buffer + * @param samples samples in buffer + * @param e_o_s 1 indicates end of stream. + */ +-void oggmux_add_audio (oggmux_info *info, int16_t * buffer, int bytes, int samples, int e_o_s) { ++void oggmux_add_audio (oggmux_info *info, uint8_t **buffer, int samples, int e_o_s) { + ogg_packet op; + + int i, j, k, count = 0; + float **vorbis_buffer; + +- if (bytes <= 0 && samples <= 0) { ++ if (samples <= 0) { + /* end of audio stream */ + if (e_o_s) + vorbis_analysis_wrote (&info->vd, 0); +@@ -1252,7 +1251,7 @@ + default: k = j; + } + } +- vorbis_buffer[k][i] = buffer[count++] / 32768.f; ++ vorbis_buffer[k][i] = ((const float *)buffer[j])[i]; + } + } + vorbis_analysis_wrote (&info->vd, samples); +@@ -1291,8 +1290,8 @@ + if (op.packetno != 4) { + /* We only expect negative start granule in the first content + packet, not any of the others... */ +- fprintf(stderr, "WARNING: vorbis packet %lld has calculated start" +- " granule of %lld, but it should be non-negative!", ++ fprintf(stderr, "WARNING: vorbis packet %" PRId64 " has calculated start" ++ " granule of %" PRId64 ", but it should be non-negative!", + op.packetno, start_granule); + } + start_granule = 0; +@@ -1302,7 +1301,7 @@ + allowed by the specification in the last packet only, and the + trailing samples should be discarded and not played/indexed. */ + if (!op.e_o_s) { +- fprintf(stderr, "WARNING: vorbis packet %lld (granulepos %lld) starts before" ++ fprintf(stderr, "WARNING: vorbis packet %" PRId64 " (granulepos %" PRId64 ") starts before" + " the end of the preceeding packet!", op.packetno, op.granulepos); + } + start_granule = info->vorbis_granulepos; +diff -Naur ffmpeg2theora-0.29/src/theorautils.h ffmpeg2theora-0.29.patched/src/theorautils.h +--- ffmpeg2theora-0.29/src/theorautils.h 2011-09-15 16:20:46.000000000 -0400 ++++ ffmpeg2theora-0.29.patched/src/theorautils.h 2014-05-14 14:59:43.000000000 -0400 +@@ -168,7 +168,7 @@ + extern void oggmux_setup_kate_streams(oggmux_info *info, int n_kate_streams); + extern void oggmux_init (oggmux_info *info); + extern void oggmux_add_video (oggmux_info *info, th_ycbcr_buffer ycbcr, int e_o_s); +-extern void oggmux_add_audio (oggmux_info *info, int16_t * readbuffer, int bytesread, int samplesread,int e_o_s); ++extern void oggmux_add_audio (oggmux_info *info, uint8_t **buffer, int samples,int e_o_s); + #ifdef HAVE_KATE + extern void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len, int x1, int x2, int y1, int y2); + extern void oggmux_add_kate_image (oggmux_info *info, int idx, double t0, double t1, const kate_region *kr, const kate_palette *kp, const kate_bitmap *kb); -- cgit v1.2.3