* qatar/master: Handle unicode file names on windows rtp: Rename the open/close functions to alloc/free Lowercase all ff* program names. Refer to ff* tools by their lowercase names. NOT Pulled Replace more FFmpeg instances by Libav or ffmpeg. Replace `` by $() syntax in shell scripts. patcheck: Allow overiding grep program(s) through environment variables. NOT Pulled Remove stray libavcore and _g binary references. vorbis: Rename decoder/encoder files to follow general file naming scheme. aacenc: Fix whitespace after last commit. cook: Fix small typo in av_log_ask_for_sample message. aacenc: Finish 3GPP psymodel analysis for non mid/side cases. Remove RDFT dependency from AAC decoder. Add some debug log messages to AAC extradata Fix mov debug (u)int64_t format strings. bswap: use native types for av_bwap16(). doc: FLV muxing is supported. applehttp: Handle AES-128 encrypted streams Add a protocol handler for AES CBC decryption with PKCS7 padding doc: Mention that DragonFly BSD requires __BSD_VISIBLE set Conflicts: ffplay.c ffprobe.c Merged-by: Michael Niedermayer <michaelni@gmx.at>tags/n0.8
| @@ -153,6 +153,66 @@ static const OptionDef* find_option(const OptionDef *po, const char *name){ | |||
| return po; | |||
| } | |||
| #if defined(_WIN32) && !defined(__MINGW32CE__) | |||
| /* Will be leaked on exit */ | |||
| static char** win32_argv_utf8 = NULL; | |||
| static int win32_argc = 0; | |||
| /** | |||
| * Prepare command line arguments for executable. | |||
| * For Windows - perform wide-char to UTF-8 conversion. | |||
| * Input arguments should be main() function arguments. | |||
| * @param argc_ptr Arguments number (including executable) | |||
| * @param argv_ptr Arguments list. | |||
| */ | |||
| static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) | |||
| { | |||
| char *argstr_flat; | |||
| wchar_t **argv_w; | |||
| int i, buffsize = 0, offset = 0; | |||
| if (win32_argv_utf8) { | |||
| *argc_ptr = win32_argc; | |||
| *argv_ptr = win32_argv_utf8; | |||
| return; | |||
| } | |||
| win32_argc = 0; | |||
| argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc); | |||
| if (win32_argc <= 0 || !argv_w) | |||
| return; | |||
| /* determine the UTF-8 buffer size (including NULL-termination symbols) */ | |||
| for (i = 0; i < win32_argc; i++) | |||
| buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, | |||
| NULL, 0, NULL, NULL); | |||
| win32_argv_utf8 = av_mallocz(sizeof(char*) * (win32_argc + 1) + buffsize); | |||
| argstr_flat = (char*)win32_argv_utf8 + sizeof(char*) * (win32_argc + 1); | |||
| if (win32_argv_utf8 == NULL) { | |||
| LocalFree(argv_w); | |||
| return; | |||
| } | |||
| for (i = 0; i < win32_argc; i++) { | |||
| win32_argv_utf8[i] = &argstr_flat[offset]; | |||
| offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, | |||
| &argstr_flat[offset], | |||
| buffsize - offset, NULL, NULL); | |||
| } | |||
| win32_argv_utf8[i] = NULL; | |||
| LocalFree(argv_w); | |||
| *argc_ptr = win32_argc; | |||
| *argv_ptr = win32_argv_utf8; | |||
| } | |||
| #else | |||
| static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) | |||
| { | |||
| /* nothing to do */ | |||
| } | |||
| #endif /* WIN32 && !__MINGW32CE__ */ | |||
| void parse_options(int argc, char **argv, const OptionDef *options, | |||
| void (* parse_arg_function)(const char*)) | |||
| { | |||
| @@ -160,6 +220,9 @@ void parse_options(int argc, char **argv, const OptionDef *options, | |||
| int optindex, handleoptions=1; | |||
| const OptionDef *po; | |||
| /* perform system-dependent conversions for arguments list */ | |||
| prepare_app_arguments(&argc, &argv); | |||
| /* parse options */ | |||
| optindex = 1; | |||
| while (optindex < argc) { | |||
| @@ -1248,7 +1248,7 @@ mdct_select="fft" | |||
| rdft_select="fft" | |||
| # decoders / encoders / hardware accelerators | |||
| aac_decoder_select="mdct rdft sinewin" | |||
| aac_decoder_select="mdct sinewin" | |||
| aac_encoder_select="mdct sinewin" | |||
| aac_latm_decoder_select="aac_decoder aac_latm_parser" | |||
| ac3_decoder_select="mdct ac3dsp ac3_parser" | |||
| @@ -280,7 +280,7 @@ Just create an "input.avs" text file with this single line ... | |||
| @example | |||
| DirectShowSource("C:\path to your file\yourfile.asf") | |||
| @end example | |||
| ... and then feed that text file to FFmpeg: | |||
| ... and then feed that text file to ffmpeg: | |||
| @example | |||
| ffmpeg -i input.avs | |||
| @end example | |||
| @@ -348,7 +348,7 @@ ffmpeg -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i all.a \ | |||
| rm temp[12].[av] all.[av] | |||
| @end example | |||
| @section FFmpeg does not adhere to the -maxrate setting, some frames are bigger than maxrate/fps. | |||
| @section The ffmpeg program does not respect the -maxrate setting, some frames are bigger than maxrate/fps. | |||
| Read the MPEG spec about video buffer verifier. | |||
| @@ -1,8 +1,8 @@ | |||
| \input texinfo @c -*- texinfo -*- | |||
| @settitle FFmpeg Documentation | |||
| @settitle ffmpeg Documentation | |||
| @titlepage | |||
| @center @titlefont{FFmpeg Documentation} | |||
| @center @titlefont{ffmpeg Documentation} | |||
| @end titlepage | |||
| @top | |||
| @@ -22,17 +22,15 @@ ffmpeg [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{ | |||
| @chapter Description | |||
| @c man begin DESCRIPTION | |||
| FFmpeg is a very fast video and audio converter. It can also grab from | |||
| a live audio/video source. | |||
| ffmpeg is a very fast video and audio converter that can also grab from | |||
| a live audio/video source. It can also convert between arbitrary sample | |||
| rates and resize video on the fly with a high quality polyphase filter. | |||
| The command line interface is designed to be intuitive, in the sense | |||
| that FFmpeg tries to figure out all parameters that can possibly be | |||
| that ffmpeg tries to figure out all parameters that can possibly be | |||
| derived automatically. You usually only have to specify the target | |||
| bitrate you want. | |||
| FFmpeg can also convert from any sample rate to any other, and resize | |||
| video on the fly with a high quality polyphase filter. | |||
| As a general rule, options are applied to the next specified | |||
| file. Therefore, order is important, and you can have the same | |||
| option on the command line multiple times. Each occurrence is | |||
| @@ -61,7 +59,7 @@ ffmpeg -r 1 -i input.m2v -r 24 output.avi | |||
| The format option may be needed for raw input files. | |||
| By default, FFmpeg tries to convert as losslessly as possible: It | |||
| By default ffmpeg tries to convert as losslessly as possible: It | |||
| uses the same audio and video parameters for the outputs as the one | |||
| specified for the inputs. | |||
| @@ -495,7 +493,7 @@ Use 'frames' B-frames (supported for MPEG-1, MPEG-2 and MPEG-4). | |||
| macroblock decision | |||
| @table @samp | |||
| @item 0 | |||
| FF_MB_DECISION_SIMPLE: Use mb_cmp (cannot change it yet in FFmpeg). | |||
| FF_MB_DECISION_SIMPLE: Use mb_cmp (cannot change it yet in ffmpeg). | |||
| @item 1 | |||
| FF_MB_DECISION_BITS: Choose the one which needs the fewest bits. | |||
| @item 2 | |||
| @@ -877,22 +875,22 @@ It allows almost lossless encoding. | |||
| @section Video and Audio grabbing | |||
| FFmpeg can grab video and audio from devices given that you specify the input | |||
| format and device. | |||
| If you specify the input format and device then ffmpeg can grab video | |||
| and audio directly. | |||
| @example | |||
| ffmpeg -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg | |||
| @end example | |||
| Note that you must activate the right video source and channel before | |||
| launching FFmpeg with any TV viewer such as xawtv | |||
| launching ffmpeg with any TV viewer such as xawtv | |||
| (@url{http://linux.bytesex.org/xawtv/}) by Gerd Knorr. You also | |||
| have to set the audio recording levels correctly with a | |||
| standard mixer. | |||
| @section X11 grabbing | |||
| FFmpeg can grab the X11 display. | |||
| Grab the X11 display with ffmpeg via | |||
| @example | |||
| ffmpeg -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg | |||
| @@ -910,7 +908,7 @@ variable. 10 is the x-offset and 20 the y-offset for the grabbing. | |||
| @section Video and Audio file format conversion | |||
| FFmpeg can use any supported file format and protocol as input: | |||
| Any supported file format and protocol can serve as input to ffmpeg: | |||
| Examples: | |||
| @itemize | |||
| @@ -930,7 +928,7 @@ It will use the files: | |||
| The Y files use twice the resolution of the U and V files. They are | |||
| raw files, without header. They can be generated by all decent video | |||
| decoders. You must specify the size of the image with the @option{-s} option | |||
| if FFmpeg cannot guess it. | |||
| if ffmpeg cannot guess it. | |||
| @item | |||
| You can input from a raw YUV420P file: | |||
| @@ -1057,7 +1055,7 @@ file to which you want to add them. | |||
| @ignore | |||
| @setfilename ffmpeg | |||
| @settitle FFmpeg video converter | |||
| @settitle ffmpeg video converter | |||
| @c man begin SEEALSO | |||
| ffplay(1), ffprobe(1), ffserver(1) and the FFmpeg HTML documentation | |||
| @@ -1,8 +1,8 @@ | |||
| \input texinfo @c -*- texinfo -*- | |||
| @settitle FFplay Documentation | |||
| @settitle ffplay Documentation | |||
| @titlepage | |||
| @center @titlefont{FFplay Documentation} | |||
| @center @titlefont{ffplay Documentation} | |||
| @end titlepage | |||
| @top | |||
| @@ -1,8 +1,8 @@ | |||
| \input texinfo @c -*- texinfo -*- | |||
| @settitle FFprobe Documentation | |||
| @settitle ffprobe Documentation | |||
| @titlepage | |||
| @center @titlefont{FFprobe Documentation} | |||
| @center @titlefont{ffprobe Documentation} | |||
| @end titlepage | |||
| @top | |||
| @@ -22,7 +22,7 @@ ffprobe [options] [@file{input_file}] | |||
| @chapter Description | |||
| @c man begin DESCRIPTION | |||
| FFprobe gathers information from multimedia streams and prints it in | |||
| ffprobe gathers information from multimedia streams and prints it in | |||
| human- and machine-readable fashion. | |||
| For example it can be used to check the format of the container used | |||
| @@ -33,7 +33,7 @@ If a filename is specified in input, ffprobe will try to open and | |||
| probe the file content. If the file cannot be opened or recognized as | |||
| a multimedia file, a positive exit code is returned. | |||
| FFprobe may be employed both as a standalone application or in | |||
| ffprobe may be employed both as a standalone application or in | |||
| combination with a textual filter, which may perform more | |||
| sophisticated processing, e.g. statistical processing or plotting. | |||
| @@ -41,7 +41,7 @@ Options are used to list some of the formats supported by ffprobe or | |||
| for specifying which information to display, and for setting how | |||
| ffprobe will show it. | |||
| FFprobe output is designed to be easily parsable by a textual filter, | |||
| ffprobe output is designed to be easily parsable by a textual filter, | |||
| and consists of one or more sections of the form: | |||
| @example | |||
| [SECTION] | |||
| @@ -119,7 +119,7 @@ with name "STREAM". | |||
| @ignore | |||
| @setfilename ffprobe | |||
| @settitle FFprobe media prober | |||
| @settitle ffprobe media prober | |||
| @c man begin SEEALSO | |||
| ffmpeg(1), ffplay(1), ffserver(1) and the FFmpeg HTML documentation | |||
| @@ -1,8 +1,8 @@ | |||
| \input texinfo @c -*- texinfo -*- | |||
| @settitle FFserver Documentation | |||
| @settitle ffserver Documentation | |||
| @titlepage | |||
| @center @titlefont{FFserver Documentation} | |||
| @center @titlefont{ffserver Documentation} | |||
| @end titlepage | |||
| @top | |||
| @@ -22,12 +22,12 @@ ffserver [options] | |||
| @chapter Description | |||
| @c man begin DESCRIPTION | |||
| FFserver is a streaming server for both audio and video. It supports | |||
| ffserver is a streaming server for both audio and video. It supports | |||
| several live feeds, streaming from files and time shifting on live feeds | |||
| (you can seek to positions in the past on each live feed, provided you | |||
| specify a big enough feed storage in ffserver.conf). | |||
| FFserver runs in daemon mode by default; that is, it puts itself in | |||
| ffserver runs in daemon mode by default; that is, it puts itself in | |||
| the background and detaches from its TTY, unless it is launched in | |||
| debug mode or a NoDaemon option is specified in the configuration | |||
| file. | |||
| @@ -39,7 +39,7 @@ information. | |||
| @section How does it work? | |||
| FFserver receives prerecorded files or FFM streams from some ffmpeg | |||
| ffserver receives prerecorded files or FFM streams from some ffmpeg | |||
| instance as input, then streams them over RTP/RTSP/HTTP. | |||
| An ffserver instance will listen on some port as specified in the | |||
| @@ -57,7 +57,7 @@ file. | |||
| @section Status stream | |||
| FFserver supports an HTTP interface which exposes the current status | |||
| ffserver supports an HTTP interface which exposes the current status | |||
| of the server. | |||
| Simply point your browser to the address of the special status stream | |||
| @@ -249,8 +249,8 @@ For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}. | |||
| Use @file{configfile} instead of @file{/etc/ffserver.conf}. | |||
| @item -n | |||
| Enable no-launch mode. This option disables all the Launch directives | |||
| within the various <Stream> sections. FFserver will not launch any | |||
| ffmpeg instance, so you will have to launch them manually. | |||
| within the various <Stream> sections. Since ffserver will not launch | |||
| any ffmpeg instances, you will have to launch them manually. | |||
| @item -d | |||
| Enable debug mode. This option increases log verbosity, directs log | |||
| messages to stdout and causes ffserver to run in the foreground | |||
| @@ -261,7 +261,7 @@ rather than as a daemon. | |||
| @ignore | |||
| @setfilename ffserver | |||
| @settitle FFserver video server | |||
| @settitle ffserver video server | |||
| @c man begin SEEALSO | |||
| @@ -789,9 +789,9 @@ to configure. | |||
| BSD make will not build FFmpeg, you need to install and use GNU Make | |||
| (@file{gmake}). | |||
| @subsubsection FreeBSD | |||
| @subsubsection FreeBSD, DragonFly BSD | |||
| FreeBSD will not compile out-of-the-box due to broken system headers. | |||
| These systems will not compile out-of-the-box due to broken system headers. | |||
| Passing @code{--extra-cflags=-D__BSD_VISIBLE} to configure will work | |||
| around the problem. This may have unexpected sideeffects, so use it at | |||
| your own risk. If you care about FreeBSD, please make an attempt at | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * FFmpeg main | |||
| * ffmpeg main | |||
| * Copyright (c) 2000-2003 Fabrice Bellard | |||
| * | |||
| * This file is part of FFmpeg. | |||
| @@ -85,7 +85,7 @@ | |||
| #include "libavutil/avassert.h" | |||
| const char program_name[] = "FFmpeg"; | |||
| const char program_name[] = "ffmpeg"; | |||
| const int program_birth_year = 2000; | |||
| /* select an input stream for an output stream */ | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * FFplay : Simple Media Player based on the FFmpeg libraries | |||
| * ffplay : Simple Media Player based on the FFmpeg libraries | |||
| * Copyright (c) 2003 Fabrice Bellard | |||
| * | |||
| * This file is part of FFmpeg. | |||
| @@ -56,7 +56,7 @@ | |||
| #include <unistd.h> | |||
| #include <assert.h> | |||
| const char program_name[] = "FFplay"; | |||
| const char program_name[] = "ffplay"; | |||
| const int program_birth_year = 2003; | |||
| //#define DEBUG | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * FFprobe : Simple Media Prober based on the FFmpeg libraries | |||
| * ffprobe : Simple Media Prober based on the FFmpeg libraries | |||
| * Copyright (c) 2007-2010 Stefano Sabatini | |||
| * | |||
| * This file is part of FFmpeg. | |||
| @@ -28,7 +28,7 @@ | |||
| #include "libavdevice/avdevice.h" | |||
| #include "cmdutils.h" | |||
| const char program_name[] = "FFprobe"; | |||
| const char program_name[] = "ffprobe"; | |||
| const int program_birth_year = 2007; | |||
| static int do_show_format = 0; | |||
| @@ -59,7 +59,7 @@ | |||
| #include "cmdutils.h" | |||
| const char program_name[] = "FFserver"; | |||
| const char program_name[] = "ffserver"; | |||
| const int program_birth_year = 2000; | |||
| static const OptionDef options[]; | |||
| @@ -392,9 +392,9 @@ OBJS-$(CONFIG_VCR1_ENCODER) += vcr1.o | |||
| OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdav.o | |||
| OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdav.o | |||
| OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o | |||
| OBJS-$(CONFIG_VORBIS_DECODER) += vorbis_dec.o vorbis.o \ | |||
| OBJS-$(CONFIG_VORBIS_DECODER) += vorbisdec.o vorbis.o \ | |||
| vorbis_data.o xiph.o | |||
| OBJS-$(CONFIG_VORBIS_ENCODER) += vorbis_enc.o vorbis.o \ | |||
| OBJS-$(CONFIG_VORBIS_ENCODER) += vorbisenc.o vorbis.o \ | |||
| vorbis_data.o | |||
| OBJS-$(CONFIG_VP3_DECODER) += vp3.o vp3dsp.o | |||
| OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp56dsp.o \ | |||
| @@ -463,6 +463,11 @@ static int decode_audio_specific_config(AACContext *ac, | |||
| GetBitContext gb; | |||
| int i; | |||
| av_dlog(avctx, "extradata size %d\n", avctx->extradata_size); | |||
| for (i = 0; i < avctx->extradata_size; i++) | |||
| av_dlog(avctx, "%02x ", avctx->extradata[i]); | |||
| av_dlog(avctx, "\n"); | |||
| init_get_bits(&gb, data, data_size * 8); | |||
| if ((i = ff_mpeg4audio_get_config(m4ac, data, data_size)) < 0) | |||
| @@ -489,6 +494,10 @@ static int decode_audio_specific_config(AACContext *ac, | |||
| return -1; | |||
| } | |||
| av_dlog(avctx, "AOT %d chan config %d sampling index %d (%d) SBR %d PS %d\n", | |||
| m4ac->object_type, m4ac->chan_config, m4ac->sampling_index, | |||
| m4ac->sample_rate, m4ac->sbr, m4ac->ps); | |||
| return get_bits_count(&gb); | |||
| } | |||
| @@ -606,8 +606,10 @@ static int aac_encode_frame(AVCodecContext *avctx, | |||
| } | |||
| frame_bits = put_bits_count(&s->pb); | |||
| if (frame_bits <= 6144 * avctx->channels - 3) | |||
| if (frame_bits <= 6144 * avctx->channels - 3) { | |||
| s->psy.bitres.bits = frame_bits / avctx->channels; | |||
| break; | |||
| } | |||
| s->lambda *= avctx->bit_rate * 1024.0f / avctx->sample_rate / frame_bits; | |||
| @@ -30,7 +30,6 @@ | |||
| /*********************************** | |||
| * TODOs: | |||
| * thresholds linearization after their modifications for attaining given bitrate | |||
| * try other bitrate controlling mechanism (maybe use ratecontrol.c?) | |||
| * control quality for quality-based output | |||
| **********************************/ | |||
| @@ -41,10 +40,51 @@ | |||
| */ | |||
| #define PSY_3GPP_THR_SPREAD_HI 1.5f // spreading factor for low-to-hi threshold spreading (15 dB/Bark) | |||
| #define PSY_3GPP_THR_SPREAD_LOW 3.0f // spreading factor for hi-to-low threshold spreading (30 dB/Bark) | |||
| /* spreading factor for low-to-hi energy spreading, long block, > 22kbps/channel (20dB/Bark) */ | |||
| #define PSY_3GPP_EN_SPREAD_HI_L1 2.0f | |||
| /* spreading factor for low-to-hi energy spreading, long block, <= 22kbps/channel (15dB/Bark) */ | |||
| #define PSY_3GPP_EN_SPREAD_HI_L2 1.5f | |||
| /* spreading factor for low-to-hi energy spreading, short block (15 dB/Bark) */ | |||
| #define PSY_3GPP_EN_SPREAD_HI_S 1.5f | |||
| /* spreading factor for hi-to-low energy spreading, long block (30dB/Bark) */ | |||
| #define PSY_3GPP_EN_SPREAD_LOW_L 3.0f | |||
| /* spreading factor for hi-to-low energy spreading, short block (20dB/Bark) */ | |||
| #define PSY_3GPP_EN_SPREAD_LOW_S 2.0f | |||
| #define PSY_3GPP_RPEMIN 0.01f | |||
| #define PSY_3GPP_RPELEV 2.0f | |||
| #define PSY_3GPP_C1 3.0f /* log2(8) */ | |||
| #define PSY_3GPP_C2 1.3219281f /* log2(2.5) */ | |||
| #define PSY_3GPP_C3 0.55935729f /* 1 - C2 / C1 */ | |||
| #define PSY_SNR_1DB 7.9432821e-1f /* -1dB */ | |||
| #define PSY_SNR_25DB 3.1622776e-3f /* -25dB */ | |||
| #define PSY_3GPP_SAVE_SLOPE_L -0.46666667f | |||
| #define PSY_3GPP_SAVE_SLOPE_S -0.36363637f | |||
| #define PSY_3GPP_SAVE_ADD_L -0.84285712f | |||
| #define PSY_3GPP_SAVE_ADD_S -0.75f | |||
| #define PSY_3GPP_SPEND_SLOPE_L 0.66666669f | |||
| #define PSY_3GPP_SPEND_SLOPE_S 0.81818181f | |||
| #define PSY_3GPP_SPEND_ADD_L -0.35f | |||
| #define PSY_3GPP_SPEND_ADD_S -0.26111111f | |||
| #define PSY_3GPP_CLIP_LO_L 0.2f | |||
| #define PSY_3GPP_CLIP_LO_S 0.2f | |||
| #define PSY_3GPP_CLIP_HI_L 0.95f | |||
| #define PSY_3GPP_CLIP_HI_S 0.75f | |||
| #define PSY_3GPP_AH_THR_LONG 0.5f | |||
| #define PSY_3GPP_AH_THR_SHORT 0.63f | |||
| enum { | |||
| PSY_3GPP_AH_NONE, | |||
| PSY_3GPP_AH_INACTIVE, | |||
| PSY_3GPP_AH_ACTIVE | |||
| }; | |||
| #define PSY_3GPP_BITS_TO_PE(bits) ((bits) * 1.18f) | |||
| /* LAME psy model constants */ | |||
| #define PSY_LAME_FIR_LEN 21 ///< LAME psy model FIR order | |||
| #define AAC_BLOCK_SIZE_LONG 1024 ///< long block size | |||
| @@ -60,9 +100,15 @@ | |||
| * information for single band used by 3GPP TS26.403-inspired psychoacoustic model | |||
| */ | |||
| typedef struct AacPsyBand{ | |||
| float energy; ///< band energy | |||
| float thr; ///< energy threshold | |||
| float thr_quiet; ///< threshold in quiet | |||
| float energy; ///< band energy | |||
| float thr; ///< energy threshold | |||
| float thr_quiet; ///< threshold in quiet | |||
| float nz_lines; ///< number of non-zero spectral lines | |||
| float active_lines; ///< number of active spectral lines | |||
| float pe; ///< perceptual entropy | |||
| float pe_const; ///< constant part of the PE calculation | |||
| float norm_fac; ///< normalization factor for linearization | |||
| int avoid_holes; ///< hole avoidance flag | |||
| }AacPsyBand; | |||
| /** | |||
| @@ -97,6 +143,15 @@ typedef struct AacPsyCoeffs{ | |||
| * 3GPP TS26.403-inspired psychoacoustic model specific data | |||
| */ | |||
| typedef struct AacPsyContext{ | |||
| int chan_bitrate; ///< bitrate per channel | |||
| int frame_bits; ///< average bits per frame | |||
| int fill_level; ///< bit reservoir fill level | |||
| struct { | |||
| float min; ///< minimum allowed PE for bit factor calculation | |||
| float max; ///< maximum allowed PE for bit factor calculation | |||
| float previous; ///< allowed PE of the previous frame | |||
| float correction; ///< PE correction factor | |||
| } pe; | |||
| AacPsyCoeffs psy_coef[2][64]; | |||
| AacPsyChannel *ch; | |||
| }AacPsyContext; | |||
| @@ -235,16 +290,33 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) { | |||
| AacPsyContext *pctx; | |||
| float bark; | |||
| int i, j, g, start; | |||
| float prev, minscale, minath; | |||
| float prev, minscale, minath, minsnr, pe_min; | |||
| const int chan_bitrate = ctx->avctx->bit_rate / ctx->avctx->channels; | |||
| const int bandwidth = ctx->avctx->cutoff ? ctx->avctx->cutoff : ctx->avctx->sample_rate / 2; | |||
| const float num_bark = calc_bark((float)bandwidth); | |||
| ctx->model_priv_data = av_mallocz(sizeof(AacPsyContext)); | |||
| pctx = (AacPsyContext*) ctx->model_priv_data; | |||
| pctx->chan_bitrate = chan_bitrate; | |||
| pctx->frame_bits = chan_bitrate * AAC_BLOCK_SIZE_LONG / ctx->avctx->sample_rate; | |||
| pctx->pe.min = 8.0f * AAC_BLOCK_SIZE_LONG * bandwidth / (ctx->avctx->sample_rate * 2.0f); | |||
| pctx->pe.max = 12.0f * AAC_BLOCK_SIZE_LONG * bandwidth / (ctx->avctx->sample_rate * 2.0f); | |||
| ctx->bitres.size = 6144 - pctx->frame_bits; | |||
| ctx->bitres.size -= ctx->bitres.size % 8; | |||
| pctx->fill_level = ctx->bitres.size; | |||
| minath = ath(3410, ATH_ADD); | |||
| for (j = 0; j < 2; j++) { | |||
| AacPsyCoeffs *coeffs = pctx->psy_coef[j]; | |||
| const uint8_t *band_sizes = ctx->bands[j]; | |||
| float line_to_frequency = ctx->avctx->sample_rate / (j ? 256.f : 2048.0f); | |||
| float avg_chan_bits = chan_bitrate / ctx->avctx->sample_rate * (j ? 128.0f : 1024.0f); | |||
| /* reference encoder uses 2.4% here instead of 60% like the spec says */ | |||
| float bark_pe = 0.024f * PSY_3GPP_BITS_TO_PE(avg_chan_bits) / num_bark; | |||
| float en_spread_low = j ? PSY_3GPP_EN_SPREAD_LOW_S : PSY_3GPP_EN_SPREAD_LOW_L; | |||
| /* High energy spreading for long blocks <= 22kbps/channel and short blocks are the same. */ | |||
| float en_spread_hi = (j || (chan_bitrate <= 22.0f)) ? PSY_3GPP_EN_SPREAD_HI_S : PSY_3GPP_EN_SPREAD_HI_L1; | |||
| i = 0; | |||
| prev = 0.0; | |||
| for (g = 0; g < ctx->num_bands[j]; g++) { | |||
| @@ -258,6 +330,11 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) { | |||
| float bark_width = coeffs[g+1].barks - coeffs->barks; | |||
| coeff->spread_low[0] = pow(10.0, -bark_width * PSY_3GPP_THR_SPREAD_LOW); | |||
| coeff->spread_hi [0] = pow(10.0, -bark_width * PSY_3GPP_THR_SPREAD_HI); | |||
| coeff->spread_low[1] = pow(10.0, -bark_width * en_spread_low); | |||
| coeff->spread_hi [1] = pow(10.0, -bark_width * en_spread_hi); | |||
| pe_min = bark_pe * bark_width; | |||
| minsnr = pow(2.0f, pe_min / band_sizes[g]) - 1.5f; | |||
| coeff->min_snr = av_clipf(1.0f / minsnr, PSY_SNR_25DB, PSY_SNR_1DB); | |||
| } | |||
| start = 0; | |||
| for (g = 0; g < ctx->num_bands[j]; g++) { | |||
| @@ -385,6 +462,97 @@ static FFPsyWindowInfo psy_3gpp_window(FFPsyContext *ctx, | |||
| return wi; | |||
| } | |||
| /* 5.6.1.2 "Calculation of Bit Demand" */ | |||
| static int calc_bit_demand(AacPsyContext *ctx, float pe, int bits, int size, | |||
| int short_window) | |||
| { | |||
| const float bitsave_slope = short_window ? PSY_3GPP_SAVE_SLOPE_S : PSY_3GPP_SAVE_SLOPE_L; | |||
| const float bitsave_add = short_window ? PSY_3GPP_SAVE_ADD_S : PSY_3GPP_SAVE_ADD_L; | |||
| const float bitspend_slope = short_window ? PSY_3GPP_SPEND_SLOPE_S : PSY_3GPP_SPEND_SLOPE_L; | |||
| const float bitspend_add = short_window ? PSY_3GPP_SPEND_ADD_S : PSY_3GPP_SPEND_ADD_L; | |||
| const float clip_low = short_window ? PSY_3GPP_CLIP_LO_S : PSY_3GPP_CLIP_LO_L; | |||
| const float clip_high = short_window ? PSY_3GPP_CLIP_HI_S : PSY_3GPP_CLIP_HI_L; | |||
| float clipped_pe, bit_save, bit_spend, bit_factor, fill_level; | |||
| ctx->fill_level += ctx->frame_bits - bits; | |||
| ctx->fill_level = av_clip(ctx->fill_level, 0, size); | |||
| fill_level = av_clipf((float)ctx->fill_level / size, clip_low, clip_high); | |||
| clipped_pe = av_clipf(pe, ctx->pe.min, ctx->pe.max); | |||
| bit_save = (fill_level + bitsave_add) * bitsave_slope; | |||
| assert(bit_save <= 0.3f && bit_save >= -0.05000001f); | |||
| bit_spend = (fill_level + bitspend_add) * bitspend_slope; | |||
| assert(bit_spend <= 0.5f && bit_spend >= -0.1f); | |||
| /* The bit factor graph in the spec is obviously incorrect. | |||
| * bit_spend + ((bit_spend - bit_spend))... | |||
| * The reference encoder subtracts everything from 1, but also seems incorrect. | |||
| * 1 - bit_save + ((bit_spend + bit_save))... | |||
| * Hopefully below is correct. | |||
| */ | |||
| bit_factor = 1.0f - bit_save + ((bit_spend - bit_save) / (ctx->pe.max - ctx->pe.min)) * (clipped_pe - ctx->pe.min); | |||
| /* NOTE: The reference encoder attempts to center pe max/min around the current pe. */ | |||
| ctx->pe.max = FFMAX(pe, ctx->pe.max); | |||
| ctx->pe.min = FFMIN(pe, ctx->pe.min); | |||
| return FFMIN(ctx->frame_bits * bit_factor, ctx->frame_bits + size - bits); | |||
| } | |||
| static float calc_pe_3gpp(AacPsyBand *band) | |||
| { | |||
| float pe, a; | |||
| band->pe = 0.0f; | |||
| band->pe_const = 0.0f; | |||
| band->active_lines = 0.0f; | |||
| if (band->energy > band->thr) { | |||
| a = log2f(band->energy); | |||
| pe = a - log2f(band->thr); | |||
| band->active_lines = band->nz_lines; | |||
| if (pe < PSY_3GPP_C1) { | |||
| pe = pe * PSY_3GPP_C3 + PSY_3GPP_C2; | |||
| a = a * PSY_3GPP_C3 + PSY_3GPP_C2; | |||
| band->active_lines *= PSY_3GPP_C3; | |||
| } | |||
| band->pe = pe * band->nz_lines; | |||
| band->pe_const = a * band->nz_lines; | |||
| } | |||
| return band->pe; | |||
| } | |||
| static float calc_reduction_3gpp(float a, float desired_pe, float pe, | |||
| float active_lines) | |||
| { | |||
| float thr_avg, reduction; | |||
| thr_avg = powf(2.0f, (a - pe) / (4.0f * active_lines)); | |||
| reduction = powf(2.0f, (a - desired_pe) / (4.0f * active_lines)) - thr_avg; | |||
| return FFMAX(reduction, 0.0f); | |||
| } | |||
| static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr, | |||
| float reduction) | |||
| { | |||
| float thr = band->thr; | |||
| if (band->energy > thr) { | |||
| thr = powf(thr, 0.25f) + reduction; | |||
| thr = powf(thr, 4.0f); | |||
| /* This deviates from the 3GPP spec to match the reference encoder. | |||
| * It performs min(thr_reduced, max(thr, energy/min_snr)) only for bands | |||
| * that have hole avoidance on (active or inactive). It always reduces the | |||
| * threshold of bands with hole avoidance off. | |||
| */ | |||
| if (thr > band->energy * min_snr && band->avoid_holes != PSY_3GPP_AH_NONE) { | |||
| thr = FFMAX(band->thr, band->energy * min_snr); | |||
| band->avoid_holes = PSY_3GPP_AH_ACTIVE; | |||
| } | |||
| } | |||
| return thr; | |||
| } | |||
| /** | |||
| * Calculate band thresholds as suggested in 3GPP TS26.403 | |||
| */ | |||
| @@ -395,37 +563,167 @@ static void psy_3gpp_analyze(FFPsyContext *ctx, int channel, | |||
| AacPsyChannel *pch = &pctx->ch[channel]; | |||
| int start = 0; | |||
| int i, w, g; | |||
| const int num_bands = ctx->num_bands[wi->num_windows == 8]; | |||
| const uint8_t *band_sizes = ctx->bands[wi->num_windows == 8]; | |||
| AacPsyCoeffs *coeffs = pctx->psy_coef[wi->num_windows == 8]; | |||
| float desired_bits, desired_pe, delta_pe, reduction, spread_en[128] = {0}; | |||
| float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f; | |||
| float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f); | |||
| const int num_bands = ctx->num_bands[wi->num_windows == 8]; | |||
| const uint8_t *band_sizes = ctx->bands[wi->num_windows == 8]; | |||
| AacPsyCoeffs *coeffs = pctx->psy_coef[wi->num_windows == 8]; | |||
| const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG; | |||
| //calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation" | |||
| for (w = 0; w < wi->num_windows*16; w += 16) { | |||
| for (g = 0; g < num_bands; g++) { | |||
| AacPsyBand *band = &pch->band[w+g]; | |||
| float form_factor = 0.0f; | |||
| band->energy = 0.0f; | |||
| for (i = 0; i < band_sizes[g]; i++) | |||
| for (i = 0; i < band_sizes[g]; i++) { | |||
| band->energy += coefs[start+i] * coefs[start+i]; | |||
| band->thr = band->energy * 0.001258925f; | |||
| start += band_sizes[g]; | |||
| form_factor += sqrtf(fabs(coefs[start+i])); | |||
| } | |||
| band->thr = band->energy * 0.001258925f; | |||
| band->nz_lines = form_factor / powf(band->energy / band_sizes[g], 0.25f); | |||
| start += band_sizes[g]; | |||
| } | |||
| } | |||
| //modify thresholds and energies - spread, threshold in quiet, pre-echo control | |||
| for (w = 0; w < wi->num_windows*16; w += 16) { | |||
| AacPsyBand *bands = &pch->band[w]; | |||
| //5.4.2.3 "Spreading" & 5.4.3 "Spreaded Energy Calculation" | |||
| for (g = 1; g < num_bands; g++) | |||
| bands[g].thr = FFMAX(bands[g].thr, bands[g-1].thr * coeffs[g].spread_hi[0]); | |||
| for (g = num_bands - 2; g >= 0; g--) | |||
| bands[g].thr = FFMAX(bands[g].thr, bands[g+1].thr * coeffs[g].spread_low[0]); | |||
| spread_en[0] = bands[0].energy; | |||
| for (g = 1; g < num_bands; g++) { | |||
| bands[g].thr = FFMAX(bands[g].thr, bands[g-1].thr * coeffs[g].spread_hi[0]); | |||
| spread_en[w+g] = FFMAX(bands[g].energy, spread_en[w+g-1] * coeffs[g].spread_hi[1]); | |||
| } | |||
| for (g = num_bands - 2; g >= 0; g--) { | |||
| bands[g].thr = FFMAX(bands[g].thr, bands[g+1].thr * coeffs[g].spread_low[0]); | |||
| spread_en[w+g] = FFMAX(spread_en[w+g], spread_en[w+g+1] * coeffs[g].spread_low[1]); | |||
| } | |||
| //5.4.2.4 "Threshold in quiet" | |||
| for (g = 0; g < num_bands; g++) { | |||
| AacPsyBand *band = &bands[g]; | |||
| band->thr_quiet = band->thr = FFMAX(band->thr, coeffs[g].ath); | |||
| //5.4.2.5 "Pre-echo control" | |||
| if (!(wi->window_type[0] == LONG_STOP_SEQUENCE || (wi->window_type[1] == LONG_START_SEQUENCE && !w))) | |||
| band->thr = FFMAX(PSY_3GPP_RPEMIN*band->thr, FFMIN(band->thr, | |||
| PSY_3GPP_RPELEV*pch->prev_band[w+g].thr_quiet)); | |||
| /* 5.6.1.3.1 "Prepatory steps of the perceptual entropy calculation" */ | |||
| pe += calc_pe_3gpp(band); | |||
| a += band->pe_const; | |||
| active_lines += band->active_lines; | |||
| /* 5.6.1.3.3 "Selection of the bands for avoidance of holes" */ | |||
| if (spread_en[w+g] * avoid_hole_thr > band->energy || coeffs[g].min_snr > 1.0f) | |||
| band->avoid_holes = PSY_3GPP_AH_NONE; | |||
| else | |||
| band->avoid_holes = PSY_3GPP_AH_INACTIVE; | |||
| } | |||
| } | |||
| /* 5.6.1.3.2 "Calculation of the desired perceptual entropy" */ | |||
| ctx->pe[channel] = pe; | |||
| desired_bits = calc_bit_demand(pctx, pe, ctx->bitres.bits, ctx->bitres.size, wi->num_windows == 8); | |||
| desired_pe = PSY_3GPP_BITS_TO_PE(desired_bits); | |||
| /* NOTE: PE correction is kept simple. During initial testing it had very | |||
| * little effect on the final bitrate. Probably a good idea to come | |||
| * back and do more testing later. | |||
| */ | |||
| if (ctx->bitres.bits > 0) | |||
| desired_pe *= av_clipf(pctx->pe.previous / PSY_3GPP_BITS_TO_PE(ctx->bitres.bits), | |||
| 0.85f, 1.15f); | |||
| pctx->pe.previous = PSY_3GPP_BITS_TO_PE(desired_bits); | |||
| if (desired_pe < pe) { | |||
| /* 5.6.1.3.4 "First Estimation of the reduction value" */ | |||
| for (w = 0; w < wi->num_windows*16; w += 16) { | |||
| reduction = calc_reduction_3gpp(a, desired_pe, pe, active_lines); | |||
| pe = 0.0f; | |||
| a = 0.0f; | |||
| active_lines = 0.0f; | |||
| for (g = 0; g < num_bands; g++) { | |||
| AacPsyBand *band = &pch->band[w+g]; | |||
| band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction); | |||
| /* recalculate PE */ | |||
| pe += calc_pe_3gpp(band); | |||
| a += band->pe_const; | |||
| active_lines += band->active_lines; | |||
| } | |||
| } | |||
| /* 5.6.1.3.5 "Second Estimation of the reduction value" */ | |||
| for (i = 0; i < 2; i++) { | |||
| float pe_no_ah = 0.0f, desired_pe_no_ah; | |||
| active_lines = a = 0.0f; | |||
| for (w = 0; w < wi->num_windows*16; w += 16) { | |||
| for (g = 0; g < num_bands; g++) { | |||
| AacPsyBand *band = &pch->band[w+g]; | |||
| if (band->avoid_holes != PSY_3GPP_AH_ACTIVE) { | |||
| pe_no_ah += band->pe; | |||
| a += band->pe_const; | |||
| active_lines += band->active_lines; | |||
| } | |||
| } | |||
| } | |||
| desired_pe_no_ah = FFMAX(desired_pe - (pe - pe_no_ah), 0.0f); | |||
| if (active_lines > 0.0f) | |||
| reduction += calc_reduction_3gpp(a, desired_pe_no_ah, pe_no_ah, active_lines); | |||
| pe = 0.0f; | |||
| for (w = 0; w < wi->num_windows*16; w += 16) { | |||
| for (g = 0; g < num_bands; g++) { | |||
| AacPsyBand *band = &pch->band[w+g]; | |||
| if (active_lines > 0.0f) | |||
| band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction); | |||
| pe += calc_pe_3gpp(band); | |||
| band->norm_fac = band->active_lines / band->thr; | |||
| norm_fac += band->norm_fac; | |||
| } | |||
| } | |||
| delta_pe = desired_pe - pe; | |||
| if (fabs(delta_pe) > 0.05f * desired_pe) | |||
| break; | |||
| } | |||
| if (pe < 1.15f * desired_pe) { | |||
| /* 6.6.1.3.6 "Final threshold modification by linearization" */ | |||
| norm_fac = 1.0f / norm_fac; | |||
| for (w = 0; w < wi->num_windows*16; w += 16) { | |||
| for (g = 0; g < num_bands; g++) { | |||
| AacPsyBand *band = &pch->band[w+g]; | |||
| if (band->active_lines > 0.5f) { | |||
| float delta_sfb_pe = band->norm_fac * norm_fac * delta_pe; | |||
| float thr = band->thr; | |||
| thr *= powf(2.0f, delta_sfb_pe / band->active_lines); | |||
| if (thr > coeffs[g].min_snr * band->energy && band->avoid_holes == PSY_3GPP_AH_INACTIVE) | |||
| thr = FFMAX(band->thr, coeffs[g].min_snr * band->energy); | |||
| band->thr = thr; | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| /* 5.6.1.3.7 "Further perceptual entropy reduction" */ | |||
| g = num_bands; | |||
| while (pe > desired_pe && g--) { | |||
| for (w = 0; w < wi->num_windows*16; w+= 16) { | |||
| AacPsyBand *band = &pch->band[w+g]; | |||
| if (band->avoid_holes != PSY_3GPP_AH_NONE && coeffs[g].min_snr < PSY_SNR_1DB) { | |||
| coeffs[g].min_snr = PSY_SNR_1DB; | |||
| band->thr = band->energy * PSY_SNR_1DB; | |||
| pe += band->active_lines * 1.5f - band->pe; | |||
| } | |||
| } | |||
| } | |||
| /* TODO: allow more holes (unused without mid/side) */ | |||
| } | |||
| } | |||
| @@ -1136,7 +1136,7 @@ static av_cold int cook_decode_init(AVCodecContext *avctx) | |||
| switch (q->subpacket[s].cookversion) { | |||
| case MONO: | |||
| if (q->nb_channels != 1) { | |||
| av_log_ask_for_sample(avctx, "Container channels != 1.!\n"); | |||
| av_log_ask_for_sample(avctx, "Container channels != 1.\n"); | |||
| return -1; | |||
| } | |||
| av_log(avctx,AV_LOG_DEBUG,"MONO\n"); | |||
| @@ -234,7 +234,7 @@ static void memset_float(float *buf, float val, int size) | |||
| * be a multiple of four. | |||
| * @return the LPC value | |||
| * | |||
| * @todo reuse code from vorbis_dec.c: vorbis_floor0_decode | |||
| * @todo reuse code from Vorbis decoder: vorbis_floor0_decode | |||
| */ | |||
| static float eval_lpc_spectrum(const float *lsp, float cos_val, int order) | |||
| { | |||
| @@ -316,6 +316,7 @@ OBJS+= avio.o aviobuf.o | |||
| OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += applehttpproto.o | |||
| OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o | |||
| OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o | |||
| OBJS-$(CONFIG_FILE_PROTOCOL) += file.o | |||
| OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o | |||
| OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o | |||
| @@ -237,6 +237,7 @@ void av_register_all(void) | |||
| /* protocols */ | |||
| REGISTER_PROTOCOL (APPLEHTTP, applehttp); | |||
| REGISTER_PROTOCOL (CONCAT, concat); | |||
| REGISTER_PROTOCOL (CRYPTO, crypto); | |||
| REGISTER_PROTOCOL (FILE, file); | |||
| REGISTER_PROTOCOL (GOPHER, gopher); | |||
| REGISTER_PROTOCOL (HTTP, http); | |||
| @@ -27,6 +27,8 @@ | |||
| #define _XOPEN_SOURCE 600 | |||
| #include "libavutil/avstring.h" | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavutil/opt.h" | |||
| #include "avformat.h" | |||
| #include "internal.h" | |||
| #include <unistd.h> | |||
| @@ -47,9 +49,17 @@ | |||
| * one anonymous toplevel variant for this, to maintain the structure. | |||
| */ | |||
| enum KeyType { | |||
| KEY_NONE, | |||
| KEY_AES_128, | |||
| }; | |||
| struct segment { | |||
| int duration; | |||
| char url[MAX_URL_SIZE]; | |||
| char key[MAX_URL_SIZE]; | |||
| enum KeyType key_type; | |||
| uint8_t iv[16]; | |||
| }; | |||
| /* | |||
| @@ -77,6 +87,9 @@ struct variant { | |||
| int needed, cur_needed; | |||
| int cur_seq_no; | |||
| int64_t last_load_time; | |||
| char key_url[MAX_URL_SIZE]; | |||
| uint8_t key[16]; | |||
| }; | |||
| typedef struct AppleHTTPContext { | |||
| @@ -160,10 +173,35 @@ static void handle_variant_args(struct variant_info *info, const char *key, | |||
| } | |||
| } | |||
| struct key_info { | |||
| char uri[MAX_URL_SIZE]; | |||
| char method[10]; | |||
| char iv[35]; | |||
| }; | |||
| static void handle_key_args(struct key_info *info, const char *key, | |||
| int key_len, char **dest, int *dest_len) | |||
| { | |||
| if (!strncmp(key, "METHOD=", key_len)) { | |||
| *dest = info->method; | |||
| *dest_len = sizeof(info->method); | |||
| } else if (!strncmp(key, "URI=", key_len)) { | |||
| *dest = info->uri; | |||
| *dest_len = sizeof(info->uri); | |||
| } else if (!strncmp(key, "IV=", key_len)) { | |||
| *dest = info->iv; | |||
| *dest_len = sizeof(info->iv); | |||
| } | |||
| } | |||
| static int parse_playlist(AppleHTTPContext *c, const char *url, | |||
| struct variant *var, AVIOContext *in) | |||
| { | |||
| int ret = 0, duration = 0, is_segment = 0, is_variant = 0, bandwidth = 0; | |||
| enum KeyType key_type = KEY_NONE; | |||
| uint8_t iv[16] = ""; | |||
| int has_iv = 0; | |||
| char key[MAX_URL_SIZE]; | |||
| char line[1024]; | |||
| const char *ptr; | |||
| int close_in = 0; | |||
| @@ -192,6 +230,19 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, | |||
| ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args, | |||
| &info); | |||
| bandwidth = atoi(info.bandwidth); | |||
| } else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) { | |||
| struct key_info info = {{0}}; | |||
| ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args, | |||
| &info); | |||
| key_type = KEY_NONE; | |||
| has_iv = 0; | |||
| if (!strcmp(info.method, "AES-128")) | |||
| key_type = KEY_AES_128; | |||
| if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) { | |||
| ff_hex_to_data(iv, info.iv + 2); | |||
| has_iv = 1; | |||
| } | |||
| av_strlcpy(key, info.uri, sizeof(key)); | |||
| } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) { | |||
| if (!var) { | |||
| var = new_variant(c, 0, url, NULL); | |||
| @@ -242,6 +293,15 @@ static int parse_playlist(AppleHTTPContext *c, const char *url, | |||
| goto fail; | |||
| } | |||
| seg->duration = duration; | |||
| seg->key_type = key_type; | |||
| if (has_iv) { | |||
| memcpy(seg->iv, iv, sizeof(iv)); | |||
| } else { | |||
| int seq = var->start_seq_no + var->n_segments; | |||
| memset(seg->iv, 0, sizeof(seg->iv)); | |||
| AV_WB32(seg->iv + 12, seq); | |||
| } | |||
| ff_make_absolute_url(seg->key, sizeof(seg->key), url, key); | |||
| ff_make_absolute_url(seg->url, sizeof(seg->url), url, line); | |||
| dynarray_add(&var->segments, &var->n_segments, seg); | |||
| is_segment = 0; | |||
| @@ -257,6 +317,50 @@ fail: | |||
| return ret; | |||
| } | |||
| static int open_input(struct variant *var) | |||
| { | |||
| struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no]; | |||
| if (seg->key_type == KEY_NONE) { | |||
| return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ); | |||
| } else if (seg->key_type == KEY_AES_128) { | |||
| char iv[33], key[33], url[MAX_URL_SIZE]; | |||
| int ret; | |||
| if (strcmp(seg->key, var->key_url)) { | |||
| URLContext *uc; | |||
| if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ) == 0) { | |||
| if (ffurl_read_complete(uc, var->key, sizeof(var->key)) | |||
| != sizeof(var->key)) { | |||
| av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", | |||
| seg->key); | |||
| } | |||
| ffurl_close(uc); | |||
| } else { | |||
| av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", | |||
| seg->key); | |||
| } | |||
| av_strlcpy(var->key_url, seg->key, sizeof(var->key_url)); | |||
| } | |||
| ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0); | |||
| ff_data_to_hex(key, var->key, sizeof(var->key), 0); | |||
| iv[32] = key[32] = '\0'; | |||
| if (strstr(seg->url, "://")) | |||
| snprintf(url, sizeof(url), "crypto+%s", seg->url); | |||
| else | |||
| snprintf(url, sizeof(url), "crypto:%s", seg->url); | |||
| if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ)) < 0) | |||
| return ret; | |||
| av_set_string3(var->input->priv_data, "key", key, 0, NULL); | |||
| av_set_string3(var->input->priv_data, "iv", iv, 0, NULL); | |||
| if ((ret = ffurl_connect(var->input)) < 0) { | |||
| ffurl_close(var->input); | |||
| var->input = NULL; | |||
| return ret; | |||
| } | |||
| return 0; | |||
| } | |||
| return AVERROR(ENOSYS); | |||
| } | |||
| static int read_data(void *opaque, uint8_t *buf, int buf_size) | |||
| { | |||
| struct variant *v = opaque; | |||
| @@ -291,9 +395,7 @@ reload: | |||
| goto reload; | |||
| } | |||
| ret = ffurl_open(&v->input, | |||
| v->segments[v->cur_seq_no - v->start_seq_no]->url, | |||
| AVIO_FLAG_READ); | |||
| ret = open_input(v); | |||
| if (ret < 0) | |||
| return ret; | |||
| } | |||
| @@ -0,0 +1,170 @@ | |||
| /* | |||
| * Decryption protocol handler | |||
| * Copyright (c) 2011 Martin Storsjo | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav 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, | |||
| * 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 | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "avformat.h" | |||
| #include "libavutil/aes.h" | |||
| #include "libavutil/avstring.h" | |||
| #include "libavutil/opt.h" | |||
| #include "internal.h" | |||
| #include "url.h" | |||
| #define MAX_BUFFER_BLOCKS 150 | |||
| #define BLOCKSIZE 16 | |||
| typedef struct { | |||
| const AVClass *class; | |||
| URLContext *hd; | |||
| uint8_t inbuffer [BLOCKSIZE*MAX_BUFFER_BLOCKS], | |||
| outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS]; | |||
| uint8_t *outptr; | |||
| int indata, indata_used, outdata; | |||
| int eof; | |||
| uint8_t *key; | |||
| int keylen; | |||
| uint8_t *iv; | |||
| int ivlen; | |||
| struct AVAES *aes; | |||
| } CryptoContext; | |||
| #define OFFSET(x) offsetof(CryptoContext, x) | |||
| static const AVOption options[] = { | |||
| {"key", "AES decryption key", OFFSET(key), FF_OPT_TYPE_BINARY }, | |||
| {"iv", "AES decryption initialization vector", OFFSET(iv), FF_OPT_TYPE_BINARY }, | |||
| { NULL } | |||
| }; | |||
| static const AVClass crypto_class = { | |||
| "crypto", av_default_item_name, options, LIBAVUTIL_VERSION_INT | |||
| }; | |||
| static int crypto_open(URLContext *h, const char *uri, int flags) | |||
| { | |||
| const char *nested_url; | |||
| int ret; | |||
| CryptoContext *c = h->priv_data; | |||
| if (!av_strstart(uri, "crypto+", &nested_url) && | |||
| !av_strstart(uri, "crypto:", &nested_url)) { | |||
| av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri); | |||
| ret = AVERROR(EINVAL); | |||
| goto err; | |||
| } | |||
| if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) { | |||
| av_log(h, AV_LOG_ERROR, "Key or IV not set\n"); | |||
| ret = AVERROR(EINVAL); | |||
| goto err; | |||
| } | |||
| if (flags & AVIO_FLAG_WRITE) { | |||
| av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n"); | |||
| ret = AVERROR(ENOSYS); | |||
| goto err; | |||
| } | |||
| if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ)) < 0) { | |||
| av_log(h, AV_LOG_ERROR, "Unable to open input\n"); | |||
| goto err; | |||
| } | |||
| c->aes = av_mallocz(av_aes_size); | |||
| if (!c->aes) { | |||
| ret = AVERROR(ENOMEM); | |||
| goto err; | |||
| } | |||
| av_aes_init(c->aes, c->key, 128, 1); | |||
| h->is_streamed = 1; | |||
| return 0; | |||
| err: | |||
| av_free(c->key); | |||
| av_free(c->iv); | |||
| return ret; | |||
| } | |||
| static int crypto_read(URLContext *h, uint8_t *buf, int size) | |||
| { | |||
| CryptoContext *c = h->priv_data; | |||
| int blocks; | |||
| retry: | |||
| if (c->outdata > 0) { | |||
| size = FFMIN(size, c->outdata); | |||
| memcpy(buf, c->outptr, size); | |||
| c->outptr += size; | |||
| c->outdata -= size; | |||
| return size; | |||
| } | |||
| // We avoid using the last block until we've found EOF, | |||
| // since we'll remove PKCS7 padding at the end. So make | |||
| // sure we've got at least 2 blocks, so we can decrypt | |||
| // at least one. | |||
| while (c->indata - c->indata_used < 2*BLOCKSIZE) { | |||
| int n = ffurl_read(c->hd, c->inbuffer + c->indata, | |||
| sizeof(c->inbuffer) - c->indata); | |||
| if (n <= 0) { | |||
| c->eof = 1; | |||
| break; | |||
| } | |||
| c->indata += n; | |||
| } | |||
| blocks = (c->indata - c->indata_used) / BLOCKSIZE; | |||
| if (!blocks) | |||
| return AVERROR_EOF; | |||
| if (!c->eof) | |||
| blocks--; | |||
| av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks, | |||
| c->iv, 1); | |||
| c->outdata = BLOCKSIZE * blocks; | |||
| c->outptr = c->outbuffer; | |||
| c->indata_used += BLOCKSIZE * blocks; | |||
| if (c->indata_used >= sizeof(c->inbuffer)/2) { | |||
| memmove(c->inbuffer, c->inbuffer + c->indata_used, | |||
| c->indata - c->indata_used); | |||
| c->indata -= c->indata_used; | |||
| c->indata_used = 0; | |||
| } | |||
| if (c->eof) { | |||
| // Remove PKCS7 padding at the end | |||
| int padding = c->outbuffer[c->outdata - 1]; | |||
| c->outdata -= padding; | |||
| } | |||
| goto retry; | |||
| } | |||
| static int crypto_close(URLContext *h) | |||
| { | |||
| CryptoContext *c = h->priv_data; | |||
| if (c->hd) | |||
| ffurl_close(c->hd); | |||
| av_free(c->aes); | |||
| av_free(c->key); | |||
| av_free(c->iv); | |||
| return 0; | |||
| } | |||
| URLProtocol ff_crypto_protocol = { | |||
| .name = "crypto", | |||
| .url_open = crypto_open, | |||
| .url_read = crypto_read, | |||
| .url_close = crypto_close, | |||
| .priv_data_size = sizeof(CryptoContext), | |||
| .priv_data_class = &crypto_class, | |||
| .flags = URL_PROTOCOL_FLAG_NESTED_SCHEME, | |||
| }; | |||
| @@ -588,7 +588,7 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom) | |||
| static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) | |||
| { | |||
| c->fragment.moof_offset = avio_tell(pb) - 8; | |||
| av_dlog(c->fc, "moof offset %llx\n", c->fragment.moof_offset); | |||
| av_dlog(c->fc, "moof offset %"PRIx64"\n", c->fragment.moof_offset); | |||
| return mov_read_default(c, pb, atom); | |||
| } | |||
| @@ -2367,7 +2367,7 @@ static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||
| av_log(s, AV_LOG_ERROR, "moov atom not found\n"); | |||
| return -1; | |||
| } | |||
| av_dlog(mov->fc, "on_parse_exit_offset=%lld\n", avio_tell(pb)); | |||
| av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); | |||
| if (pb->seekable && mov->chapter_track > 0) | |||
| mov_read_chapters(s); | |||
| @@ -2416,7 +2416,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) | |||
| mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || | |||
| url_feof(s->pb)) | |||
| return AVERROR_EOF; | |||
| av_dlog(s, "read fragments, offset 0x%llx\n", avio_tell(s->pb)); | |||
| av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb)); | |||
| goto retry; | |||
| } | |||
| sc = st->priv_data; | |||
| @@ -28,6 +28,34 @@ | |||
| #include "avformat.h" | |||
| #include "os_support.h" | |||
| #if defined(_WIN32) && !defined(__MINGW32CE__) | |||
| #include <windows.h> | |||
| #undef open | |||
| int ff_win32_open(const char *filename_utf8, int oflag, int pmode) | |||
| { | |||
| int fd; | |||
| int num_chars; | |||
| wchar_t *filename_w; | |||
| /* convert UTF-8 to wide chars */ | |||
| num_chars = MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, NULL, 0); | |||
| if (num_chars <= 0) | |||
| return -1; | |||
| filename_w = av_mallocz(sizeof(wchar_t) * num_chars); | |||
| MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars); | |||
| fd = _wopen(filename_w, oflag, pmode); | |||
| av_freep(&filename_w); | |||
| /* filename maybe be in CP_ACP */ | |||
| if (fd == -1 && !(oflag & O_CREAT)) | |||
| return open(filename_utf8, oflag, pmode); | |||
| return fd; | |||
| } | |||
| #endif | |||
| #if CONFIG_NETWORK | |||
| #include <fcntl.h> | |||
| #include <unistd.h> | |||
| @@ -45,6 +45,11 @@ static inline int is_dos_path(const char *path) | |||
| return 0; | |||
| } | |||
| #if defined(_WIN32) && !defined(__MINGW32CE__) | |||
| int ff_win32_open(const char *filename, int oflag, int pmode); | |||
| #define open ff_win32_open | |||
| #endif | |||
| #if CONFIG_NETWORK | |||
| #if !HAVE_SOCKLEN_T | |||
| typedef int socklen_t; | |||
| @@ -551,8 +551,8 @@ static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \ | |||
| .codec_type = t, \ | |||
| .codec_id = CODEC_ID_NONE, \ | |||
| .parse_sdp_a_line = rdt_parse_sdp_line, \ | |||
| .open = rdt_new_context, \ | |||
| .close = rdt_free_context, \ | |||
| .alloc = rdt_new_context, \ | |||
| .free = rdt_free_context, \ | |||
| .parse_packet = rdt_parse_packet \ | |||
| } | |||
| @@ -126,8 +126,8 @@ struct RTPDynamicProtocolHandler_s { | |||
| int st_index, | |||
| PayloadContext *priv_data, | |||
| const char *line); ///< Parse the a= line from the sdp field | |||
| PayloadContext *(*open) (void); ///< allocate any data needed by the rtp parsing for this dynamic data. | |||
| void (*close)(PayloadContext *protocol_data); ///< free any data needed by the rtp parsing for this dynamic data. | |||
| PayloadContext *(*alloc) (void); ///< allocate any data needed by the rtp parsing for this dynamic data. | |||
| void (*free)(PayloadContext *protocol_data); ///< free any data needed by the rtp parsing for this dynamic data. | |||
| DynamicPayloadPacketHandlerProc parse_packet; ///< parse handler for this dynamic packet. | |||
| struct RTPDynamicProtocolHandler_s *next; | |||
| @@ -191,8 +191,8 @@ RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_AMR_NB, | |||
| .parse_sdp_a_line = amr_parse_sdp_line, | |||
| .open = amr_new_context, | |||
| .close = amr_free_context, | |||
| .alloc = amr_new_context, | |||
| .free = amr_free_context, | |||
| .parse_packet = amr_handle_packet, | |||
| }; | |||
| @@ -201,8 +201,8 @@ RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_AMR_WB, | |||
| .parse_sdp_a_line = amr_parse_sdp_line, | |||
| .open = amr_new_context, | |||
| .close = amr_free_context, | |||
| .alloc = amr_new_context, | |||
| .free = amr_free_context, | |||
| .parse_packet = amr_handle_packet, | |||
| }; | |||
| @@ -286,8 +286,8 @@ RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \ | |||
| .codec_type = t, \ | |||
| .codec_id = CODEC_ID_NONE, \ | |||
| .parse_sdp_a_line = asfrtp_parse_sdp_line, \ | |||
| .open = asfrtp_new_context, \ | |||
| .close = asfrtp_free_context, \ | |||
| .alloc = asfrtp_new_context, \ | |||
| .free = asfrtp_free_context, \ | |||
| .parse_packet = asfrtp_parse_packet, \ | |||
| } | |||
| @@ -398,7 +398,7 @@ RTPDynamicProtocolHandler ff_h264_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_VIDEO, | |||
| .codec_id = CODEC_ID_H264, | |||
| .parse_sdp_a_line = parse_h264_sdp_line, | |||
| .open = h264_new_context, | |||
| .close = h264_free_context, | |||
| .alloc = h264_new_context, | |||
| .free = h264_free_context, | |||
| .parse_packet = h264_handle_packet | |||
| }; | |||
| @@ -181,7 +181,7 @@ RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_AAC, | |||
| .parse_sdp_a_line = latm_parse_sdp_line, | |||
| .open = latm_new_context, | |||
| .close = latm_free_context, | |||
| .alloc = latm_new_context, | |||
| .free = latm_free_context, | |||
| .parse_packet = latm_parse_packet | |||
| }; | |||
| @@ -235,8 +235,8 @@ RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_VIDEO, | |||
| .codec_id = CODEC_ID_MPEG4, | |||
| .parse_sdp_a_line = parse_sdp_line, | |||
| .open = NULL, | |||
| .close = NULL, | |||
| .alloc = NULL, | |||
| .free = NULL, | |||
| .parse_packet = NULL | |||
| }; | |||
| @@ -245,7 +245,7 @@ RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_AAC, | |||
| .parse_sdp_a_line = parse_sdp_line, | |||
| .open = new_context, | |||
| .close = free_context, | |||
| .alloc = new_context, | |||
| .free = free_context, | |||
| .parse_packet = aac_parse_packet | |||
| }; | |||
| @@ -223,7 +223,7 @@ RTPDynamicProtocolHandler ff_qcelp_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_QCELP, | |||
| .static_payload_id = 12, | |||
| .open = qcelp_new_context, | |||
| .close = qcelp_free_context, | |||
| .alloc = qcelp_new_context, | |||
| .free = qcelp_free_context, | |||
| .parse_packet = qcelp_parse_packet | |||
| }; | |||
| @@ -309,7 +309,7 @@ RTPDynamicProtocolHandler ff_qdm2_dynamic_handler = { | |||
| .enc_name = "X-QDM", | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_NONE, | |||
| .open = qdm2_extradata_new, | |||
| .close = qdm2_extradata_free, | |||
| .alloc = qdm2_extradata_new, | |||
| .free = qdm2_extradata_free, | |||
| .parse_packet = qdm2_parse_packet, | |||
| }; | |||
| @@ -244,8 +244,8 @@ RTPDynamicProtocolHandler ff_ ## m ## _rtp_ ## n ## _handler = { \ | |||
| .enc_name = s, \ | |||
| .codec_type = t, \ | |||
| .codec_id = CODEC_ID_NONE, \ | |||
| .open = qt_rtp_new, \ | |||
| .close = qt_rtp_free, \ | |||
| .alloc = qt_rtp_new, \ | |||
| .free = qt_rtp_free, \ | |||
| .parse_packet = qt_rtp_parse_packet, \ | |||
| } | |||
| @@ -128,7 +128,7 @@ RTPDynamicProtocolHandler ff_svq3_dynamic_handler = { | |||
| .enc_name = "X-SV3V-ES", | |||
| .codec_type = AVMEDIA_TYPE_VIDEO, | |||
| .codec_id = CODEC_ID_NONE, // see if (config_packet) above | |||
| .open = svq3_extradata_new, | |||
| .close = svq3_extradata_free, | |||
| .alloc = svq3_extradata_new, | |||
| .free = svq3_extradata_free, | |||
| .parse_packet = svq3_parse_packet, | |||
| }; | |||
| @@ -148,7 +148,7 @@ RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { | |||
| .enc_name = "VP8", | |||
| .codec_type = AVMEDIA_TYPE_VIDEO, | |||
| .codec_id = CODEC_ID_VP8, | |||
| .open = vp8_new_context, | |||
| .close = vp8_free_context, | |||
| .alloc = vp8_new_context, | |||
| .free = vp8_free_context, | |||
| .parse_packet = vp8_handle_packet, | |||
| }; | |||
| @@ -389,8 +389,8 @@ RTPDynamicProtocolHandler ff_theora_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_VIDEO, | |||
| .codec_id = CODEC_ID_THEORA, | |||
| .parse_sdp_a_line = xiph_parse_sdp_line, | |||
| .open = xiph_new_context, | |||
| .close = xiph_free_context, | |||
| .alloc = xiph_new_context, | |||
| .free = xiph_free_context, | |||
| .parse_packet = xiph_handle_packet | |||
| }; | |||
| @@ -399,7 +399,7 @@ RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { | |||
| .codec_type = AVMEDIA_TYPE_AUDIO, | |||
| .codec_id = CODEC_ID_VORBIS, | |||
| .parse_sdp_a_line = xiph_parse_sdp_line, | |||
| .open = xiph_new_context, | |||
| .close = xiph_free_context, | |||
| .alloc = xiph_new_context, | |||
| .free = xiph_free_context, | |||
| .parse_packet = xiph_handle_packet | |||
| }; | |||
| @@ -132,8 +132,8 @@ static void init_rtp_handler(RTPDynamicProtocolHandler *handler, | |||
| return; | |||
| codec->codec_id = handler->codec_id; | |||
| rtsp_st->dynamic_handler = handler; | |||
| if (handler->open) | |||
| rtsp_st->dynamic_protocol_context = handler->open(); | |||
| if (handler->alloc) | |||
| rtsp_st->dynamic_protocol_context = handler->alloc(); | |||
| } | |||
| /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */ | |||
| @@ -526,7 +526,7 @@ void ff_rtsp_close_streams(AVFormatContext *s) | |||
| rtsp_st = rt->rtsp_streams[i]; | |||
| if (rtsp_st) { | |||
| if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context) | |||
| rtsp_st->dynamic_handler->close( | |||
| rtsp_st->dynamic_handler->free( | |||
| rtsp_st->dynamic_protocol_context); | |||
| av_free(rtsp_st); | |||
| } | |||
| @@ -25,7 +25,7 @@ | |||
| #define LIBAVFORMAT_VERSION_MAJOR 53 | |||
| #define LIBAVFORMAT_VERSION_MINOR 0 | |||
| #define LIBAVFORMAT_VERSION_MICRO 1 | |||
| #define LIBAVFORMAT_VERSION_MICRO 3 | |||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | |||
| LIBAVFORMAT_VERSION_MINOR, \ | |||
| @@ -29,9 +29,9 @@ | |||
| #include "libavutil/attributes.h" | |||
| #define av_bswap16 av_bswap16 | |||
| static av_always_inline av_const uint16_t av_bswap16(uint16_t x) | |||
| static av_always_inline av_const unsigned av_bswap16(unsigned x) | |||
| { | |||
| __asm__("rorw $8, %0" : "+r"(x)); | |||
| __asm__("rorw $8, %w0" : "+r"(x)); | |||
| return x; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| #!/bin/sh | |||
| sed '/^+[^+]/!s/ /TaBBaT/g' |\ | |||
| expand -t `seq -s , 9 8 200` |\ | |||
| expand -t $(seq -s , 9 8 200) |\ | |||
| sed 's/TaBBaT/ /g' |\ | |||
| sed '/^+[^+]/s/ * $//' |\ | |||
| tr -d '\015' |\ | |||
| @@ -8,9 +8,11 @@ if [ $# = 0 ]; then | |||
| exit | |||
| fi | |||
| GREP=grep | |||
| EGREP=egrep | |||
| TMP=patcheck.tmp | |||
| OPT="-nH" | |||
| #FILES=`grep '^+++' $* | sed 's/+++ //g'` | |||
| #FILES=$($GREP '^+++' $* | sed 's/+++ //g') | |||
| echo patCHeck 1e10.0 | |||
| echo This tool is intended to help a human check/review patches it is very far from | |||
| @@ -27,7 +29,7 @@ hiegrep(){ | |||
| arg="$1" | |||
| msg="$2" | |||
| shift 2 | |||
| grep $OPT '^+' $* | grep -v ':+++'| egrep --color=always -- "$arg"> $TMP && printf "\n$msg\n" | |||
| $GREP $OPT '^+' $* | $GREP -v ':+++'| $EGREP --color=always -- "$arg"> $TMP && printf "\n$msg\n" | |||
| cat $TMP | |||
| } | |||
| @@ -36,12 +38,12 @@ hiegrep2(){ | |||
| varg="$2" | |||
| msg="$3" | |||
| shift 3 | |||
| grep $OPT '^+' $* | grep -v ':+++' | egrep -v -- "$varg" | egrep --color=always -- "$arg" > $TMP && printf "\n$msg\n" | |||
| $GREP $OPT '^+' $* | $GREP -v ':+++' | $EGREP -v -- "$varg" | $EGREP --color=always -- "$arg" > $TMP && printf "\n$msg\n" | |||
| cat $TMP | |||
| } | |||
| hiegrep '[[:space:]]$' 'trailing whitespace' $* | |||
| hiegrep "`echo x | tr 'x' '\t'`" 'tabs' $* | |||
| hiegrep "$(echo x | tr 'x' '\t')" 'tabs' $* | |||
| #hiegrep ':\+$' 'Empty lines' $* | |||
| hiegrep ';;' 'double ;' $* | |||
| hiegrep2 '\b_[a-zA-Z0-9_]{1,}' '__(asm|attribute)([^a-zA-Z0-9]|$)' 'reserved identifer' $* | |||
| @@ -60,7 +62,7 @@ hiegrep '\+= *1 *;' 'can be simplified to ++' $* | |||
| hiegrep '-= *1 *;' 'can be simplified to --' $* | |||
| hiegrep '((!|=)= *(0|NULL)[^0-9a-z]|[^0-9a-z](0|NULL) *(!|=)=)' 'x==0 / x!=0 can be simplified to !x / x' $* | |||
| egrep $OPT '^\+ *(const *|)static' $*| egrep --color=always '[^=]= *(0|NULL)[^0-9a-zA-Z]'> $TMP && printf '\nuseless 0 init\n' | |||
| $EGREP $OPT '^\+ *(const *|)static' $*| $EGREP --color=always '[^=]= *(0|NULL)[^0-9a-zA-Z]'> $TMP && printf '\nuseless 0 init\n' | |||
| cat $TMP | |||
| hiegrep '# *ifdef * (HAVE|CONFIG)_' 'ifdefs that should be #if' $* | |||
| @@ -90,7 +92,7 @@ hiegrep2 '\.sample_fmts *= *\(' 'const' 'missing const for sample_fmts array' $* | |||
| hiegrep2 '\.supported_framerates *= *\(' 'const' 'missing const for supported_framerates array' $* | |||
| hiegrep2 '\.channel_layouts *= *\(' 'const' 'missing const for channel_layouts array' $* | |||
| #egrep $OPT '^\+.*const ' $*| grep -v 'static'> $TMP && printf '\nnon static const\n' | |||
| #$EGREP $OPT '^\+.*const ' $*| $GREP -v 'static'> $TMP && printf '\nnon static const\n' | |||
| #cat $TMP | |||
| hiegrep2 "$ERE_TYPES" '(static|av_|ff_|typedef|:\+[^a-zA-Z_])' 'Non static with no ff_/av_ prefix' $* | |||
| @@ -105,58 +107,58 @@ hiegrep ':\+ *{ *$' '{ should be on the same line as the related previous state | |||
| rm $TMP | |||
| for i in `grep -H '^+.*@param' $*| sed 's/^\([^:]*\):.*@param\(\[.*\]\|\) *\([a-zA-Z0-9_]*\) .*$/\1:\3/'` ; do | |||
| doxpar=`echo $i | sed 's/^.*:\(.*\)$/\1/'` | |||
| file=`echo $i | sed 's/^\([^:]*\):.*$/\1/'` | |||
| grep " *$doxpar *[),]" $file | grep -v '@param' >/dev/null || grep --color=always "@param *$doxpar" $file >>$TMP | |||
| for i in $($GREP -H '^+.*@param' $*| sed 's/^\([^:]*\):.*@param\(\[.*\]\|\) *\([a-zA-Z0-9_]*\) .*$/\1:\3/') ; do | |||
| doxpar=$(echo $i | sed 's/^.*:\(.*\)$/\1/') | |||
| file=$(echo $i | sed 's/^\([^:]*\):.*$/\1/') | |||
| $GREP " *$doxpar *[),]" $file | $GREP -v '@param' >/dev/null || $GREP --color=always "@param *$doxpar" $file >>$TMP | |||
| done | |||
| if test -e $TMP ; then | |||
| printf '\nmismatching doxy params\n' | |||
| cat $TMP | |||
| fi | |||
| egrep -B2 $OPT '^(\+|) *('"$ERE_TYPES"'|# *define)' $* | egrep -A2 --color=always '(:|-)\+[^/]*/(\*([^*]|$)|/([^/]|$))' > $TMP && printf "\n Non doxy comments\n" | |||
| $EGREP -B2 $OPT '^(\+|) *('"$ERE_TYPES"'|# *define)' $* | $EGREP -A2 --color=always '(:|-)\+[^/]*/(\*([^*]|$)|/([^/]|$))' > $TMP && printf "\n Non doxy comments\n" | |||
| cat $TMP | |||
| rm $TMP | |||
| for i in \ | |||
| `egrep -H '^\+ *'"$ERE_TYPES" $* |\ | |||
| grep -v '(' | egrep -v '\Wgoto\W' |\ | |||
| $($EGREP -H '^\+ *'"$ERE_TYPES" $* |\ | |||
| $GREP -v '(' | $EGREP -v '\Wgoto\W' |\ | |||
| xargs -d '\n' -n 1 |\ | |||
| grep -o '[* ][* ]*[a-zA-Z][0-9a-zA-Z_]* *[,;=]' |\ | |||
| sed 's/.[* ]*\([a-zA-Z][0-9a-zA-Z_]*\) *[,;=]/\1/'` \ | |||
| $GREP -o '[* ][* ]*[a-zA-Z][0-9a-zA-Z_]* *[,;=]' |\ | |||
| sed 's/.[* ]*\([a-zA-Z][0-9a-zA-Z_]*\) *[,;=]/\1/') \ | |||
| ; do | |||
| echo $i | grep '^NULL$' && continue | |||
| egrep $i' *(\+|-|\*|/|\||&|%|)=[^=]' $* >/dev/null || echo "possibly never written:"$i >> $TMP | |||
| egrep '(=|\(|return).*'$i'(==|[^=])*$' $* >/dev/null || echo "possibly never read :"$i >> $TMP | |||
| egrep -o $i' *((\+|-|\*|/|\||&|%|)=[^=]|\+\+|--) *(0x|)[0-9]*(;|)' $* |\ | |||
| egrep -v $i' *= *(0x|)[0-9]{1,};'>/dev/null || echo "possibly constant :"$i >> $TMP | |||
| echo $i | $GREP '^NULL$' && continue | |||
| $EGREP $i' *(\+|-|\*|/|\||&|%|)=[^=]' $* >/dev/null || echo "possibly never written:"$i >> $TMP | |||
| $EGREP '(=|\(|return).*'$i'(==|[^=])*$' $* >/dev/null || echo "possibly never read :"$i >> $TMP | |||
| $EGREP -o $i' *((\+|-|\*|/|\||&|%|)=[^=]|\+\+|--) *(0x|)[0-9]*(;|)' $* |\ | |||
| $EGREP -v $i' *= *(0x|)[0-9]{1,};'>/dev/null || echo "possibly constant :"$i >> $TMP | |||
| done | |||
| if test -e $TMP ; then | |||
| printf '\npossibly unused variables\n' | |||
| cat $TMP | |||
| fi | |||
| grep '^+++ .*Changelog' $* >/dev/null || printf "\nMissing changelog entry (ignore if minor change)\n" | |||
| $GREP '^+++ .*Changelog' $* >/dev/null || printf "\nMissing changelog entry (ignore if minor change)\n" | |||
| cat $* | tr '\n' '@' | egrep --color=always -o '(fprintf|av_log|printf)\([^)]*\)[+ ;@]*\1' >$TMP && printf "\nMergeable calls\n" | |||
| cat $* | tr '\n' '@' | $EGREP --color=always -o '(fprintf|av_log|printf)\([^)]*\)[+ ;@]*\1' >$TMP && printf "\nMergeable calls\n" | |||
| cat $TMP | tr '@' '\n' | |||
| cat $* | tr '\n' '@' | egrep --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *[0-9]* *\) * \1 *= *[0-9]* *;[ @\\+]*else *if *\( *\1 *[<>]=? *[0-9]* *\) *\1 *= *[0-9]* *;' >$TMP && printf "\nav_clip / av_clip_uint8 / av_clip_int16 / ...\n" | |||
| cat $* | tr '\n' '@' | $EGREP --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *[0-9]* *\) * \1 *= *[0-9]* *;[ @\\+]*else *if *\( *\1 *[<>]=? *[0-9]* *\) *\1 *= *[0-9]* *;' >$TMP && printf "\nav_clip / av_clip_uint8 / av_clip_int16 / ...\n" | |||
| cat $TMP | tr '@' '\n' | |||
| cat $* | tr '\n' '@' | egrep --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *([A-Za-z0-9_]*) *\)[ @\\+]*(\1|\2) *= *(\1|\2) *;' >$TMP && printf "\nFFMIN/FFMAX\n" | |||
| cat $* | tr '\n' '@' | $EGREP --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *[<>]=? *([A-Za-z0-9_]*) *\)[ @\\+]*(\1|\2) *= *(\1|\2) *;' >$TMP && printf "\nFFMIN/FFMAX\n" | |||
| cat $TMP | tr '@' '\n' | |||
| cat $* | tr '\n' '@' | egrep --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *\)[ @\\+]*av_free(p|) *\( *(&|) *\1[^-.]' >$TMP && printf "\nav_free(NULL) is safe\n" | |||
| cat $* | tr '\n' '@' | $EGREP --color=always -o '\+ *if *\( *([A-Za-z0-9_]*) *\)[ @\\+]*av_free(p|) *\( *(&|) *\1[^-.]' >$TMP && printf "\nav_free(NULL) is safe\n" | |||
| cat $TMP | tr '@' '\n' | |||
| cat $* | tr '\n' '@' | egrep --color=always -o '[^a-zA-Z0-9_]([a-zA-Z0-9_]*) *= *av_malloc *\([^)]*\)[ @;\\+]*memset *\( *\1' >$TMP && printf "\nav_mallocz()\n" | |||
| cat $* | tr '\n' '@' | $EGREP --color=always -o '[^a-zA-Z0-9_]([a-zA-Z0-9_]*) *= *av_malloc *\([^)]*\)[ @;\\+]*memset *\( *\1' >$TMP && printf "\nav_mallocz()\n" | |||
| cat $TMP | tr '@' '\n' | |||
| # doesnt work | |||
| #cat $* | tr '\n' '@' | egrep -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1' | egrep -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1 *=[^=]' >$TMP && printf "\nPossibly written 2x before read\n" | |||
| #cat $* | tr '\n' '@' | $EGREP -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1' | $EGREP -o '[^a-zA-Z_0-9]([a-zA-Z][a-zA-Z_0-9]*) *=[^=].*\1 *=[^=]' >$TMP && printf "\nPossibly written 2x before read\n" | |||
| #cat $TMP | tr '@' '\n' | |||
| exit | |||
| @@ -164,7 +166,7 @@ exit | |||
| TODO/idea list: | |||
| for all demuxers & muxers | |||
| grep for "avctx->priv_data" | |||
| $EGREP for "avctx->priv_data" | |||
| vertical align = | |||
| /* and * align | |||