[Libav-user] Retrieve all raw Mpeg2-TS packets from FFmpeg

Elliott, Bruce belliott at kuttatech.com
Fri Sep 7 19:11:28 EEST 2018


I am a newbie to this site. Please let me know if I am sending too much/little
info about my question.

I am using FFmpeg to write a video player/recorder for a customer. The customer
has a legacy video camera system that sends an Mpeg2_TS stream over unicast
UDP. The Mpeg2-TS stream contains three PES streams, an H264 video stream,
a private meta data stream and a stream containing high resolution still image
captures. The PID for the video and private meta data streams are defined
in the PMT but the high resolution still image captures are not. The PID for
all Mpeg2-TS packets in the stream are predefined by the legacy camera system
creating the Mpeg2-TS stream. All data in the received Mpeg2-ts stream is to be
recorded as it is received and also decoded and displayed.

I am trying to use the AVIOContext that is a member of the AVFormatContext
created from the avformat_open_input() call to redirect the calls to the
functions that are members of the AVIOContext to my local implementations
of those functions. This may be somewhat naive but I was hoping to use the
opaque parameter set to my class's this pointer in the local implementations.
Here are some relevant excerpts of the code:

   avformat_open_input( &m_pFmt_ctx, m_Src_filename, NULL, &options );
   // Hijack the AVIOContext from the AVFormatContext returned from opening
   // the URL and use it to redirect the read function to our private read
   // function.
   // 1. First save off the pointers to the original functions
   //   (they will be called by the local functions)
   AVIOContext *pb = m_pFmt_ctx->pb;
   m_pOpaque = pb->opaque;
   m_pRead_packet     = pb->read_packet;
   m_pWrite_packet    = pb->write_packet;
   m_pSeek                      = pb->seek;
   m_pRead_pause       = pb->read_pause;
   m_pRead_seek          = pb->read_seek;
   m_pWrite_data_type = pb->write_data_type;
   m_pShort_seek_get  = pb->short_seek_get;
   // 2. Set the pointers to the local functions
   pb->opaque = (void*)this;
   if (m_pRead_packet != NULL)
      pb->read_packet = lcl_read_packet;
   if (m_pWrite_packet != NULL)
      pb->write_packet = lcl_write_packet;
   if (m_pSeek != NULL)
      pb->seek = lcl_seek;
   if (m_pRead_pause != NULL)
      pb->read_pause = lcl_read_pause;
   if (m_pRead_seek != NULL)
      pb->read_seek = lcl_read_seek;
   if (m_pWrite_data_type != NULL)
      pb->write_data_type = lcl_write_data_type;
   if (m_pShort_seek_get != NULL)
      pb->short_seek_get = lcl_short_seek_get;

   while(!m_bStopStrmPktRdThrd)
   {
      /* read frames from the file */
      if (av_read_frame( m_pFmt_ctx, &m_pkt ) >= 0)
      {
         .. . do stuff

int lcl_read_packet(void *opaque, uint8_t *buf, int buf_size)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   int retVal = This->m_pRead_packet(This->m_pOpaque, buf, buf_size);
   // If recording, write packet out to video file.
   if (retVal > 0)
   {
      std::lock_guard<std::mutex> lock( This->m_VideoFileMtx );
      if ((This->m_bRecording == true) && (This->m_VideoFile != NULL))
      {
         fwrite( buf, retVal, 1, This->m_VideoFile );
      }
      // Also need to check the PID and look for packets that are
      // part of the high resolution still image capture.
   }
   return retVal;
}

int lcl_write_packet(void *opaque, uint8_t *buf, int buf_size)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   return This->m_pWrite_packet(This->m_pOpaque, buf, buf_size);
}

int64_t lcl_seek(void *opaque, int64_t offset, int whence)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   return This->m_pSeek(This->m_pOpaque, offset, whence);
}

int lcl_read_pause(void *opaque, int pause)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   return This->m_pRead_pause(This->m_pOpaque, pause);
}

int64_t lcl_read_seek(void *opaque, int stream_index, int64_t timestamp, int flags)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   return This->m_pRead_seek(This->m_pOpaque, stream_index, timestamp, flags);
}

int lcl_write_data_type(void *opaque, uint8_t *buf, int buf_size, enum AVIODataMarkerType type, int64_t time)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   return This->m_pWrite_data_type(This->m_pOpaque, buf, buf_size, type, time);
}

int lcl_short_seek_get(void *opaque)
{
   FFmpegUtil* This = static_cast<FFmpegUtil*>(opaque);
   return This->m_pShort_seek_get(This->m_pOpaque);
}

This causes the application to SegFault and the gdb backtrace is:

(gdb) bt
#0  0x000003be00073f3a in  ()
#1  0x00007f861eea8b0c in av_opt_find2 () at /usr/local/lib/libavutil.so.56
#2  0x00007f861eea8af8 in av_opt_find2 () at /usr/local/lib/libavutil.so.56
#3  0x00007f861eea8af8 in av_opt_find2 () at /usr/local/lib/libavutil.so.56
#4  0x00007f861eea9969 in av_opt_get_dict_val () at /usr/local/lib/libavutil.so.56
#5  0x00007f861ebc6847 in  () at /usr/local/lib/libavformat.so.58
#6  0x00007f861ebc6f13 in av_read_frame () at /usr/local/lib/libavformat.so.58
#7  0x00007f86066b943b in FFmpegUtil::StreamPktRdThrd() (this=0x7f859800f0e8) at FFmpegUtil.cpp:414

The simple work around for this is to not change the value of opaque in the
AVIOContext of AVFormatContext. But then the code is less clean because the this
pointer for the class is a static variable set by a single instance of the class
instead of being passed in as the opaque parameter.

Is there a better way to get the raw Mpeg2-TS stream packets from FFmpeg?

Below is the information about the system environment if needed:

My application will run on Centos 7 and below is the information about the
FFmpeg build I am using (custom build):

[toga-ops at localhost out]$ ffmpeg -version
ffmpeg version 4.0.2 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-28)
configuration: --prefix=/home/toga-ops/ffmpeg_build
               --pkg-config-flags=--static
               --extra-cflags='-fPIC
               -m64
               -I/home/toga-ops/ffmpeg_build/include'
               --extra-ldflags=-L/home/toga-ops/ffmpeg_build/lib
               --extra-libs=-lpthread
               --extra-libs=-ldl
               --bindir=/home/toga-ops/bin
               --enable-gpl
               --enable-libfdk_aac
               --enable-libfreetype
               --enable-libmp3lame
               --enable-libopus
               --enable-libvorbis
               --enable-libtheora
               --enable-vaapi
               --enable-libvpx
               --enable-libx264
               --enable-hwaccel=h264
               --enable-nonfree
               --enable-pic
               --extra-ldexeflags=-pie
               --enable-shared
libavutil      56. 14.100 / 56. 14.100
libavcodec     58. 18.100 / 58. 18.100
libavformat    58. 12.100 / 58. 12.100
libavdevice    58.  3.100 / 58.  3.100
libavfilter     7. 16.100 /  7. 16.100
libswscale      5.  1.100 /  5.  1.100
libswresample   3.  1.100 /  3.  1.100
libpostproc    55.  1.100 / 55.  1.100
[toga-ops at localhost out]$ vainfo
libva info: VA-API version 0.40.0
libva info: va_getDriverName() returns 0
libva info: Trying to open /usr/lib64/dri/i965_drv_video.so
libva info: Found init function __vaDriverInit_0_40
libva info: va_openDriver() returns 0
vainfo: VA-API version: 0.40 (libva )
vainfo: Driver version: Intel i965 driver for Intel(R) Haswell Mobile - 1.8.3
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Simple            :	VAEntrypointEncSlice
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointEncSlice
      VAProfileH264ConstrainedBaseline:	VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:	VAEntrypointEncSlice
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointEncSlice
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointEncSlice
      VAProfileH264MultiviewHigh      :	VAEntrypointVLD
      VAProfileH264MultiviewHigh      :	VAEntrypointEncSlice
      VAProfileH264StereoHigh         :	VAEntrypointVLD
      VAProfileH264StereoHigh         :	VAEntrypointEncSlice
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD
      VAProfileNone                   :	VAEntrypointVideoProc
      VAProfileJPEGBaseline           :	VAEntrypointVLD
      VAProfileVP9Profile0            :	VAEntrypointVLD
[toga-ops at localhost out]$ 

The application tells me the following information about the OpenGL environment
and the contents of the Mpeg2-TS stream:


OpenGl information: VENDOR:       Intel Open Source Technology Center
                    RENDERDER:    Mesa DRI Intel(R) Haswell Mobile 
                    VERSION:      3.0 Mesa 11.2.2
                    GLSL VERSION: 1.30

Stream[ 0]  PID:0x0011,
            Type:     Video,
            CodecID:  h264(       H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10),
            CodecTag: [27][0][0][0]
Stream[ 1]  PID:0x0021,
            Type:      Data,
            CodecID:   bin_data(                                binary data),
            CodecTag:  [6][0][0][0]

Regards,
B Elliott



More information about the Libav-user mailing list