ffmpeg/libavformat/mpegts.c
Michael Niedermayer 56629aa012 Merge branch 'master' into oldabi
* master:
  mmsh: fixed printf injection bug in mmsh request
  ac3enc: use correct alignment and length in channel coupling dsp functions.
  ffmpeg: don't abuse a global for passing framerate from input to output
  ffmpeg: don't abuse a global for passing channels from input to output
  ffmpeg: don't abuse a global for passing samplerate from input to output
  Make buffer size check consistent and avoid a possible overflow.
  Fix spelling.
  Full support for sending H.264 in RTP
  ARM: update ff_h264_idct8_add4_neon for 4:4:4 changes
  swscale: use SwsContext for av_log when available
  Support reading chan atoms with empty channel descriptions.
  Reindent after last commit.
  Fix multi-channel AAC encoding.
  Fix "redundant redeclaration" warning.
  Fix compilation with --disable-everything --enable-encoder=ac3/ac3_fixed.
  vf_mp: Fix large memleak.
  swscale: Remove HAVE_MMX from files that are only compiled with MMX enabled.
  swscale: Fix compilation with --disable-mmx2.
  mjpegenc: Fix JFIF version
  swscale: remove misplaced comment.
  ffmpeg: fix streaming to ffserver.
  swscale: split out RGB48 output functions from yuv2packed[12X]_c().
  build: move vpath directives to main Makefile
  swscale: fix JPEG-range YUV scaling artifacts.
  build: move ALLFFLIBS to a more logical place
  ARM: factor some repetitive code into macros
  CrystalHD: Use mp4toannexb bitstream filter.
  CrystalHD: Keep mp4toannexb filter around for entire decoder lifetime.
  Fix SVQ3 after adding 4:4:4 H.264 support
  H.264: fix CODEC_FLAG_GRAY
  4:4:4 H.264 decoding support
  matroskadec: properly decode color space in an endian neutral way
  matroskadec: use a temporary fourcc variable
  matroskaenc: ensure the written colorspace don't depend on host endianness
  ac3enc: fix allocation of floating point samples.
  utils: Drop pointless '#if 1' preprocessor directive.
  ac3enc: remove empty ac3_float function that is never called
  ac3enc: split templated float vs. fixed functions into a separate file.
  ac3enc: dynamically allocate AC3EncodeContext fields windowed_samples and mdct
  ac3enc: use function pointer to choose between AC-3 and E-AC-3 header output functions.
  Roll back 4:4:4 H.264 for now Needs some ARM/PPC asm modifications.
  Fix SVQ3 after adding 4:4:4 H.264 support
  H.264: fix CODEC_FLAG_GRAY
  4:4:4 H.264 decoding support
  h264_parser: Fix whitespace after previous change.
  h264_parser: Fix behaviour when PARSER_FLAG_COMPLETE_FRAMES is set.
  wav: remove an invalid free().
  lavf: initialise reference_dts in av_estimate_timings_from_pts.
  h264: don't be so picky on decoding pps in extradata.
  avcodec.h: add or elaborate on some documentation comments.
  h264: change a few comments into error messages
  ac3dec: fix doxy-style for comment ("///>" should be "///<" instead).
  img2: add .dpx to the list of supported file extensions.
  ffv1: fix undefined behavior with insane widths.
  replace remaining usage of deprecated av_metadata_set2() by av_dict_set()
  matroskaenc: write colourspace element for rawvideo tracks
  nsv: simplify probe function
  nsv: return error code instead of discarding it in read_header()
  ARM: jrevdct_arm: simplify stack usage
  ARM: jrevdct_arm: use push/pop mnemonics
  ARM: jrevdct_arm: misc cleanup
  ARM: optimised mpadsp_apply_window_fixed
  Add some (important) changelog entries
  H264: Reduce pointless diffs to qatar
  Revert "H264: Split out hl_motion and template it, this seems a bit faster"
  libavfilter: implement avfilter_fill_frame_from_video_buffer_ref()
  avfiltergraph: make the AVFilterInOut alloc/free API public
  avfiltergraph: change the syntax of avfilter_graph_parse()
  graphparser: prefer void * over AVClass * for log contexts
  h264: Complexify frame num gap shortening code
  Update todo
  mpeg12: replace 2 asserts by av_assert0
  cmdutils: add missing NULL check in parse_options()
  x11grab: remove a memory allocation and the associated memcpy.
  Fix --disable-everything
  build: fix "make install" with documentation disabled
  build: simplify some conditional targets
  resample: clarify supported resampling.
  lavfi: fix signature for avfilter_graph_parse() and avfilter_graph_config()
  avfiltergraph: use meaningful error codes
  Revert "ac3: there was no libav in 2010 thus this code cannot be from  libav."
  Fix -t option for formats which holds dts and no pts
  dnxhd: Renama tables
  Extract rotation in MOV metadata
  bitstream: Properly promote av_reverse values before shifting.
  pixfmt: Replace 9/10bit deprecation by a technical explanation.
  libavutil/swscale: YUV444P10/YUV444P9 support.
  H.264: Fix high bit depth explicit biweight
  h264: Fix 10-bit H.264 x86 chroma v loopfilter asm.
  Replace DEBUG_SEEK/DEBUG_SI + av_log combinations by av_dlog.
  Update copyright year for ac3enc_opts_template.c.
  adts: Adjust frame size mask to follow the specification.
  APIchanges: fill hash for the avfilter_get_audio_buffer_ref_from_arrays addition
  lavfi: avfilter_merge_formats: handle case where inputs are same
  lavfi: use avfilter_get_audio_buffer_ref_from_arrays() in defaults.c
  lavfi: implement avfilter_get_audio_buffer_ref_from_arrays()
  APIchanges: remove duplicated entry
  APIchanges: fill in dates and numbers
  APIchanges: remove duplicated entry
  APIchanges: correctly interleave entries
  APIchanges: add entry for av_force_cpu_flags() addition
  lavf: bump minor after the addition of fps_probe_size to AVFormatContext
  lavc: bump minor after the addition of AVCodecContext.request_sample_fmt
  movenc: Add RTP muxer/hinter options
  movenc: Pass the RTP AVFormatContext to the SDP generation
  rtspenc: Add RTP muxer options
  rtspenc: Add an AVClass for setting muxer specific options
  rtpenc_chain: Pass the rtpflags options through to the chained muxer
  rtpenc: Declare the rtp flags private AVOptions in rtpenc.h
  sdp: Reindent after the previous commit
  rtpenc: MP4A-LATM payload support
  avoptions: Add an av_opt_flag_is_set function for inspecting flag fields
  sdp: Allow passing an AVFormatContext to the SDP generation
  mov: Fix wrong timestamp generation for fragmented movies that have time offset caused by the first edit list entry.
  mpeg12: more advanced ffmpeg mpeg2 aspect guessing code.
  ac3: there was no libav in 2010 thus this code cannot be from  libav.
  swscale: split YUYV output out of yuv2packed[12X]_c().
  dict: This code was developed in ffmpeg and not libav, nor by libav developers. Correct copyright notices.
  lavf: make compute_pkt_fields2() return meaningful error values
  matroskadec: set timestamps for RealAudio packets.
  intelh263dec: aspect ratio processing fix.
  intelh263dec: fix "Strict H.263 compliance"  file playback
  oss,sndio: simplify by using FFMIN.
  swscale: extract monowhite/black output from yuv2packed[12X]_c().
  swscale: de-macro'ify RGB15/16/32 input functions.
  swscale: rearrange code.
  movdec: Add support for the 'wfex' atom.
  ffmpeg.c: Add a necessary const qualifier
  riff: Fix potential memleak.
  swscale: change 48bit RGB input macros to inline functions.
  swscale: change 9/10bit YUV input macros to inline functions.
  swscale: extract gray16 output functions from yuv2packed[12X]().
  swscale: use standard clipping functions.
  swscale: merge macros that are used only once.
  swscale: fix function declarations in swscale.c.
  swscale: fix function declaration keywords in x86/swscale_template.c.
  jpegdec: actually search for and parse RSTn
  crypto: Use av_freep instead of av_free
  Revert "crypto: fix potential double free"
  Revert "build: remove empty $(OBJS) target"
  crypto: Use av_freep instead of av_free
  aac: fix adts frame size mask, fix demuxer probing for some files.
  lavf: don't try to free private options if priv_data is NULL.
  lavfi: handle NULL lists in avfilter_make_format_list
  swscale: fix types of assembly arguments.
  swscale: move two macros that are only used once into caller.
  swscale: remove unused function.
  Fix "mixed declarations and code" warnings.
  options: Add missing braces around struct initializer.
  mov: Remove leftover crufty debug statement with references to a local file.
  dvbsubdec: Fix compilation of debug code.
  Remove all uses of now deprecated metadata functions.
  Move metadata API from lavf to lavu.
  crypto: fix potential double free
  libx264: fix double free
  ffplay: remove -debug option
  ffplay: remove -vismv option
  mpegvideo: use av_get_picture_type_char() in ff_print_debug_info()
  Remove some non-compiling debug messages.
  ffplay: Fix non-compiling debug printf and replace it by av_dlog.
  H264: x86 predict init cosmetics.
  ac3enc: Fix linking of AC-3 encoder without the E-AC-3 encoder.
  Move E-AC-3 encoder functions to a separate eac3enc.c file.
  ac3enc: remove convenience macro, #define DEBUG
  ac3enc: remove unused #define
  vc1: re-initialize tables after width/height change.
  APIchanges: fill-in git commit hash for av_get_bytes_per_sample() addition
  samplefmt: add av_get_bytes_per_sample()
  libvpxenc: add forgotten AVClass.
  iirfilter: fix biquad filter coefficients.
  swscale: remove duplicate conversion routine in swScale().
  swscale: add yuv2planar/packed function typedefs.
  swscale: integrate yuv2nv12X_C into yuv2yuvX() function pointers.
  swscale: reindent x86 init code.
  swscale: extract SWS_FULL_CHR_H_INT conditional into init code.
  swscale: cosmetics.
  swscale: remove alp/chr/lumSrcOffset.
  swscale: un-special-case yuv2yuvX16_c().
  shorten: Remove stray DEBUG #define and corresponding av_dlog statement.
  vorbisdec: Restore mistakenly removed debug output.
  v4l2: set default standard to NULL
  sws: make dither_scale const
  configure: Document --enable-vdpau.
  Replace some av_log/printf + #ifdef combinations by av_dlog.
  Replace some nonstandard DEBUG_* preprocessor directives by plain DEBUG.
  svq1dec: Fix debug statements that referenced non-existing context.
  Replace some printf instances in debug code by av_log.
  showfiltfmts: use av_get_pix_fmt_name()
  inverse.c: Replace unnecessary intmath.h header by necessary stdint.h.
  Drop unnecessary directory prefixes from #include directives.
  Makefile: critical build fix after the merge. make fate passed locally due to ffmpeg/ffmpeg_g being there from before
  ffplay: Fix -vismv
  mem: Trying to workaround posix_memalign() bug on OSX
  build: remove empty $(OBJS) target
  build: make rule for linking ff* apply only to these targets
  eval: add support for pow() function
  build: rearrange some lines in a more logical way
  s302m: fix resampling for 16 and 24bits.
  ARM: remove MUL64 and MAC64 inline asm
  build: clean up .PHONY lists
  build: move all (un)install* target aliases to toplevel Makefile
  flvenc: propagate error properly
  build: remove stale dependency
  build: do not add CFLAGS-yes to CFLAGS
  utils.c: fix crash with threading enabled.
  configure: simplify source_path setup
  configure: remove --source-path option
  pixdesc: remove duplicated header inclusion
  lavfi: use av_samples_alloc() in avfilter_default_get_audio_buffer()
  lavfi: prefer nb_samples over size in AVFilterBufferRefAudioProps
  samplefmt: switch nb_channels/nb_samples params order in av_samples_alloc()
  samplefmt: change layout for arrays created by av_samples_alloc() and _fill_arrays()
  lavf: deprecate AVFormatParameters.time_base.
  img2: add framerate private option.
  img2: add video_size private option.
  img2: add pixel_format private option.
  tty: add framerate private option.
  Move code for "ffmpeg: fix massive leak occurring when seeking" / e4841a404bdabfeafb917454d510b60d888cb761 elsewhere
  lavf: remove reference to output-example in Makefile
  vsrc_buffer: add flags param to av_vsrc_buffer_add_video_buffer_ref
  Remove some unused scripts from tools/.
  Add x86 assembly for some 10-bit H.264 intra predict functions.
  v4l2: do not force NTSC as standard
  Add const to avfilter_get_video_buffer_ref_from_arrays arguments.
  Skip tableprint.h during 'make checkheaders'.
  Remove unnecessary LIBAVFORMAT_BUILD #ifdef.
  Drop explicit filenames from @file Doxygen tags.
  Skip generated table headers during 'make checkheaders'.
  lavf,lavc: free avoptions in a generic way.
  AVOptions: add av_opt_free convenience function.
  sdl: align option fields after last commit
  ffmpeg: fix massive leak occurring when seeking
  ffprobe: implement -i FILE option
  tableprint: Restore mistakenly deleted common.h #include for FF_ARRAY_ELEMS.
  ffplay.texi: document -i FILE option
  cmdutils: remove unnecessary OPT_DUMMY implementation
  cmdutils: change the signature of the function argument in parse_options()
  sdl: use the filename for defining the window title, if not specified
  tiff: print log in case of unknown / unsupported tag.
  tiff: fix linesize for mono-white/black formats.
  Fix build of eval-test program
  configure: Document --enable-vaapi
  swscale: override the lack of the accurate rounding flag when needed for dither.
  swscale: factor should_dither out
  ac3enc: extract all exponents for the frame at once
  ARM: remove MULL inline asm
  mathops: use MUL64 macro where it forms part of other ops
  tty: factorise returning error codes.
  rawdec: add framerate private option.
  x11grab: add framerate private option.
  fbdev,v4l2: remove some forgotten uses of AVFormatParameters.time_base.
  bktr: don't error when AVFormatParameters.time_base isn't set.
  cmdutils: add missing const qualifier
  Skip headers not designed to work standalone during 'make checkheaders'.
  Add missing #includes to make headers self-contained.
  musepack: remove unnecessary #include from mpcdata.h
  musepack: remove extraneous mpcdata.h inclusions
  Fix error check in av_file_map()
  udp: support old, crappy non pthread mode
  ffmpeg: use opt_acodec when setting audio codec in opt_target.
  ffmpeg: fix segfault with too many output files
  ffplay: error out with invalid sample rate or channels.
  oggdec: fix Ticket185
  build: simplify commands for clean target
  j2kdec: dont fail on non zero cblock style.
  makefile: fix j2k encoder dependancies
  udp: fix indention
  swscale: split swscale.c in unscaled and generic conversion routines.
  swscale: cosmetics.
  swscale: integrate (literally) swscale_template.c in swscale.c.
  swscale: split out x86/swscale_template.c from swscale.c.
  swscale: enable hScale_altivec_real.
  swscale: split out ppc _template.c files from main swscale.c.
  swscale: remove indirections in ppc/swscale_template.c.
  swscale: split out unscaled altivec YUV converters in their own file.
  mpegvideoenc: fix multislice fate tests with threading disabled.
  cmdutils: move "#undef main" from ffplay.c to cmdutils.h
  wav: update size check for ds64
  wav: fix skip size at end of ds64 chunk
  mpegts: Wrap #ifdef DEBUG and av_hex_dump_log() combination in a macro.
  build: Simplify texi2html invocation through the --output option.
  Mark some variables with av_unused
  Replace avcodec_get_pix_fmt_name() by av_get_pix_fmt_name().
  svq3: Check negative mb_type to fix potential crash.
  svq3: Move svq3-specific fields to their own context.
  rawdec: initialize return value to 0.
  Remove unused get_psnr() prototype
  rawdec: don't leak option strings.
  bktr: get default framerate from video standard.
  swscale: remove unused COMPILE_TEMPLATE_ALTIVEC.
  h264 fill_filter_caches: Dont init chroma nnz_cache.
  In print_report, print progression time in hours:mins:secs:us
  ffmpeg: In print_report, use int64_t for pts to check for 0 and avoid inf value for bitrate.
  In libswscale, use all lines when converting from 422p to rgb with mmx, improve quality.
  Replace custom DEBUG preprocessor trickery by the standard one.
  vorbis: Remove non-compiling debug statement.
  vorbis: Remove pointless DEBUG #ifdef around debug output macros.
  cook: Remove non-compiling debug output.
  Remove pointless #ifdefs around function declarations in a header.
  Replace #ifdef + av_log() combinations by av_dlog().
  Replace custom debug output functions by av_dlog().
  cook: Remove unused debug functions.
  lavfi: add avfilter_link_free() function
  swscale: reintroduce sws_format_name() symbol
  Remove stray extra arguments from av_dlog() invocations.
  targa: fix big-endian build
  v4l2: remove one forgotten use of AVFormatParameters.pix_fmt.
  vfwcap: add a framerate private option.
  v4l2: add a framerate private option.
  libdc1394: add a framerate private option.
  fbdev: add a framerate private option.
  bktr: add a framerate private option.
  oma: check avio_read() return value
  nutdec: remove unused variable
  Remove unused variables
  swscale: dither for planar yuv outputs
  swscale: Fix use of uninitialized values (bug probably introduced from a marge of libav)
  cpudetect: add av_force_cpu_flags()
  swscale: allocate larger buffer to handle altivec overreads.
  H264/MPEG frame-level multi-threading.
  vsrc_buffer: propagate error code in av_vsrc_buffer_add_frame()
  lavfi: reindent after the previous commit
  lavfi: add braces around the block of an if() expression in avfilter_default_get_video_buffer
  lavfi: clarify the context of a comment in avfilter_default_get_video_buffer()
  lavfi: apply misc style fixes
  Cosmetic changes to h264_idct_10bit.asm.
  2x faster h264_idct_add8_10.
  aacenc: Add stereo_mode option.
  h264: remove CONFIG_GPL from x86 intra prediction code.
  doc: cosmetics: libx264 typos
  postprocess: Remove test for impossible condition (was: Re: postprocess.c: replace check for p==NULL with *p==0)
  Fix various uninitialized variable warnings
  Port remove of get_sws_cpuflags from MPlayer's libmpcodecs.
  Replace "vector const" by "const vector" otherwise gcc 4.6.0 fails.
  Port recent changes to MPlayer libmpcodecs.
  Replace non-existent HAVE_SSE2 with HAVE_SSE.
  Simplify code and avoid compiler warning about incompatible types.
  Fix type of out[] variable, it should not be const.
  ARM: ac3dsp: optimised update_bap_counts()
  mpegaudiodec: Fix av_dlog() invocation.
  swscale: fix compilation of bfin due to missing pixdesc.h header
  lavf: tag dump_format() as @deprecated
  yuv4mpeg: complain and exit if a non-rawvideo stream is selected
  ffmpeg: handle copy of packets for AVFMT_RAWPICTURE output formats
  doc/examples: give meaningful names to the example files
  h264/10bit: add HAVE_ALIGNED_STACK checks.
  swscale: More accurate rounding in YSCALE_YUV_2_PACKEDX_FULL_C()
  Update 8-bit H.264 IDCT function names to reflect bit-depth.
  Add IDCT functions for 10-bit H.264.
  mpegaudioenc: Fix broken av_dlog statement.
  Employ correct printf format specifiers, mostly in debug output.
  ARM: fix MUL64 inline asm for pre-armv6
  doc: add libvpx encoder section
  vf_drawtext: Replace FFmpeg by Libav in license boilerplate.
  mpegaudiodec: remove unusued code and variables
  postprocess.c: filter name needs to be double 0 terminated
  improved 'edts' atom writing support
  mpegaudio: clean up compute_antialias() definition
  vp8: fix segmentation race during frame-threading.
  Port libmpcodec fixes from MPlayer.
  Merge remote-tracking branch 'ffmpeg-mt/master'
  swscale: Remove unused variable.
  ARM: simplify inline asm with 64-bit operands
  Add "const" to avoid "initialization discards qualifiers" warning.
  Add const to fix "cast discards qualifiers" warnings.
  Include pixdesc.h for av_get_pix_fmt_name.
  wav: Don't avio_seek() if we know we'll run into EOF
  api-example: uppercase first letter in "copyright"
  output-example: create @file doxy from text in the copyright header
  examples: move API examples to a dedicated dir in doc
  ffmpeg: simplify opt_*_codec() options
  v4l2: rewrite code iterating the supported standards
  v4l2: perform minor style fixes
  v4l2: replace memset() with explicit struct initialization
  rawdec: fail in case of unknow pixel format
  swscale: remove sws_format_name()
  error.c: fix compile flags
  TCP: change default timeout to 5sec
  Revert "Timeout TCP open() after 5 seconds."
  Fix various unused variable warnings
  Fix various bad printf format warnings
  ARM: enable UAL syntax in asm.S
  Remove now unused nb_istreams variable.
  Add const to vector types for input in altivec code.
  Remove unused variable, avoiding compiler warning.
  Cast pointers to uintptr_t rather than unsigned int.
  v4l2: don't leak video standard string on error.
  swscale: Remove disabled code.
  avfilter: Surround function only used in debug mode by appropriate #ifdef.
  vf_crop: Replace #ifdef DEBUG + av_log() by av_dlog().
  build: remove BUILD_ROOT variable
  vp8: use av_clip_uintp2() where possible
  swscale: Commits that could not be pulled earlier due to bugs #2
  Commits that could not be pulled earlier due to bugs.
  Revert 1a5e4fd8c5b99478b4e08a69261930bb12aa948b for postproc. This broke the code
  doc: correct AC-3 option subsection placement
  ac3enc: fix LOCAL_ALIGNED usage in count_mantissa_bits()
  ac3dsp: do not use the ff_* prefix when referencing ff_ac3_bap_bits.
  swscale: use av_clip_uint8() in yuv2yuv1_c().
  swscale: replace formatConvBuffer[VOF] by allocated array.
  v4l2: create file @doxy from text in the copyright header
  v4l2: remove pointless empty lines
  v4l2: set default standard to NULL
  v4l2: use OFFSET macro when setting options
  ac3dsp: fix loop condition in ac3_update_bap_counts_c()
  ARM: unbreak build
  lavdev: add SDL output device
  ac3enc: modify mantissa bit counting to keep bap counts for all values of bap instead of just 0 to 4.
  ac3enc: split mantissa bit counting into a separate function.
  ac3enc: store per-block/channel bap pointers by reference block in a 2D array rather than in the AC3Block struct.
  lavu: add av_get_pix_fmt_name() convenience function
  iff: remove duplicated file description
  cmdutils: remove OPT_FUNC2
  get_bits: add av_unused tag to cache variable
  sws: replace all long with int.
  ARM: aacdec: fix constraints on inline asm
  ARM: remove unnecessary volatile from inline asm
  ARM: add "cc" clobbers to inline asm where needed
  ARM: improve FASTDIV asm
  ac3enc: use LOCAL_ALIGNED macro
  APIchanges: fill in git hash for av_get_pix_fmt_name (0420bd7).
  lavu: add av_get_pix_fmt_name() convenience function
  cmdutils: remove OPT_FUNC2
  swscale: fix crash in bilinear scaling.
  vpxenc: add VP8E_SET_STATIC_THRESHOLD mapping
  webm: support stereo videos in matroska/webm muxer
  rgb2rgb: remove duplicate mmx/mmx2/3dnow/sse2 functions.
  swscale: reindent h[cy]scale_fast() and updateDitherTables().
  swscale: reformat x86/swscale_template.c.
  swscale: remove duplicate mmx/mmx2 functions if they are identical.
  swscale: remove if (c->dstFormat) branch from yuv2packed[12X]().
  swscale: remove if(full_chr_int) from yuv2packed1().
  swscale: remove if(accurate_rnd) branch from functions.
  swscale: revive SWS_CPU_CAPS until next major bump.
  swscale: Remove commented-out printf cruft.
  Export PCR pid
  Export more transport stream information.
  Output MPEG-TS stream identifiers.
  lavf: deprecate AVFormatParameters.pix_fmt.
  rawdec: add a pixel_format private option.
  v4l2: add a pixel_format private option.
  libdc1394: add a pixel_format private option.
  cosmetics: indentation and alignment after previous commit
  ac3enc: add support for E-AC-3 encoding.
  ac3enc: Move AC-3 AVOptions array to a separate file to make it easier to use only selected options for the different AC-3 encoder types.
  ARM: disable ff_vector_fmul_vfp on VFPv3 systems
  ARM: check for VFPv3
  swscale: Remove unused variables in x86 code.
  doc: Drop DJGPP section, Libav now compiles out-of-the-box on FreeDOS.
  x86: Add appropriate ifdefs around certain AVX functions.
  cmdutils: use sws_freeContext() instead of av_freep().
  swscale: delay allocation of formatConvBuffer().
  swscale: fix build with --disable-swscale-alpha.
  movenc: Deprecate the global RTP hinting flag, use a private AVOption instead
  movenc: Add an AVClass for setting muxer specific options
  libdc1394: choose best video mode and rate based on camera capabilities.
  Remove support for libdc1394 < 2.0.
  avopt: fix segfault
  swscale: fix non-bitexact yuv2yuv[X2]() MMX/MMX2 functions.
  swscale: dont loose precission on RGB/BGR48 input, that is dont drop half the bits.
  patch checklist: suggest --disable-yasm test.
  lavdev: prefer the inclusion of avdevice.h over that of libavformat/avformat.h
  lavdev: include libavformat/avformat.h in avdevice.h
  fate.txt: replace FATE rsync command with a make command
  configure: report yasm/nasm presence properly
  tcp: make connect() timeout properly
  rawdec: factor video demuxer definitions into a macro.
  rtspdec: add initial_pause private option.
  lavf: deprecate AVFormatParameters.width/height.
  tty: add video_size private option.
  rawdec: add video_size private option.
  x11grab: add video_size private option.
  x11grab: factorize returning error codes.
  vfwcap: add video_size private option.
  v4l2: add video_size private option.
  v4l2: factorize returning error codes.
  libdc1394: add video_size private option.
  libdc1394: return meaninful error codes.
  bktr: add video_size private option.
  bktr: factorize returning error codes.
  Fix memleak
  Fix typo
  Remove specific note when not specific
  Minor cleanup in libx264.c
  Add metadata conversion table to the wav demuxer
  Fix 32bit rawvideo in avi on big-endian.
  id3v2: Check malloc result. ID3v2 tags can be very large.
  id3v2: Initialize tflags for version 2.2.
  webm: Additional options/presets for VP8 encodes under FFmpeg
  muxers: Add a flag to mark muxers that allow (non strict) monotone timestamps.
  swscale: Do not loose precission on yuv values after rgb->yuv.
  libx264: support aspect Ratio Switch
  ARM: add ARMv6 optimised av_clip_uintp2
  ARM: remove volatile from asm statements in libavutil/intmath
  ARM: fix av_clipl_int32_arm()
  v4l: include avdevice.h
  ffserver: move close_connection() call to avoid a temporary string and copy.
  lavf: initialize demuxer private options.
  AVOptions: set string default values.
  Fix compilation with YASM/NASM versions not supporting AVX.
  lavdevice: mark v4l for removal on next major bump.
  swscale: fix compile on ppc.
  swscale: fix compile on x86-32.
  build: Remove generated .version file on distclean.
  configure: Add -D_GNU_SOURCE to CPPFLAGS on OS/2.
  doc: Drop hint at --enable-memalign-hack for MinGW, it is now autodetected.
  ffplay: Remove disabled code.
  Mark parameterless function declarations as 'void'.
  swscale: use av_clip_uint8() in yuv2yuv1_c().
  swscale: remove VOF/VOFW.
  swscale: split chroma buffers into separate U/V planes.
  swscale: replace formatConvBuffer[VOF] by allocated array.
  rgb2rgb: remove duplicate mmx/mmx2/3dnow/sse2 functions.
  swscale: reindent h[cy]scale_fast() and updateDitherTables().
  swscale: reformat x86/swscale_template.c.
  swscale: remove duplicate mmx/mmx2 functions if they are identical.
  swscale: remove if (c->dstFormat) branch from yuv2packed[12X]().
  swscale: remove if(full_chr_int) from yuv2packed1().
  swscale: remove if(accurate_rnd) branch from functions.
  ffserver: Fix a null pointer dereference as a result of the FF_API_MAX_STREAMS cleanup.
  libdc1394: fix compilation.
  swscale: revive SWS_CPU_CAPS until next major bump.
  swscale: Remove commented-out printf cruft.
  ac3enc: initialize all coefficients to zero.
  ffv1: fix 16bits multithreading
  doc: create separate section for audio encoders
  swscale: Remove orphaned, commented-out function declaration.
  swscale: Eliminate rgb24toyv12_c() duplication.
  mpegvideo_enc: use AV_LOG_ERROR instead of AV_LOG_INFO for two error messages
  Fail when lowres value is lower than 0
  Remove h263_msmpeg4 from MpegEncContext.
  APIchanges: Fill in git hash for fps_probe_size (30315a8)
  avformat: Add fpsprobesize as an AVOption.
  swscale: document SWS_CPU_CAPS*
  Revert removial of SWS flags from e66149e714006d099d1ebfcca3f22ca74fc7dcf4
  avoptions: Return explicitly NAN or {0,0} if the option isn't found
  rtmp: Reindent
  rtmp: Don't try to do av_malloc(0)
  swscale: remove duplicatiopn of rgb24toyv12_c()
  Return -1 on invalid input instead of crashing.
  vf_mp: fix name of the remove-logo filter referenced in filters.texi
  tty: replace AVFormatParameters.sample_rate abuse with a private option.
  Fix end time of last chapter in compute_chapters_end
  ffmpeg: get rid of useless AVInputStream.nb_streams.
  ffmpeg: simplify managing input files and streams
  ffmpeg: purge redundant AVInputStream.index.
  lavf: deprecate AVFormatParameters.channel.
  libdc1394: add a private option for channel.
  dv1394: add a private option for channel.
  v4l2: reindent.
  v4l2: add a private option for channel.
  lavf: deprecate AVFormatParameters.standard.
  v4l2: add a private option for video standard.
  v4l: add a private option for video standard.
  dv1394: add a private option for video standard.
  bktr: add a private option for video standard.
  lavf: deprecate AVFormatParameters.{channels,sample_rate}.
  rawdec: add sample_rate/channels private options.
  ALSA: add channels and sample_rate private options.
  oss: add channels and sample_rate private options.
  sndio: add channels and sample_rate private options.
  lavf: deprecate AVFormatParameters.mpeg2ts_raw.
  mpegts: add compute_pcr option.
  lavf: add priv_class field to AVInputFormat.
  lavfi: add select filter
  eval: implement not() expression
  vsrc_buffer: return an error code if no frames are available
  ffmpeg: handle the case when get_filtered_frame() fails
  indeo3: add out-of-buffer write check
  Add reading of disc number to mov.c
  Fix end time of last chapter in compute_chapters_end().
  Do not reset channel_layout to 0.
  vsrc_buffer: remove duplicated file description
  Merge swscale bloatup This will be cleaned up in the next merge
  swscale: MMX optim of hscale16()
  swscale: dont loose bits on planar >8bit yuv ind gray nput.
  swscale: Switch to ronalds yuv2yuvX16inC_template() its very similar to baptsites and supports alpha
  configure: enable memalign_hack automatically when needed
  rawdec: fix decoding of QT WRAW files
  matroska: improve declaration of video_stereo_* constant tables
  matroskadec: fix reverted condition to accept combine_plane operation
  Fix register types for LOAD_AB arguments, fixes compilation with NASM.
  swscale: unbreak the build on non-x86 systems.
  swscale: remove if(bitexact) branch from functions.
  swscale: remove if(canMMX2BeUsed) conditional.
  swscale: remove swScale_{c,MMX,MMX2} duplication.
  swscale: use emms_c().
  Move emms_c() from libavcodec to libavutil.
  tiff: set palette in the context when specified in TIFF_PAL tag
  rtsp: use strtoul to parse rtptime and seq values.
  pgssubdec: fix incorrect colors.
  dvdsubdec: fix incorrect colors.
  ape: Allow demuxing of files with metadata tags.
  swscale: remove dead macro WRITEBGR24OLD.
  swscale: remove AMD3DNOW "optimizations".
  swscale: remove duplicate code in ppc/ subdirectory.
  swscale: remove duplicated x86/ functions.
  swscale: force --enable-runtime-cpudetect and remove SWS_CPU_CAPS_*.
  vsrc_buffer.h: add file doxy
  vsrc_buffer: tweak error message in init()
  wav: fix various printf warnings related to wrong argument type
  wav: propagate ff_get_wav_header() error code in w64_read_header()
  msmpeg4: reindent.
  lavc: remove msmpeg4v1 encoder.
  Remove avconfig.h and INCINSTDIRs on uninstall.
  ac3enc: add channel coupling support
  partial revert of 01d3ebaf219d83c0a70cdf9696ecb6b868e8a165
  fate: reenable frext-pph10i4_panasonic_a after the bitstream has been fixed
  avcodec_find_decoder: prefer non experimental decoders.
  j2kdec: mark as CODEC_CAP_EXPERIMENTAL
  j2k[c/h] j2kdec.c: Implement 2 code block styles
  j2k: Add void as the parameter of function ff_j2k_init_tier1_luts
  Add Kamil Nowosads j2k code.
  matroska: cleanup handling of video stereo mode
  oggdec: use av_dlog()
  mem: define the MAX_MALLOC_SIZE constant and use it in place of INT_MAX
  configure: Add -U__STRICT_ANSI__ to CPPFLAGS on Cygwin and DOS.
  muxers.texi changes for mkv/webm options
  aacdec: fix typo in scalefactor clipping check
  mpegaudio: Correct license header
  add 5.1 to stereo downmix to resample.c this is based on previous 6to2channel-resample.patch from ffmpeg2theora but updated to work with trunk and using av_clip_int16.
  fate: fix fate-h264-conformance-frext-pph10i4-panasonic-a crcs.
  fate: update 9/10bit refs.
  h264: Properly set coded_{width, height} when parsing H.264.
  x86 asm: Add SECTION_TEXT to dct32_sse.asm.
  Fix 9/10 bit in swscale.
  Do not ask for samples if a specific channel layout was requested.
  libx264: specify field for default union values in options
  movdec: dont divide by zero when stts_data[0].duration = 0.
  Fix ticket127
  dct32: Replacing libav by ffmpeg in the license header with the authors permission. Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
  ffmpeg: Don't trigger url_interrupt_cb on the first signal
  avoptions: Check the return value from av_get_number
  lavf: fix style for avformat_alloc_output_context2()
  lavf: deprecate avformat_alloc_output_context() in favor of avformat_alloc_output_context2()
  lavfi: make vsrc_buffer.h header public
  dct32_sse: eliminate some spills
  Fix compilation with --disable-yasm.
  Fix dct32() compilation with --disable-yasm
  mpeg2dec: Fix lowres 3
  lavfi: bump minor and add changelog entry after the split filter addition
  vf_split: add documentation to filters.texi
  vf_split: give more meaningful names to the output pads
  vf_split: define draw_slice() before end_frame()
  vf_split: add description
  vf_split: fix various nits
  wmadec: avoid infinit loop.
  DirectShow capture: Fix build
  ffmpeg: get rid of the -vglobal option.
  dct32: Add AVX implementation of 32-point DCT
  dct32: Change pass 6 permutation to allow for AVX implementation
  dct32: port SSE 32-point DCT to YASM
  matroska: switch stereo mode from int to string and add support in the demuxer too
  matroska: cosmetics
  Create a stereo_mode metadata tag to specify the stereo 3d video layout using the StereoMode tag in a matroska/webm video track.
  libavfilter: vf_split from soc.
  DirectShow capture support Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
  multiple inclusion guard cleanup
  avio: document buffer must created with av_malloc() and friends
  avio: check AVIOContext malloc failure
  swscale: point out an alternative to sws_getContext
  svq3: Do initialization after parsing the extradata
  Fix channel_layout documentation.
  add changelog entries for 0.7_beta2
  ffserver: dont just crash
  fix ffserver's SIGSEGV
  avoptions: Support getting flag values using av_get_int
  preset dir for win32
  Merge remote-tracking branch 'ffmpeg-mt/master'
  Add a flag to disable side data merging.
  Merge/split side data.
  Encoding alac with more than two channels is not supported.
  mp3lame: add #include required for AV_RB32 macro.
  configure: make executable again
  LATM/AAC: Free previously initialized context on reinit.
  configure: Do not unconditionally add -Wall to host CFLAGS.
  configure: Set OS/2 objformat to a.out.
  Add support for a.out object format to assembler macros.
  fate: disable threading for encoding
  fate: add comment field
  fate: allow overriding default build and install dirs
  mpegtsenc: Add an AVClass pointer to the private data
  mpegaudio: clean up #includes
  mpegaudio: move all header parsing to mpegaudiodecheader.[ch]
  vf_libopencv: prefer opencv/cxcore.h over cxtypes.h
  decoders.texi: fix typos in rawvideo section
  cmdutils: use const AVClass * when senseful
  encoders.texi: add documentation for the libx264 encoder
  decoders.texi: add documentation for rawvideo decoder and options
  doc: add decoders.texi file
  encoders.texi: decrease level for audio encoders section
  ffprobe.texi: remove inclusion of muxers section
  indeo3: release buffer in indeo3_decode_end()
  indeo3: remove unnecessary includes
  indeo3: add @file doxy and a link to multimedia wiki documentation
  cmdutils: reset *picref_ptr to NULL in get_filtered_frame()
  ffmpeg: remove useless NULL-check on avfilter_unref_buffer
  libmp3lame: include "libavutil/intreadwrite.h" header
  qdm2: Use floating point synthesis filter.
  h264: correct border check.
  h264: fix loopfilter with threading at slice boundaries.
  Fix ff_mpa_synth_filter_fixed() prototype
  Reindent
  rtpenc_chain: Pass the MP4A_LATM flag to chained muxers
  rtpenc: MP4A-LATM payload support
  movenc: Pass AVFormatContext flags to the SDP generation
  sdp: Allow passing AVFormatContext flags to the SDP generation
  vsrc_buffer: document av_vsrc_buffer_add_video_buffer_ref()
  vsrc_buffer: add av_vsrc_buffer_add_frame()
  vsrc_buffer: fix example in docs, add mandatory parameters
  vsrc_buffer: make the source accept sws_param in init
  vsrc_buffer: propagate avfilter_open() error code
  vsrc_buffer: fix style
  lavfi: add avfilter_get_video_buffer_ref_from_frame to avcodec.h
  vsrc_buffer: remove dependency on AVFrame
  Rename costablegen.c ---> cos_tablegen.c.
  Collapse tableprint.c into tableprint.h.
  Simplify trig table rules
  Remove potentially unstable filenames from comments in generated files.
  Ignore generated tables and generated table generator programs.
  Simplify CLEANFILES make variable by using wildcards.
  Remove silly insults from avformat_version() Doxygen documentation.
  mpegaudiodsp: fix x86 and ppc makefiles
  configure: Adjust AVX assembler check.
  mpegaudio: remove unused version of SAME_HEADER_MASK
  mpegaudio: remove useless #undef at end of file
  asfdec: add missing #include for av_bswap32()
  mpegaudio: merge two #if CONFIG_FLOAT blocks
  mpegaudio: move some struct definitions from mpegaudio.h
  Move some mpegaudio functions to new mpegaudiodsp subsystem
  Clean up #includes in cmdutils.h.
  g729: Merge g729.h into g729dec.c.
  av_find_stream_info: Print more details about max anaylize duration failures.
  10l: wrap float_interleave functions in HAVE_YASM.
  Add little description for -rc_override
  APIchanges: fill in date and commit for request_sample_fmt
  Add floating-point sample format support to the ac3, eac3, dca, aac, and vorbis decoders.
  Add support for request_sample_format in ffmpeg and ffplay.
  Add APIchanges entry for request_sample_fmt.
  Add request_sample_fmt field to AVCodecContext.
  Add float_interleave() to FmtConvertContext with x86-optimized versions.
  Remove unused make variable SEEK_REFFILE
  fate: remove redundant aref and vref references
  Parse 'bext' metadata in the wav demuxer
  Cosmetics: indent
  Keep parsing wav until EOF if the input is seekable and we know the size of the data tag
  Refactor the tag checking into a switch statement
  Use avio_tell() instead of url_ftell()
  add x264opts entry to docs
  cleaned up the udp.c, removed some variables and an av_log
  configure: favor pkg_config over sdl_config
  libx264: support passing arbitrary parameters.
  ffmpeg: dont show_banner() on verbose<0
  fate: remove do_ffmpeg_nocheck function
  fate: do not collect -benchmark output
  mpegaudiodec: remove decode_end() function
  fate: run aref and vref as regular tests
  mpegaudio: sanitise compute_antialias_* names
  mpeg12: add slice-threading checks to slice-threading initializers.
  h264: copy pixel_shift between slice threading contexts.
  mdec: enable frame-level multithreading.
  mdec.c: fix overread.
  id3v2: prevent unsigned integer overflow in ff_id3v2_parse()
  id3v2: add @file doxy and link to format documentation
  configure: opensolaris install is not compatible with ffmpeg, allow overriding it.
  Fix compilation of iirfilter-test.
  eval: opensolaris strtod() cannot handle 0x1234
  libx264: handle closed GOP codec flag
  lavf: remove duplicate assignment in avformat_alloc_context.
  lavf: use designated initializers for AVClasses.
  Make sure neither data_size nor sample_count is negative
  Refactor the 'fmt ' tag search and parsing
  flvdec: clenup debug code
  asfdec: fix possible overread on broken files.
  asfdec: do not fall back to binary/generic search
  asfdec: reindent after previous commit c7bd5ed
  asfdec: fallback to binary search internally
  mpegaudio: add _fixed suffix to some names
  Modify x86util.asm to ease transitioning to 10-bit H.264 assembly.
  ffmpeg: reset top_field_first in opt_input_file().
  dct: build dct32 as separate object files
  qdm2: include correct header for rdft
  Ogg demuxer: give meaningful error codes and warnings.
  update changelog with 9/10 bit H264 and FFV1 changes
  Add some forgotten const to function arguments in libavfilter & libavformat.
  Write channel_layout for multichannel aif files.
  Fix ff_mov_write_chan() so it can be used by other muxers.
  Fix some mov files with little endian audio (tickets 201 - 203).
  iff/8svx: redesign 8SVX demuxing and decoding for handling stereo samples correctly
  iff: compact code setting metadata tags
  iff: fix bitrate computation for compressed audio stream
  iff: distinguish fields for audio and video compression
  imgutils: introduce internal image_get_linesize() and use it
  imgutils: make av_image_get_linesize() return AVERROR(EINVAL) for invalid pixel formats
  drawtext: specify union type for setting default options
  drawtext: reindent after the previous commit
  drawtext: fix strftime() text expansion
  ffmpeg: fix -aspect cli option
  Restructure video filter implementation in ffmpeg.c.
  ffplay: remove audio_write_get_buf_size() forward declaration
  lavfi: print key-frame and picture type information in ff_dlog_ref()
  mathops: remove ancient confusing comment
  rawdec: Allow overriding top field first.
  ffmpeg: initialize input_codec array earlier.
  cmdutils: Allocate private decoder context if its not allocated yet.
  cws2fws: Improve error message wording.
  tools: Check the return value of write().
  mpegaudio: move OUT_FMT macro to mpegaudiodec.c
  mpegaudio: remove OUT_MIN/MAX macros
  Add missing #includes to mp3_header_(de)compress bsf
  dct: fix indentation
  dct: bypass table allocation for DCT_II of size 32
  pngdec: relax condition for setting monoblack pixel format
  h264dsp_mmx: Add #ifdefs around some mmxext functions on x86_64.
  Remove unused header mpegaudio3.h.
  Support decoding of 1bpp rawvideo in avi (ticket 205).
  Support decoding of 2bpp rawvideo in avi (ticket 206).
  Bump minor after adding a caf muxer.
  configure: another try on fixing osx/mingw SDL
  aacdec: Use float instead of int16_t for ltp_state to avoid needless rounding.
  av_picture_crop(): Support simple cases with packed pixels too.
  acelp: Remove unused gray_decode table.
  dfa: Remove unused variable.
  configure: Include AVX availability in summary output.
  rawdec: propagate pict_type information to the output frame
  showinfo: replace "CRC" by "checksum"
  showinfo: fix vertical align nit
  showinfo: fix computation of Adler checksum
  imgutils: generalize linesize computation for bitstream formats
  configure: use same CPPFLAGS in kFreeBSD as Linux

Conflicts:
	ffserver.c
	libavcodec/avcodec.h
	libavcodec/opt.h
	libavcodec/version.h
	libavdevice/avdevice.h
	libavfilter/avfilter.h
	libavformat/avformat.h
	libavformat/metadata.c
	libavformat/metadata.h
	libavformat/utils.c
	libavformat/version.h
	libavutil/avutil.h
	libavutil/mem.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
2011-06-16 06:29:01 +02:00

1924 lines
59 KiB
C

/*
* MPEG2 transport stream (aka DVB) demuxer
* Copyright (c) 2002-2003 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//#define USE_SYNCPOINT_SEARCH
#include "libavutil/crc.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavcodec/bytestream.h"
#include "avformat.h"
#include "mpegts.h"
#include "internal.h"
#include "avio_internal.h"
#include "seek.h"
#include "mpeg.h"
#include "isom.h"
/* maximum size in which we look for synchronisation if
synchronisation is lost */
#define MAX_RESYNC_SIZE 65536
#define MAX_PES_PAYLOAD 200*1024
enum MpegTSFilterType {
MPEGTS_PES,
MPEGTS_SECTION,
};
typedef struct MpegTSFilter MpegTSFilter;
typedef int PESCallback(MpegTSFilter *f, const uint8_t *buf, int len, int is_start, int64_t pos);
typedef struct MpegTSPESFilter {
PESCallback *pes_cb;
void *opaque;
} MpegTSPESFilter;
typedef void SectionCallback(MpegTSFilter *f, const uint8_t *buf, int len);
typedef void SetServiceCallback(void *opaque, int ret);
typedef struct MpegTSSectionFilter {
int section_index;
int section_h_size;
uint8_t *section_buf;
unsigned int check_crc:1;
unsigned int end_of_section_reached:1;
SectionCallback *section_cb;
void *opaque;
} MpegTSSectionFilter;
struct MpegTSFilter {
int pid;
int last_cc; /* last cc code (-1 if first packet) */
enum MpegTSFilterType type;
union {
MpegTSPESFilter pes_filter;
MpegTSSectionFilter section_filter;
} u;
};
#define MAX_PIDS_PER_PROGRAM 64
struct Program {
unsigned int id; //program id/service id
unsigned int nb_pids;
unsigned int pids[MAX_PIDS_PER_PROGRAM];
};
struct MpegTSContext {
const AVClass *class;
/* user data */
AVFormatContext *stream;
/** raw packet size, including FEC if present */
int raw_packet_size;
int pos47;
/** if true, all pids are analyzed to find streams */
int auto_guess;
/** compute exact PCR for each transport stream packet */
int mpeg2ts_compute_pcr;
int64_t cur_pcr; /**< used to estimate the exact PCR */
int pcr_incr; /**< used to estimate the exact PCR */
/* data needed to handle file based ts */
/** stop parsing loop */
int stop_parse;
/** packet containing Audio/Video data */
AVPacket *pkt;
/** to detect seek */
int64_t last_pos;
/******************************************/
/* private mpegts data */
/* scan context */
/** structure to keep track of Program->pids mapping */
unsigned int nb_prg;
struct Program *prg;
/** filters for various streams specified by PMT + for the PAT and PMT */
MpegTSFilter *pids[NB_PID_MAX];
};
static const AVOption options[] = {
{"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), FF_OPT_TYPE_INT,
{.dbl = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
static const AVClass mpegtsraw_class = {
.class_name = "mpegtsraw demuxer",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
/* TS stream handling */
enum MpegTSState {
MPEGTS_HEADER = 0,
MPEGTS_PESHEADER,
MPEGTS_PESHEADER_FILL,
MPEGTS_PAYLOAD,
MPEGTS_SKIP,
};
/* enough for PES header + length */
#define PES_START_SIZE 6
#define PES_HEADER_SIZE 9
#define MAX_PES_HEADER_SIZE (9 + 255)
typedef struct PESContext {
int pid;
int pcr_pid; /**< if -1 then all packets containing PCR are considered */
int stream_type;
MpegTSContext *ts;
AVFormatContext *stream;
AVStream *st;
AVStream *sub_st; /**< stream for the embedded AC3 stream in HDMV TrueHD */
enum MpegTSState state;
/* used to get the format */
int data_index;
int total_size;
int pes_header_size;
int extended_stream_id;
int64_t pts, dts;
int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
uint8_t header[MAX_PES_HEADER_SIZE];
uint8_t *buffer;
} PESContext;
extern AVInputFormat ff_mpegts_demuxer;
static void clear_program(MpegTSContext *ts, unsigned int programid)
{
int i;
for(i=0; i<ts->nb_prg; i++)
if(ts->prg[i].id == programid)
ts->prg[i].nb_pids = 0;
}
static void clear_programs(MpegTSContext *ts)
{
av_freep(&ts->prg);
ts->nb_prg=0;
}
static void add_pat_entry(MpegTSContext *ts, unsigned int programid)
{
struct Program *p;
void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(struct Program));
if(!tmp)
return;
ts->prg = tmp;
p = &ts->prg[ts->nb_prg];
p->id = programid;
p->nb_pids = 0;
ts->nb_prg++;
}
static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid)
{
int i;
struct Program *p = NULL;
for(i=0; i<ts->nb_prg; i++) {
if(ts->prg[i].id == programid) {
p = &ts->prg[i];
break;
}
}
if(!p)
return;
if(p->nb_pids >= MAX_PIDS_PER_PROGRAM)
return;
p->pids[p->nb_pids++] = pid;
}
static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid)
{
int i;
for(i=0; i<s->nb_programs; i++) {
if(s->programs[i]->id == programid) {
s->programs[i]->pcr_pid = pid;
break;
}
}
}
/**
* \brief discard_pid() decides if the pid is to be discarded according
* to caller's programs selection
* \param ts : - TS context
* \param pid : - pid
* \return 1 if the pid is only comprised in programs that have .discard=AVDISCARD_ALL
* 0 otherwise
*/
static int discard_pid(MpegTSContext *ts, unsigned int pid)
{
int i, j, k;
int used = 0, discarded = 0;
struct Program *p;
for(i=0; i<ts->nb_prg; i++) {
p = &ts->prg[i];
for(j=0; j<p->nb_pids; j++) {
if(p->pids[j] != pid)
continue;
//is program with id p->id set to be discarded?
for(k=0; k<ts->stream->nb_programs; k++) {
if(ts->stream->programs[k]->id == p->id) {
if(ts->stream->programs[k]->discard == AVDISCARD_ALL)
discarded++;
else
used++;
}
}
}
}
return !used && discarded;
}
/**
* Assemble PES packets out of TS packets, and then call the "section_cb"
* function when they are complete.
*/
static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1,
const uint8_t *buf, int buf_size, int is_start)
{
MpegTSSectionFilter *tss = &tss1->u.section_filter;
int len;
if (is_start) {
memcpy(tss->section_buf, buf, buf_size);
tss->section_index = buf_size;
tss->section_h_size = -1;
tss->end_of_section_reached = 0;
} else {
if (tss->end_of_section_reached)
return;
len = 4096 - tss->section_index;
if (buf_size < len)
len = buf_size;
memcpy(tss->section_buf + tss->section_index, buf, len);
tss->section_index += len;
}
/* compute section length if possible */
if (tss->section_h_size == -1 && tss->section_index >= 3) {
len = (AV_RB16(tss->section_buf + 1) & 0xfff) + 3;
if (len > 4096)
return;
tss->section_h_size = len;
}
if (tss->section_h_size != -1 && tss->section_index >= tss->section_h_size) {
tss->end_of_section_reached = 1;
if (!tss->check_crc ||
av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1,
tss->section_buf, tss->section_h_size) == 0)
tss->section_cb(tss1, tss->section_buf, tss->section_h_size);
}
}
static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, unsigned int pid,
SectionCallback *section_cb, void *opaque,
int check_crc)
{
MpegTSFilter *filter;
MpegTSSectionFilter *sec;
av_dlog(ts->stream, "Filter: pid=0x%x\n", pid);
if (pid >= NB_PID_MAX || ts->pids[pid])
return NULL;
filter = av_mallocz(sizeof(MpegTSFilter));
if (!filter)
return NULL;
ts->pids[pid] = filter;
filter->type = MPEGTS_SECTION;
filter->pid = pid;
filter->last_cc = -1;
sec = &filter->u.section_filter;
sec->section_cb = section_cb;
sec->opaque = opaque;
sec->section_buf = av_malloc(MAX_SECTION_SIZE);
sec->check_crc = check_crc;
if (!sec->section_buf) {
av_free(filter);
return NULL;
}
return filter;
}
static MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid,
PESCallback *pes_cb,
void *opaque)
{
MpegTSFilter *filter;
MpegTSPESFilter *pes;
if (pid >= NB_PID_MAX || ts->pids[pid])
return NULL;
filter = av_mallocz(sizeof(MpegTSFilter));
if (!filter)
return NULL;
ts->pids[pid] = filter;
filter->type = MPEGTS_PES;
filter->pid = pid;
filter->last_cc = -1;
pes = &filter->u.pes_filter;
pes->pes_cb = pes_cb;
pes->opaque = opaque;
return filter;
}
static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
{
int pid;
pid = filter->pid;
if (filter->type == MPEGTS_SECTION)
av_freep(&filter->u.section_filter.section_buf);
else if (filter->type == MPEGTS_PES) {
PESContext *pes = filter->u.pes_filter.opaque;
av_freep(&pes->buffer);
/* referenced private data will be freed later in
* av_close_input_stream */
if (!((PESContext *)filter->u.pes_filter.opaque)->st) {
av_freep(&filter->u.pes_filter.opaque);
}
}
av_free(filter);
ts->pids[pid] = NULL;
}
static int analyze(const uint8_t *buf, int size, int packet_size, int *index){
int stat[TS_MAX_PACKET_SIZE];
int i;
int x=0;
int best_score=0;
memset(stat, 0, packet_size*sizeof(int));
for(x=i=0; i<size-3; i++){
if(buf[i] == 0x47 && !(buf[i+1] & 0x80) && (buf[i+3] & 0x30)){
stat[x]++;
if(stat[x] > best_score){
best_score= stat[x];
if(index) *index= x;
}
}
x++;
if(x == packet_size) x= 0;
}
return best_score;
}
/* autodetect fec presence. Must have at least 1024 bytes */
static int get_packet_size(const uint8_t *buf, int size)
{
int score, fec_score, dvhs_score;
if (size < (TS_FEC_PACKET_SIZE * 5 + 1))
return -1;
score = analyze(buf, size, TS_PACKET_SIZE, NULL);
dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, NULL);
fec_score= analyze(buf, size, TS_FEC_PACKET_SIZE, NULL);
// av_log(NULL, AV_LOG_DEBUG, "score: %d, dvhs_score: %d, fec_score: %d \n", score, dvhs_score, fec_score);
if (score > fec_score && score > dvhs_score) return TS_PACKET_SIZE;
else if(dvhs_score > score && dvhs_score > fec_score) return TS_DVHS_PACKET_SIZE;
else if(score < fec_score && dvhs_score < fec_score) return TS_FEC_PACKET_SIZE;
else return -1;
}
typedef struct SectionHeader {
uint8_t tid;
uint16_t id;
uint8_t version;
uint8_t sec_num;
uint8_t last_sec_num;
} SectionHeader;
static inline int get8(const uint8_t **pp, const uint8_t *p_end)
{
const uint8_t *p;
int c;
p = *pp;
if (p >= p_end)
return -1;
c = *p++;
*pp = p;
return c;
}
static inline int get16(const uint8_t **pp, const uint8_t *p_end)
{
const uint8_t *p;
int c;
p = *pp;
if ((p + 1) >= p_end)
return -1;
c = AV_RB16(p);
p += 2;
*pp = p;
return c;
}
/* read and allocate a DVB string preceeded by its length */
static char *getstr8(const uint8_t **pp, const uint8_t *p_end)
{
int len;
const uint8_t *p;
char *str;
p = *pp;
len = get8(&p, p_end);
if (len < 0)
return NULL;
if ((p + len) > p_end)
return NULL;
str = av_malloc(len + 1);
if (!str)
return NULL;
memcpy(str, p, len);
str[len] = '\0';
p += len;
*pp = p;
return str;
}
static int parse_section_header(SectionHeader *h,
const uint8_t **pp, const uint8_t *p_end)
{
int val;
val = get8(pp, p_end);
if (val < 0)
return -1;
h->tid = val;
*pp += 2;
val = get16(pp, p_end);
if (val < 0)
return -1;
h->id = val;
val = get8(pp, p_end);
if (val < 0)
return -1;
h->version = (val >> 1) & 0x1f;
val = get8(pp, p_end);
if (val < 0)
return -1;
h->sec_num = val;
val = get8(pp, p_end);
if (val < 0)
return -1;
h->last_sec_num = val;
return 0;
}
typedef struct {
uint32_t stream_type;
enum AVMediaType codec_type;
enum CodecID codec_id;
} StreamType;
static const StreamType ISO_types[] = {
{ 0x01, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG2VIDEO },
{ 0x02, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG2VIDEO },
{ 0x03, AVMEDIA_TYPE_AUDIO, CODEC_ID_MP3 },
{ 0x04, AVMEDIA_TYPE_AUDIO, CODEC_ID_MP3 },
{ 0x0f, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC },
{ 0x10, AVMEDIA_TYPE_VIDEO, CODEC_ID_MPEG4 },
{ 0x11, AVMEDIA_TYPE_AUDIO, CODEC_ID_AAC_LATM }, /* LATM syntax */
{ 0x1b, AVMEDIA_TYPE_VIDEO, CODEC_ID_H264 },
{ 0xd1, AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC },
{ 0xea, AVMEDIA_TYPE_VIDEO, CODEC_ID_VC1 },
{ 0 },
};
static const StreamType HDMV_types[] = {
{ 0x80, AVMEDIA_TYPE_AUDIO, CODEC_ID_PCM_BLURAY },
{ 0x81, AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 },
{ 0x82, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
{ 0x83, AVMEDIA_TYPE_AUDIO, CODEC_ID_TRUEHD },
{ 0x84, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 },
{ 0x90, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_HDMV_PGS_SUBTITLE },
{ 0 },
};
/* ATSC ? */
static const StreamType MISC_types[] = {
{ 0x81, AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 },
{ 0x8a, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
{ 0 },
};
static const StreamType REGD_types[] = {
{ MKTAG('d','r','a','c'), AVMEDIA_TYPE_VIDEO, CODEC_ID_DIRAC },
{ MKTAG('A','C','-','3'), AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 },
{ MKTAG('B','S','S','D'), AVMEDIA_TYPE_AUDIO, CODEC_ID_S302M },
{ 0 },
};
/* descriptor present */
static const StreamType DESC_types[] = {
{ 0x6a, AVMEDIA_TYPE_AUDIO, CODEC_ID_AC3 }, /* AC-3 descriptor */
{ 0x7a, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, /* E-AC-3 descriptor */
{ 0x7b, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS },
{ 0x56, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_DVB_TELETEXT },
{ 0x59, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */
{ 0 },
};
static void mpegts_find_stream_type(AVStream *st,
uint32_t stream_type, const StreamType *types)
{
for (; types->stream_type; types++) {
if (stream_type == types->stream_type) {
st->codec->codec_type = types->codec_type;
st->codec->codec_id = types->codec_id;
st->request_probe = 0;
return;
}
}
}
static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
uint32_t stream_type, uint32_t prog_reg_desc)
{
av_set_pts_info(st, 33, 1, 90000);
st->priv_data = pes;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = CODEC_ID_NONE;
st->need_parsing = AVSTREAM_PARSE_FULL;
pes->st = st;
pes->stream_type = stream_type;
av_log(pes->stream, AV_LOG_DEBUG,
"stream=%d stream_type=%x pid=%x prog_reg_desc=%.4s\n",
st->index, pes->stream_type, pes->pid, (char*)&prog_reg_desc);
st->codec->codec_tag = pes->stream_type;
mpegts_find_stream_type(st, pes->stream_type, ISO_types);
if (prog_reg_desc == AV_RL32("HDMV") &&
st->codec->codec_id == CODEC_ID_NONE) {
mpegts_find_stream_type(st, pes->stream_type, HDMV_types);
if (pes->stream_type == 0x83) {
// HDMV TrueHD streams also contain an AC3 coded version of the
// audio track - add a second stream for this
AVStream *sub_st;
// priv_data cannot be shared between streams
PESContext *sub_pes = av_malloc(sizeof(*sub_pes));
if (!sub_pes)
return AVERROR(ENOMEM);
memcpy(sub_pes, pes, sizeof(*sub_pes));
sub_st = av_new_stream(pes->stream, pes->pid);
if (!sub_st) {
av_free(sub_pes);
return AVERROR(ENOMEM);
}
av_set_pts_info(sub_st, 33, 1, 90000);
sub_st->priv_data = sub_pes;
sub_st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
sub_st->codec->codec_id = CODEC_ID_AC3;
sub_st->need_parsing = AVSTREAM_PARSE_FULL;
sub_pes->sub_st = pes->sub_st = sub_st;
}
}
if (st->codec->codec_id == CODEC_ID_NONE)
mpegts_find_stream_type(st, pes->stream_type, MISC_types);
return 0;
}
static void new_pes_packet(PESContext *pes, AVPacket *pkt)
{
av_init_packet(pkt);
pkt->destruct = av_destruct_packet;
pkt->data = pes->buffer;
pkt->size = pes->data_index;
memset(pkt->data+pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
// Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID
if (pes->sub_st && pes->stream_type == 0x83 && pes->extended_stream_id == 0x76)
pkt->stream_index = pes->sub_st->index;
else
pkt->stream_index = pes->st->index;
pkt->pts = pes->pts;
pkt->dts = pes->dts;
/* store position of first TS packet of this PES packet */
pkt->pos = pes->ts_packet_pos;
/* reset pts values */
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
pes->buffer = NULL;
pes->data_index = 0;
}
/* return non zero if a packet could be constructed */
static int mpegts_push_data(MpegTSFilter *filter,
const uint8_t *buf, int buf_size, int is_start,
int64_t pos)
{
PESContext *pes = filter->u.pes_filter.opaque;
MpegTSContext *ts = pes->ts;
const uint8_t *p;
int len, code;
if(!ts->pkt)
return 0;
if (is_start) {
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) {
new_pes_packet(pes, ts->pkt);
ts->stop_parse = 1;
}
pes->state = MPEGTS_HEADER;
pes->data_index = 0;
pes->ts_packet_pos = pos;
}
p = buf;
while (buf_size > 0) {
switch(pes->state) {
case MPEGTS_HEADER:
len = PES_START_SIZE - pes->data_index;
if (len > buf_size)
len = buf_size;
memcpy(pes->header + pes->data_index, p, len);
pes->data_index += len;
p += len;
buf_size -= len;
if (pes->data_index == PES_START_SIZE) {
/* we got all the PES or section header. We can now
decide */
if (pes->header[0] == 0x00 && pes->header[1] == 0x00 &&
pes->header[2] == 0x01) {
/* it must be an mpeg2 PES stream */
code = pes->header[3] | 0x100;
av_dlog(pes->stream, "pid=%x pes_code=%#x\n", pes->pid, code);
if ((pes->st && pes->st->discard == AVDISCARD_ALL) ||
code == 0x1be) /* padding_stream */
goto skip;
#if FF_API_MAX_STREAMS
if (!pes->st && pes->stream->nb_streams == MAX_STREAMS)
goto skip;
#endif
/* stream not present in PMT */
if (!pes->st) {
pes->st = av_new_stream(ts->stream, pes->pid);
if (!pes->st)
return AVERROR(ENOMEM);
mpegts_set_stream_info(pes->st, pes, 0, 0);
}
pes->total_size = AV_RB16(pes->header + 4);
/* NOTE: a zero total size means the PES size is
unbounded */
if (!pes->total_size)
pes->total_size = MAX_PES_PAYLOAD;
/* allocate pes buffer */
pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
if (!pes->buffer)
return AVERROR(ENOMEM);
if (code != 0x1bc && code != 0x1bf && /* program_stream_map, private_stream_2 */
code != 0x1f0 && code != 0x1f1 && /* ECM, EMM */
code != 0x1ff && code != 0x1f2 && /* program_stream_directory, DSMCC_stream */
code != 0x1f8) { /* ITU-T Rec. H.222.1 type E stream */
pes->state = MPEGTS_PESHEADER;
if (pes->st->codec->codec_id == CODEC_ID_NONE && !pes->st->request_probe) {
av_dlog(pes->stream, "pid=%x stream_type=%x probing\n",
pes->pid, pes->stream_type);
pes->st->request_probe= 1;
}
} else {
pes->state = MPEGTS_PAYLOAD;
pes->data_index = 0;
}
} else {
/* otherwise, it should be a table */
/* skip packet */
skip:
pes->state = MPEGTS_SKIP;
continue;
}
}
break;
/**********************************************/
/* PES packing parsing */
case MPEGTS_PESHEADER:
len = PES_HEADER_SIZE - pes->data_index;
if (len < 0)
return -1;
if (len > buf_size)
len = buf_size;
memcpy(pes->header + pes->data_index, p, len);
pes->data_index += len;
p += len;
buf_size -= len;
if (pes->data_index == PES_HEADER_SIZE) {
pes->pes_header_size = pes->header[8] + 9;
pes->state = MPEGTS_PESHEADER_FILL;
}
break;
case MPEGTS_PESHEADER_FILL:
len = pes->pes_header_size - pes->data_index;
if (len < 0)
return -1;
if (len > buf_size)
len = buf_size;
memcpy(pes->header + pes->data_index, p, len);
pes->data_index += len;
p += len;
buf_size -= len;
if (pes->data_index == pes->pes_header_size) {
const uint8_t *r;
unsigned int flags, pes_ext, skip;
flags = pes->header[7];
r = pes->header + 9;
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
if ((flags & 0xc0) == 0x80) {
pes->dts = pes->pts = ff_parse_pes_pts(r);
r += 5;
} else if ((flags & 0xc0) == 0xc0) {
pes->pts = ff_parse_pes_pts(r);
r += 5;
pes->dts = ff_parse_pes_pts(r);
r += 5;
}
pes->extended_stream_id = -1;
if (flags & 0x01) { /* PES extension */
pes_ext = *r++;
/* Skip PES private data, program packet sequence counter and P-STD buffer */
skip = (pes_ext >> 4) & 0xb;
skip += skip & 0x9;
r += skip;
if ((pes_ext & 0x41) == 0x01 &&
(r + 2) <= (pes->header + pes->pes_header_size)) {
/* PES extension 2 */
if ((r[0] & 0x7f) > 0 && (r[1] & 0x80) == 0)
pes->extended_stream_id = r[1];
}
}
/* we got the full header. We parse it and get the payload */
pes->state = MPEGTS_PAYLOAD;
pes->data_index = 0;
}
break;
case MPEGTS_PAYLOAD:
if (buf_size > 0 && pes->buffer) {
if (pes->data_index > 0 && pes->data_index+buf_size > pes->total_size) {
new_pes_packet(pes, ts->pkt);
pes->total_size = MAX_PES_PAYLOAD;
pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
if (!pes->buffer)
return AVERROR(ENOMEM);
ts->stop_parse = 1;
} else if (pes->data_index == 0 && buf_size > pes->total_size) {
// pes packet size is < ts size packet and pes data is padded with 0xff
// not sure if this is legal in ts but see issue #2392
buf_size = pes->total_size;
}
memcpy(pes->buffer+pes->data_index, p, buf_size);
pes->data_index += buf_size;
}
buf_size = 0;
/* emit complete packets with known packet size
* decreases demuxer delay for infrequent packets like subtitles from
* a couple of seconds to milliseconds for properly muxed files.
* total_size is the number of bytes following pes_packet_length
* in the pes header, i.e. not counting the first 6 bytes */
if (!ts->stop_parse && pes->total_size < MAX_PES_PAYLOAD &&
pes->pes_header_size + pes->data_index == pes->total_size + 6) {
ts->stop_parse = 1;
new_pes_packet(pes, ts->pkt);
}
break;
case MPEGTS_SKIP:
buf_size = 0;
break;
}
}
return 0;
}
static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid)
{
MpegTSFilter *tss;
PESContext *pes;
/* if no pid found, then add a pid context */
pes = av_mallocz(sizeof(PESContext));
if (!pes)
return 0;
pes->ts = ts;
pes->stream = ts->stream;
pes->pid = pid;
pes->pcr_pid = pcr_pid;
pes->state = MPEGTS_SKIP;
pes->pts = AV_NOPTS_VALUE;
pes->dts = AV_NOPTS_VALUE;
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
if (!tss) {
av_free(pes);
return 0;
}
return pes;
}
static int mp4_read_iods(AVFormatContext *s, const uint8_t *buf, unsigned size,
int *es_id, uint8_t **dec_config_descr,
int *dec_config_descr_size)
{
AVIOContext pb;
int tag;
unsigned len;
ffio_init_context(&pb, buf, size, 0, NULL, NULL, NULL, NULL);
len = ff_mp4_read_descr(s, &pb, &tag);
if (tag == MP4IODescrTag) {
avio_rb16(&pb); // ID
avio_r8(&pb);
avio_r8(&pb);
avio_r8(&pb);
avio_r8(&pb);
avio_r8(&pb);
len = ff_mp4_read_descr(s, &pb, &tag);
if (tag == MP4ESDescrTag) {
*es_id = avio_rb16(&pb); /* ES_ID */
av_dlog(s, "ES_ID %#x\n", *es_id);
avio_r8(&pb); /* priority */
len = ff_mp4_read_descr(s, &pb, &tag);
if (tag == MP4DecConfigDescrTag) {
*dec_config_descr = av_malloc(len);
if (!*dec_config_descr)
return AVERROR(ENOMEM);
*dec_config_descr_size = len;
avio_read(&pb, *dec_config_descr, len);
}
}
}
return 0;
}
int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type,
const uint8_t **pp, const uint8_t *desc_list_end,
int mp4_dec_config_descr_len, int mp4_es_id, int pid,
uint8_t *mp4_dec_config_descr)
{
const uint8_t *desc_end;
int desc_len, desc_tag;
char language[252];
int i;
desc_tag = get8(pp, desc_list_end);
if (desc_tag < 0)
return -1;
desc_len = get8(pp, desc_list_end);
if (desc_len < 0)
return -1;
desc_end = *pp + desc_len;
if (desc_end > desc_list_end)
return -1;
av_dlog(fc, "tag: 0x%02x len=%d\n", desc_tag, desc_len);
if (st->codec->codec_id == CODEC_ID_NONE &&
stream_type == STREAM_TYPE_PRIVATE_DATA)
mpegts_find_stream_type(st, desc_tag, DESC_types);
switch(desc_tag) {
case 0x1F: /* FMC descriptor */
get16(pp, desc_end);
if (st->codec->codec_id == CODEC_ID_AAC_LATM &&
mp4_dec_config_descr_len && mp4_es_id == pid) {
AVIOContext pb;
ffio_init_context(&pb, mp4_dec_config_descr,
mp4_dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
ff_mp4_read_dec_config_descr(fc, st, &pb);
if (st->codec->codec_id == CODEC_ID_AAC &&
st->codec->extradata_size > 0)
st->need_parsing = 0;
}
break;
case 0x56: /* DVB teletext descriptor */
language[0] = get8(pp, desc_end);
language[1] = get8(pp, desc_end);
language[2] = get8(pp, desc_end);
language[3] = 0;
av_dict_set(&st->metadata, "language", language, 0);
break;
case 0x59: /* subtitling descriptor */
language[0] = get8(pp, desc_end);
language[1] = get8(pp, desc_end);
language[2] = get8(pp, desc_end);
language[3] = 0;
/* hearing impaired subtitles detection */
switch(get8(pp, desc_end)) {
case 0x20: /* DVB subtitles (for the hard of hearing) with no monitor aspect ratio criticality */
case 0x21: /* DVB subtitles (for the hard of hearing) for display on 4:3 aspect ratio monitor */
case 0x22: /* DVB subtitles (for the hard of hearing) for display on 16:9 aspect ratio monitor */
case 0x23: /* DVB subtitles (for the hard of hearing) for display on 2.21:1 aspect ratio monitor */
case 0x24: /* DVB subtitles (for the hard of hearing) for display on a high definition monitor */
case 0x25: /* DVB subtitles (for the hard of hearing) with plano-stereoscopic disparity for display on a high definition monitor */
st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
break;
}
if (st->codec->extradata) {
if (st->codec->extradata_size == 4 && memcmp(st->codec->extradata, *pp, 4))
av_log_ask_for_sample(fc, "DVB sub with multiple IDs\n");
} else {
st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
if (st->codec->extradata) {
st->codec->extradata_size = 4;
memcpy(st->codec->extradata, *pp, 4);
}
}
*pp += 4;
av_dict_set(&st->metadata, "language", language, 0);
break;
case 0x0a: /* ISO 639 language descriptor */
for (i = 0; i + 4 <= desc_len; i += 4) {
language[i + 0] = get8(pp, desc_end);
language[i + 1] = get8(pp, desc_end);
language[i + 2] = get8(pp, desc_end);
language[i + 3] = ',';
switch (get8(pp, desc_end)) {
case 0x01: st->disposition |= AV_DISPOSITION_CLEAN_EFFECTS; break;
case 0x02: st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; break;
case 0x03: st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; break;
}
}
if (i) {
language[i - 1] = 0;
av_dict_set(&st->metadata, "language", language, 0);
}
break;
case 0x05: /* registration descriptor */
st->codec->codec_tag = bytestream_get_le32(pp);
av_dlog(fc, "reg_desc=%.4s\n", (char*)&st->codec->codec_tag);
if (st->codec->codec_id == CODEC_ID_NONE &&
stream_type == STREAM_TYPE_PRIVATE_DATA)
mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types);
break;
case 0x52: /* stream identifier descriptor */
st->stream_identifier = 1 + get8(pp, desc_end);
break;
default:
break;
}
*pp = desc_end;
return 0;
}
static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
MpegTSContext *ts = filter->u.section_filter.opaque;
SectionHeader h1, *h = &h1;
PESContext *pes;
AVStream *st;
const uint8_t *p, *p_end, *desc_list_end;
int program_info_length, pcr_pid, pid, stream_type;
int desc_list_len;
uint32_t prog_reg_desc = 0; /* registration descriptor */
uint8_t *mp4_dec_config_descr = NULL;
int mp4_dec_config_descr_len = 0;
int mp4_es_id = 0;
av_dlog(ts->stream, "PMT: len %i\n", section_len);
hex_dump_debug(ts->stream, (uint8_t *)section, section_len);
p_end = section + section_len - 4;
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
av_dlog(ts->stream, "sid=0x%x sec_num=%d/%d\n",
h->id, h->sec_num, h->last_sec_num);
if (h->tid != PMT_TID)
return;
clear_program(ts, h->id);
pcr_pid = get16(&p, p_end) & 0x1fff;
if (pcr_pid < 0)
return;
add_pid_to_pmt(ts, h->id, pcr_pid);
set_pcr_pid(ts->stream, h->id, pcr_pid);
av_dlog(ts->stream, "pcr_pid=0x%x\n", pcr_pid);
program_info_length = get16(&p, p_end) & 0xfff;
if (program_info_length < 0)
return;
while(program_info_length >= 2) {
uint8_t tag, len;
tag = get8(&p, p_end);
len = get8(&p, p_end);
av_dlog(ts->stream, "program tag: 0x%02x len=%d\n", tag, len);
if(len > program_info_length - 2)
//something else is broken, exit the program_descriptors_loop
break;
program_info_length -= len + 2;
if (tag == 0x1d) { // IOD descriptor
get8(&p, p_end); // scope
get8(&p, p_end); // label
len -= 2;
mp4_read_iods(ts->stream, p, len, &mp4_es_id,
&mp4_dec_config_descr, &mp4_dec_config_descr_len);
} else if (tag == 0x05 && len >= 4) { // registration descriptor
prog_reg_desc = bytestream_get_le32(&p);
len -= 4;
}
p += len;
}
p += program_info_length;
if (p >= p_end)
goto out;
// stop parsing after pmt, we found header
if (!ts->stream->nb_streams)
ts->stop_parse = 1;
for(;;) {
st = 0;
stream_type = get8(&p, p_end);
if (stream_type < 0)
break;
pid = get16(&p, p_end) & 0x1fff;
if (pid < 0)
break;
/* now create ffmpeg stream */
if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) {
pes = ts->pids[pid]->u.pes_filter.opaque;
if (!pes->st)
pes->st = av_new_stream(pes->stream, pes->pid);
st = pes->st;
} else {
if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably
pes = add_pes_stream(ts, pid, pcr_pid);
if (pes)
st = av_new_stream(pes->stream, pes->pid);
}
if (!st)
goto out;
if (!pes->stream_type)
mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc);
add_pid_to_pmt(ts, h->id, pid);
ff_program_add_stream_index(ts->stream, h->id, st->index);
desc_list_len = get16(&p, p_end) & 0xfff;
if (desc_list_len < 0)
break;
desc_list_end = p + desc_list_len;
if (desc_list_end > p_end)
break;
for(;;) {
if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, desc_list_end,
mp4_dec_config_descr_len, mp4_es_id, pid, mp4_dec_config_descr) < 0)
break;
if (prog_reg_desc == AV_RL32("HDMV") && stream_type == 0x83 && pes->sub_st) {
ff_program_add_stream_index(ts->stream, h->id, pes->sub_st->index);
pes->sub_st->codec->codec_tag = st->codec->codec_tag;
}
}
p = desc_list_end;
}
out:
av_free(mp4_dec_config_descr);
}
static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
MpegTSContext *ts = filter->u.section_filter.opaque;
SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end;
int sid, pmt_pid;
AVProgram *program;
av_dlog(ts->stream, "PAT:\n");
hex_dump_debug(ts->stream, (uint8_t *)section, section_len);
p_end = section + section_len - 4;
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
if (h->tid != PAT_TID)
return;
ts->stream->ts_id = h->id;
clear_programs(ts);
for(;;) {
sid = get16(&p, p_end);
if (sid < 0)
break;
pmt_pid = get16(&p, p_end) & 0x1fff;
if (pmt_pid < 0)
break;
av_dlog(ts->stream, "sid=0x%x pid=0x%x\n", sid, pmt_pid);
if (sid == 0x0000) {
/* NIT info */
} else {
program = av_new_program(ts->stream, sid);
program->program_num = sid;
program->pmt_pid = pmt_pid;
if (ts->pids[pmt_pid])
mpegts_close_filter(ts, ts->pids[pmt_pid]);
mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
add_pat_entry(ts, sid);
add_pid_to_pmt(ts, sid, 0); //add pat pid to program
add_pid_to_pmt(ts, sid, pmt_pid);
}
}
}
static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
MpegTSContext *ts = filter->u.section_filter.opaque;
SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end, *desc_list_end, *desc_end;
int onid, val, sid, desc_list_len, desc_tag, desc_len, service_type;
char *name, *provider_name;
av_dlog(ts->stream, "SDT:\n");
hex_dump_debug(ts->stream, (uint8_t *)section, section_len);
p_end = section + section_len - 4;
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
if (h->tid != SDT_TID)
return;
onid = get16(&p, p_end);
if (onid < 0)
return;
val = get8(&p, p_end);
if (val < 0)
return;
for(;;) {
sid = get16(&p, p_end);
if (sid < 0)
break;
val = get8(&p, p_end);
if (val < 0)
break;
desc_list_len = get16(&p, p_end) & 0xfff;
if (desc_list_len < 0)
break;
desc_list_end = p + desc_list_len;
if (desc_list_end > p_end)
break;
for(;;) {
desc_tag = get8(&p, desc_list_end);
if (desc_tag < 0)
break;
desc_len = get8(&p, desc_list_end);
desc_end = p + desc_len;
if (desc_end > desc_list_end)
break;
av_dlog(ts->stream, "tag: 0x%02x len=%d\n",
desc_tag, desc_len);
switch(desc_tag) {
case 0x48:
service_type = get8(&p, p_end);
if (service_type < 0)
break;
provider_name = getstr8(&p, p_end);
if (!provider_name)
break;
name = getstr8(&p, p_end);
if (name) {
AVProgram *program = av_new_program(ts->stream, sid);
if(program) {
av_dict_set(&program->metadata, "service_name", name, 0);
av_dict_set(&program->metadata, "service_provider", provider_name, 0);
}
}
av_free(name);
av_free(provider_name);
break;
default:
break;
}
p = desc_end;
}
p = desc_list_end;
}
}
/* handle one TS packet */
static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
AVFormatContext *s = ts->stream;
MpegTSFilter *tss;
int len, pid, cc, cc_ok, afc, is_start;
const uint8_t *p, *p_end;
int64_t pos;
pid = AV_RB16(packet + 1) & 0x1fff;
if(pid && discard_pid(ts, pid))
return 0;
is_start = packet[1] & 0x40;
tss = ts->pids[pid];
if (ts->auto_guess && tss == NULL && is_start) {
add_pes_stream(ts, pid, -1);
tss = ts->pids[pid];
}
if (!tss)
return 0;
/* continuity check (currently not used) */
cc = (packet[3] & 0xf);
cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc));
tss->last_cc = cc;
/* skip adaptation field */
afc = (packet[3] >> 4) & 3;
p = packet + 4;
if (afc == 0) /* reserved value */
return 0;
if (afc == 2) /* adaptation field only */
return 0;
if (afc == 3) {
/* skip adapation field */
p += p[0] + 1;
}
/* if past the end of packet, ignore */
p_end = packet + TS_PACKET_SIZE;
if (p >= p_end)
return 0;
pos = avio_tell(ts->stream->pb);
ts->pos47= pos % ts->raw_packet_size;
if (tss->type == MPEGTS_SECTION) {
if (is_start) {
/* pointer field present */
len = *p++;
if (p + len > p_end)
return 0;
if (len && cc_ok) {
/* write remaining section bytes */
write_section_data(s, tss,
p, len, 0);
/* check whether filter has been closed */
if (!ts->pids[pid])
return 0;
}
p += len;
if (p < p_end) {
write_section_data(s, tss,
p, p_end - p, 1);
}
} else {
if (cc_ok) {
write_section_data(s, tss,
p, p_end - p, 0);
}
}
} else {
int ret;
// Note: The position here points actually behind the current packet.
if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,
pos - ts->raw_packet_size)) < 0)
return ret;
}
return 0;
}
/* XXX: try to find a better synchro over several packets (use
get_packet_size() ?) */
static int mpegts_resync(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
int c, i;
for(i = 0;i < MAX_RESYNC_SIZE; i++) {
c = avio_r8(pb);
if (url_feof(pb))
return -1;
if (c == 0x47) {
avio_seek(pb, -1, SEEK_CUR);
return 0;
}
}
av_log(s, AV_LOG_ERROR, "max resync size reached, could not find sync byte\n");
/* no sync found */
return -1;
}
/* return -1 if error or EOF. Return 0 if OK. */
static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size)
{
AVIOContext *pb = s->pb;
int skip, len;
for(;;) {
len = avio_read(pb, buf, TS_PACKET_SIZE);
if (len != TS_PACKET_SIZE)
return len < 0 ? len : AVERROR_EOF;
/* check paquet sync byte */
if (buf[0] != 0x47) {
/* find a new packet start */
avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR);
if (mpegts_resync(s) < 0)
return AVERROR(EAGAIN);
else
continue;
} else {
skip = raw_packet_size - TS_PACKET_SIZE;
if (skip > 0)
avio_skip(pb, skip);
break;
}
}
return 0;
}
static int handle_packets(MpegTSContext *ts, int nb_packets)
{
AVFormatContext *s = ts->stream;
uint8_t packet[TS_PACKET_SIZE];
int packet_num, ret;
ts->stop_parse = 0;
packet_num = 0;
for(;;) {
if (ts->stop_parse>0)
break;
packet_num++;
if (nb_packets != 0 && packet_num >= nb_packets)
break;
ret = read_packet(s, packet, ts->raw_packet_size);
if (ret != 0)
return ret;
ret = handle_packet(ts, packet);
if (ret != 0)
return ret;
}
return 0;
}
static int mpegts_probe(AVProbeData *p)
{
#if 1
const int size= p->buf_size;
int score, fec_score, dvhs_score;
int check_count= size / TS_FEC_PACKET_SIZE;
#define CHECK_COUNT 10
if (check_count < CHECK_COUNT)
return -1;
score = analyze(p->buf, TS_PACKET_SIZE *check_count, TS_PACKET_SIZE , NULL)*CHECK_COUNT/check_count;
dvhs_score= analyze(p->buf, TS_DVHS_PACKET_SIZE*check_count, TS_DVHS_PACKET_SIZE, NULL)*CHECK_COUNT/check_count;
fec_score = analyze(p->buf, TS_FEC_PACKET_SIZE *check_count, TS_FEC_PACKET_SIZE , NULL)*CHECK_COUNT/check_count;
// av_log(NULL, AV_LOG_DEBUG, "score: %d, dvhs_score: %d, fec_score: %d \n", score, dvhs_score, fec_score);
// we need a clear definition for the returned score otherwise things will become messy sooner or later
if (score > fec_score && score > dvhs_score && score > 6) return AVPROBE_SCORE_MAX + score - CHECK_COUNT;
else if(dvhs_score > score && dvhs_score > fec_score && dvhs_score > 6) return AVPROBE_SCORE_MAX + dvhs_score - CHECK_COUNT;
else if( fec_score > 6) return AVPROBE_SCORE_MAX + fec_score - CHECK_COUNT;
else return -1;
#else
/* only use the extension for safer guess */
if (av_match_ext(p->filename, "ts"))
return AVPROBE_SCORE_MAX;
else
return 0;
#endif
}
/* return the 90kHz PCR and the extension for the 27MHz PCR. return
(-1) if not available */
static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
const uint8_t *packet)
{
int afc, len, flags;
const uint8_t *p;
unsigned int v;
afc = (packet[3] >> 4) & 3;
if (afc <= 1)
return -1;
p = packet + 4;
len = p[0];
p++;
if (len == 0)
return -1;
flags = *p++;
len--;
if (!(flags & 0x10))
return -1;
if (len < 6)
return -1;
v = AV_RB32(p);
*ppcr_high = ((int64_t)v << 1) | (p[4] >> 7);
*ppcr_low = ((p[4] & 1) << 8) | p[5];
return 0;
}
static int mpegts_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
MpegTSContext *ts = s->priv_data;
AVIOContext *pb = s->pb;
uint8_t buf[8*1024];
int len;
int64_t pos;
#if FF_API_FORMAT_PARAMETERS
if (ap) {
if (ap->mpeg2ts_compute_pcr)
ts->mpeg2ts_compute_pcr = ap->mpeg2ts_compute_pcr;
if(ap->mpeg2ts_raw){
av_log(s, AV_LOG_ERROR, "use mpegtsraw_demuxer!\n");
return -1;
}
}
#endif
/* read the first 1024 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
if (len != sizeof(buf))
goto fail;
ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
if (ts->raw_packet_size <= 0) {
av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n");
ts->raw_packet_size = TS_PACKET_SIZE;
}
ts->stream = s;
ts->auto_guess = 0;
if (s->iformat == &ff_mpegts_demuxer) {
/* normal demux */
/* first do a scaning to get all the services */
if (avio_seek(pb, pos, SEEK_SET) < 0)
av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n");
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
handle_packets(ts, s->probesize / ts->raw_packet_size);
/* if could not find service, enable auto_guess */
ts->auto_guess = 1;
av_dlog(ts->stream, "tuning done\n");
s->ctx_flags |= AVFMTCTX_NOHEADER;
} else {
AVStream *st;
int pcr_pid, pid, nb_packets, nb_pcrs, ret, pcr_l;
int64_t pcrs[2], pcr_h;
int packet_count[2];
uint8_t packet[TS_PACKET_SIZE];
/* only read packets */
st = av_new_stream(s, 0);
if (!st)
goto fail;
av_set_pts_info(st, 60, 1, 27000000);
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = CODEC_ID_MPEG2TS;
/* we iterate until we find two PCRs to estimate the bitrate */
pcr_pid = -1;
nb_pcrs = 0;
nb_packets = 0;
for(;;) {
ret = read_packet(s, packet, ts->raw_packet_size);
if (ret < 0)
return -1;
pid = AV_RB16(packet + 1) & 0x1fff;
if ((pcr_pid == -1 || pcr_pid == pid) &&
parse_pcr(&pcr_h, &pcr_l, packet) == 0) {
pcr_pid = pid;
packet_count[nb_pcrs] = nb_packets;
pcrs[nb_pcrs] = pcr_h * 300 + pcr_l;
nb_pcrs++;
if (nb_pcrs >= 2)
break;
}
nb_packets++;
}
/* NOTE1: the bitrate is computed without the FEC */
/* NOTE2: it is only the bitrate of the start of the stream */
ts->pcr_incr = (pcrs[1] - pcrs[0]) / (packet_count[1] - packet_count[0]);
ts->cur_pcr = pcrs[0] - ts->pcr_incr * packet_count[0];
s->bit_rate = (TS_PACKET_SIZE * 8) * 27e6 / ts->pcr_incr;
st->codec->bit_rate = s->bit_rate;
st->start_time = ts->cur_pcr;
av_dlog(ts->stream, "start=%0.3f pcr=%0.3f incr=%d\n",
st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);
}
avio_seek(pb, pos, SEEK_SET);
return 0;
fail:
return -1;
}
#define MAX_PACKET_READAHEAD ((128 * 1024) / 188)
static int mpegts_raw_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
MpegTSContext *ts = s->priv_data;
int ret, i;
int64_t pcr_h, next_pcr_h, pos;
int pcr_l, next_pcr_l;
uint8_t pcr_buf[12];
if (av_new_packet(pkt, TS_PACKET_SIZE) < 0)
return AVERROR(ENOMEM);
pkt->pos= avio_tell(s->pb);
ret = read_packet(s, pkt->data, ts->raw_packet_size);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
if (ts->mpeg2ts_compute_pcr) {
/* compute exact PCR for each packet */
if (parse_pcr(&pcr_h, &pcr_l, pkt->data) == 0) {
/* we read the next PCR (XXX: optimize it by using a bigger buffer */
pos = avio_tell(s->pb);
for(i = 0; i < MAX_PACKET_READAHEAD; i++) {
avio_seek(s->pb, pos + i * ts->raw_packet_size, SEEK_SET);
avio_read(s->pb, pcr_buf, 12);
if (parse_pcr(&next_pcr_h, &next_pcr_l, pcr_buf) == 0) {
/* XXX: not precise enough */
ts->pcr_incr = ((next_pcr_h - pcr_h) * 300 + (next_pcr_l - pcr_l)) /
(i + 1);
break;
}
}
avio_seek(s->pb, pos, SEEK_SET);
/* no next PCR found: we use previous increment */
ts->cur_pcr = pcr_h * 300 + pcr_l;
}
pkt->pts = ts->cur_pcr;
pkt->duration = ts->pcr_incr;
ts->cur_pcr += ts->pcr_incr;
}
pkt->stream_index = 0;
return 0;
}
static int mpegts_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
MpegTSContext *ts = s->priv_data;
int ret, i;
if (avio_tell(s->pb) != ts->last_pos) {
/* seek detected, flush pes buffer */
for (i = 0; i < NB_PID_MAX; i++) {
if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) {
PESContext *pes = ts->pids[i]->u.pes_filter.opaque;
av_freep(&pes->buffer);
pes->data_index = 0;
pes->state = MPEGTS_SKIP; /* skip until pes header */
}
}
}
ts->pkt = pkt;
ret = handle_packets(ts, 0);
if (ret < 0) {
/* flush pes data left */
for (i = 0; i < NB_PID_MAX; i++) {
if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) {
PESContext *pes = ts->pids[i]->u.pes_filter.opaque;
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) {
new_pes_packet(pes, pkt);
pes->state = MPEGTS_SKIP;
ret = 0;
break;
}
}
}
}
ts->last_pos = avio_tell(s->pb);
return ret;
}
static int mpegts_read_close(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
int i;
clear_programs(ts);
for(i=0;i<NB_PID_MAX;i++)
if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]);
return 0;
}
static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
int64_t *ppos, int64_t pos_limit)
{
MpegTSContext *ts = s->priv_data;
int64_t pos, timestamp;
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid;
const int find_next= 1;
pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
if (find_next) {
for(;;) {
avio_seek(s->pb, pos, SEEK_SET);
if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
return AV_NOPTS_VALUE;
if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
parse_pcr(&timestamp, &pcr_l, buf) == 0) {
break;
}
pos += ts->raw_packet_size;
}
} else {
for(;;) {
pos -= ts->raw_packet_size;
if (pos < 0)
return AV_NOPTS_VALUE;
avio_seek(s->pb, pos, SEEK_SET);
if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
return AV_NOPTS_VALUE;
if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
parse_pcr(&timestamp, &pcr_l, buf) == 0) {
break;
}
}
}
*ppos = pos;
return timestamp;
}
#ifdef USE_SYNCPOINT_SEARCH
static int read_seek2(AVFormatContext *s,
int stream_index,
int64_t min_ts,
int64_t target_ts,
int64_t max_ts,
int flags)
{
int64_t pos;
int64_t ts_ret, ts_adj;
int stream_index_gen_search;
AVStream *st;
AVParserState *backup;
backup = ff_store_parser_state(s);
// detect direction of seeking for search purposes
flags |= (target_ts - min_ts > (uint64_t)(max_ts - target_ts)) ?
AVSEEK_FLAG_BACKWARD : 0;
if (flags & AVSEEK_FLAG_BYTE) {
// use position directly, we will search starting from it
pos = target_ts;
} else {
// search for some position with good timestamp match
if (stream_index < 0) {
stream_index_gen_search = av_find_default_stream_index(s);
if (stream_index_gen_search < 0) {
ff_restore_parser_state(s, backup);
return -1;
}
st = s->streams[stream_index_gen_search];
// timestamp for default must be expressed in AV_TIME_BASE units
ts_adj = av_rescale(target_ts,
st->time_base.den,
AV_TIME_BASE * (int64_t)st->time_base.num);
} else {
ts_adj = target_ts;
stream_index_gen_search = stream_index;
}
pos = av_gen_search(s, stream_index_gen_search, ts_adj,
0, INT64_MAX, -1,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE,
flags, &ts_ret, mpegts_get_pcr);
if (pos < 0) {
ff_restore_parser_state(s, backup);
return -1;
}
}
// search for actual matching keyframe/starting position for all streams
if (ff_gen_syncpoint_search(s, stream_index, pos,
min_ts, target_ts, max_ts,
flags) < 0) {
ff_restore_parser_state(s, backup);
return -1;
}
ff_free_parser_state(s, backup);
return 0;
}
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags)
{
int ret;
if (flags & AVSEEK_FLAG_BACKWARD) {
flags &= ~AVSEEK_FLAG_BACKWARD;
ret = read_seek2(s, stream_index, INT64_MIN, target_ts, target_ts, flags);
if (ret < 0)
// for compatibility reasons, seek to the best-fitting timestamp
ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags);
} else {
ret = read_seek2(s, stream_index, target_ts, target_ts, INT64_MAX, flags);
if (ret < 0)
// for compatibility reasons, seek to the best-fitting timestamp
ret = read_seek2(s, stream_index, INT64_MIN, target_ts, INT64_MAX, flags);
}
return ret;
}
#else
static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
MpegTSContext *ts = s->priv_data;
uint8_t buf[TS_PACKET_SIZE];
int64_t pos;
if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
return -1;
pos= avio_tell(s->pb);
for(;;) {
avio_seek(s->pb, pos, SEEK_SET);
if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
return -1;
// pid = AV_RB16(buf + 1) & 0x1fff;
if(buf[1] & 0x40) break;
pos += ts->raw_packet_size;
}
avio_seek(s->pb, pos, SEEK_SET);
return 0;
}
#endif
/**************************************************************/
/* parsing functions - called from other demuxers such as RTP */
MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s)
{
MpegTSContext *ts;
ts = av_mallocz(sizeof(MpegTSContext));
if (!ts)
return NULL;
/* no stream case, currently used by RTP */
ts->raw_packet_size = TS_PACKET_SIZE;
ts->stream = s;
ts->auto_guess = 1;
return ts;
}
/* return the consumed length if a packet was output, or -1 if no
packet is output */
int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
const uint8_t *buf, int len)
{
int len1;
len1 = len;
ts->pkt = pkt;
ts->stop_parse = 0;
for(;;) {
if (ts->stop_parse>0)
break;
if (len < TS_PACKET_SIZE)
return -1;
if (buf[0] != 0x47) {
buf++;
len--;
} else {
handle_packet(ts, buf);
buf += TS_PACKET_SIZE;
len -= TS_PACKET_SIZE;
}
}
return len1 - len;
}
void ff_mpegts_parse_close(MpegTSContext *ts)
{
int i;
for(i=0;i<NB_PID_MAX;i++)
av_free(ts->pids[i]);
av_free(ts);
}
AVInputFormat ff_mpegts_demuxer = {
"mpegts",
NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"),
sizeof(MpegTSContext),
mpegts_probe,
mpegts_read_header,
mpegts_read_packet,
mpegts_read_close,
read_seek,
mpegts_get_pcr,
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
.read_seek2 = read_seek2,
#endif
};
AVInputFormat ff_mpegtsraw_demuxer = {
"mpegtsraw",
NULL_IF_CONFIG_SMALL("MPEG-2 raw transport stream format"),
sizeof(MpegTSContext),
NULL,
mpegts_read_header,
mpegts_raw_read_packet,
mpegts_read_close,
read_seek,
mpegts_get_pcr,
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
.read_seek2 = read_seek2,
#endif
.priv_class = &mpegtsraw_class,
};