c++ffmpeglibavblackmagic-designdecklink

Why the source order matters on working with multiple media sources in a single AVFormatContext?


avformat_open_input() deletes the AVFormatContext* and returns -6 when the source order changes.

I am trying to open multiple media sources dynamically with different(mixed) formats and codecs in a single context (AVFormatContext).

My media sources are a BlackMagic DeckLink Duo SDI input as first source and an mp4 file or rtsp stream as second.

When I order to open (avformat_open_input()) the source 2 (RTSP or MP4 file) at first and then open the BlackMagic DeckLink Duo, proceed as expected.

But when I change the order, and first open the DeckLink and then try to open RTSP stream or MP4 file, as I inspected in the step debugger; AVFormatContext* deleting in the av_open_input() function and it returns -6 as result.

Please find the simple error reproduction code snappet below;

AVFormatContext* context{avformat_alloc_context()};
const char* url_source1{"DeckLink Duo (1)"};
const AVInputFormat* format_source1{av_find_input_format("decklink")};

const char* url_source2{"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"};

// Open the first media input
int result = avformat_open_input(&context, url_source1, format_source1, NULL);

if(result < 0) {
  exit(1);
}

// Open the second media input
// This function in current order deletes the context and returns -6
result = avformat_open_input(&context, url_source2, NULL, NULL);
if(result < 0) {
  exit(1);
}

// Since the context has been deleted in previous step, segmentation fault accours here!
result = avformat_find_stream_info(context, NULL);
if(result < 0) {
  exit(1);
}

std::cout << "Total number of streams: " << context->nb_streams << std::endl;

But When I change the order and call the avformat_open_input() first for the mp4 file and then the DeckLink device as following it proceed as expected, no error.

AVFormatContext* context{avformat_alloc_context()};
const char* url_source1{"DeckLink Duo (1)"};
const AVInputFormat* format_source1{av_find_input_format("decklink")};

const char* url_source2{"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"};


// Open the second media input
int result = avformat_open_input(&context, url_source2, NULL, NULL);
if(result < 0) {
  exit(1);
}


// Open the first media input
result = avformat_open_input(&context, url_source1, format_source1, NULL);

if(result < 0) {
  exit(1);
}


result = avformat_find_stream_info(context, NULL);
if(result < 0) {
  exit(1);
}

std::cout << "Total number of streams: " << context->nb_streams << std::endl;


Solution

  • It is clearly mentioned on the FFmpeg API avformat_open_input() will free the user-supplied context in case of failure:

    ps (the first parameter) is a pointer to the user-supplied AVFormatContext (allocated by
    avformat_alloc_context) may be a pointer to NULL, in which case an AVFormatContext is
    allocated by this function and written into ps. Note that a user-supplied AVFormatContext
    will be freed on failure.
    

    Implement on your error handler an av_strerror to get human-readable error information. It will help.