vendredi 23 janvier 2015

ffmpeg: all concatenation methods don't lead to a correct file

As I used recently ffmpeg to concatente some really huge video files coming from a CamCorder, I discovered that even if they looks really similar the "Concat protocol" and "Concat demuxer"describe in "Concatenating media files" didn't lead to the same result and that the "Concat demuxer" approach introduced some weird PTS (presentation time stamp) at files boundaries.


As I spend several hour comparing the different way to do that, I can now recommend to use one of those 2 simple methods if you have to concatenate files with the following properties:
  • if they use the same container and codecs
  • if they are consecutive in a way their PTS should not have discontinuities

copy /B 1.MTS+2.MTS out.MTS

or

ffmpeg -i "concat:1.MTS|2.MTS" -an -vcodec copy out.ts
 It should be fast and it should not introduce weird PTS between 1 and 2 !

Observed with:

ffmpeg version N-68482-g92a596f Copyright (c) 2000-2014 the FFmpeg developers
  built on Dec 16 2014 02:53:08 with gcc 4.9.2 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libblu
ray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrw
b --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --
enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-decklink --enable-zlib
  libavutil      54. 15.100 / 54. 15.100
  libavcodec     56. 15.100 / 56. 15.100
  libavformat    56. 15.105 / 56. 15.105
  libavdevice    56.  3.100 / 56.  3.100
  libavfilter     5.  3.101 /  5.  3.101
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100

CMAKE script retro-compatibility

Hi,

I didn't post anything for a while, but in since few days, I found several topic for which I would like to write something (It's like a reminder for me ...)

I worked on product that we build on several different linux platform (Centos/Ubuntu/ etc ...). We use cmake and someone updated a script in a way it couldn't work anymore with older version of cmake (prior to 2.8.3). As I implemented a work-around, I wanted to share it because it was an annoying issue.

In cmake v2.8.3, a new "Useful variable" was introduced CMAKE_CURRENT_LIST_DIR.
If you had to use a cmake script in which that variable is used, cmake will not complain, it will just consider the variable as empty.

The work-around use the other function of cmake to initialize that value and let the rest of your script unchanged.

if("${CMAKE_CURRENT_LIST_DIR}" STREQUAL "")
message(STATUS "work-around to get the current folder for cmake version prior to 2.8.3")
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
endif()


It's quit simple, first I test if the value is empty, and if it's true I use get_filename_component cmake command to extract the current folder path from the CMAKE_CURRENT_LIST_FILE cmake variable.


lundi 5 janvier 2015

C++ STL copy and lvalue

 

A common mistake when using STL object and algorithm is to assume implementation details. For example when we use the ostringstream class, it may be easy to assume that the object contain a string member and that the str() function must return that data. If we just think like that and don’t look deeper at the str() function declaration, we can write the following code and suppose that the output will be correct.

std::ostringstream os; os << 1234 << std::endl;

std::copy(os.str().begin(), os.str().end(), std::back_inserter(outputContainer));

But it will not be correct and you cannot rely on the compiler to detect the issue because the syntax is correct. We pass 2 iterator on a string, but the issue is that they are not iterator on the ‘same’ string.

The function declaration of str() is:

string str() const;
and it means 2 things:


  1. the ostringstream object will not be modified by the call

  2. the returned string object is an lvalue (return by copy).

you can also read that post in which that trap is fully detailed….


But to summarize, every call to str() return a different string so the the begin and end iterator we provided in the previous piece of code aren’t related to the same string.


The only correct way to manage that situation is to create a copy of the string like below or to use your own ostringstream version like describe in that post.


 


std::ostringstream os; os << 1234 << std::endl;


std::string acpy = os.str();


std::copy(acpy.begin(), acpy.end(), std::back_inserter(outputContainer));


The conclusion is that when you use a STL object or an algorithm take attention at the declaration because if you don’t you may fall in some traps.