FFMPEG Create output RTMP stream from two RTMP streams C++

I wrote this program that connects to two RTMP streamings that are running in my machine.

Stream 1 has audio and video.

Stream 2 has only video.

My goal is to take audio from streaming 1, and video from streaming 2, and put it on the output stream.

I tried copying stream 2’s codec context and initialized it but i get this output (attached at the end)

Please help!

#include <stdio.h>
#include<iostream>
using namespace std;

extern "C"
{
    #include "libavcodecavcodec.h"
    #include "libavformatavformat.h"
}

int main() {
    const char* filename = "rtmp://localhost/live/STREAM_NAME3.flv";


    // STREAM 1
    AVFormatContext* format_context1 = avformat_alloc_context();
    AVCodecContext* av_codec_ctx1 = NULL;
    AVCodec* av_codec1 = NULL;
    AVPacket packet1;
    AVFrame* frame1;
    int width1 = -1;
    int height1 = -1;
    int video_stream_index1 = -1;
    double time_base1 = -1;


    // STREAM 2
    AVFormatContext* format_context2 = avformat_alloc_context();
    AVCodecContext* av_codec_ctx2 = NULL;
    AVCodec* av_codec2 = NULL;
    AVPacket packet2;
    AVFrame* frame2;
    int width2 = -1;
    int height2 = -1;
    int video_stream_index2 = -1;
    double time_base2 = -1;

    avformat_network_init();

    // Opening Stream 1
    if (avformat_open_input(&format_context1, "rtmp://localhost/live/STREAM_NAME.flv", NULL, NULL) != 0)
    {
        avformat_close_input(&format_context1);
        return 0;
    }

    // Opening Stream 2
    if (avformat_open_input(&format_context2, "rtmp://localhost/live/STREAM_NAME2.flv", NULL, NULL) != 0)
    {
        avformat_close_input(&format_context2);
        return 0;
    }

    // Obtain info from Stream 1
    if (avformat_find_stream_info(format_context1, NULL) < 0)
    {
        avformat_close_input(&format_context1);
        return 0;
    }

    // Obtain info from Stream 2
    if (avformat_find_stream_info(format_context2, NULL) < 0)
    {
        avformat_close_input(&format_context2);
        return 0;
    }

    cout << "CONTEXT 1 NUMBER OF STREAMS DETECTED: " << format_context1->nb_streams << "n";
    cout << "CONTEXT 2 NUMBER OF STREAMS DETECTED: " << format_context2->nb_streams << "n";

    //Width and Height Stream 1
    for (int i = 0; i < format_context1->nb_streams; i++) {
        if (format_context1->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            cout << "AUDIO STREAM INDEX: " << i << "n";
            video_stream_index1 = i;
            width1 = format_context1->streams[i]->codecpar->width;
            height1 = format_context1->streams[i]->codecpar->height;
        }
    }
    //Width and Height Stream 2
    for (int i = 0; i < format_context2->nb_streams; i++) {
        if (format_context2->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            cout << "VIDEO STREAM INDEX: " << i << "n";
            video_stream_index2 = i;
            width2 = format_context2->streams[i]->codecpar->width;
            height2 = format_context2->streams[i]->codecpar->height;
        }
    }

    cout << "START TIME STREAM 1:" << format_context1->start_time << "n";
    cout << "START TIME STREAM 2:" << format_context2->start_time  << "n";

    time_base1 = av_q2d(format_context1->streams[video_stream_index1]->time_base);
    time_base2 = av_q2d(format_context2->streams[video_stream_index2]->time_base);

    cout << "TIME BASE STREAM 1:" << time_base1 << "n";
    cout << "TIME BASE STREAM 2:" << time_base2 << "n";

    av_codec1 = avcodec_find_decoder(format_context1->streams[video_stream_index1]->codecpar->codec_id);
    av_codec_ctx1 = avcodec_alloc_context3(av_codec1);

    av_codec2 = avcodec_find_decoder(format_context2->streams[video_stream_index2]->codecpar->codec_id);
    av_codec_ctx2 = avcodec_alloc_context3(av_codec2);

    //////// OUTPUT STREAM START///////
    AVOutputFormat* ofmt = NULL;
    AVFormatContext* ifmt_ctx = NULL, * ofmt_ctx = NULL;
    AVPacket pkt;
    AVFrame* pFrame = NULL;
    AVFrame* pFrameRGB = NULL;
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();
    int ret;

    AVCodec* out_codec = NULL;
    AVCodecContext* o_avctx = NULL;

    int o_video_stream_index = -1;

    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
    AVStream* out_stream = avformat_new_stream(ofmt_ctx, av_codec2);


    out_codec = avcodec_find_encoder(format_context2->streams[video_stream_index2]->codecpar->codec_id);
    o_avctx = avcodec_alloc_context3(out_codec);

    o_avctx->height = height2;
    o_avctx->width = width2;
    o_avctx->sample_aspect_ratio = format_context2->streams[video_stream_index2]->codecpar->sample_aspect_ratio;
    o_avctx->pix_fmt = out_codec->pix_fmts[0];
    o_avctx->time_base = format_context2->streams[video_stream_index2]->time_base;
    ofmt = ofmt_ctx->oformat;
    avcodec_parameters_from_context(ofmt_ctx->streams[0]->codecpar, av_codec_ctx2);

    av_dump_format(ofmt_ctx, 0, filename, 1);
    char errorBuff[80];
    if (!(ofmt->flags & AVFMT_NOFILE)) {

        ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            fprintf(stderr, "Could not open outfile '%s': %s", filename, av_make_error_string(errorBuff, 80, ret));
            return 1;
        }
    }
    avcodec_open2(o_avctx, out_codec, NULL);
    avformat_write_header(ofmt_ctx, NULL);
    
    ///// OUTPUT STREAM END ////////


    while (true) {
        if (av_read_frame(format_context1, &packet1) >= 0) {
            if (packet1.stream_index == video_stream_index1) {
                //TODO: write packets
            }
        }   

        if (av_read_frame(format_context2, &packet2) >= 0) {
            if (packet2.stream_index == video_stream_index2) {
                //TODO: write packets
            }
        }
    }
    return 0;
}

Output:

CONTEXT 1 NUMBER OF STREAMS DETECTED: 3
CONTEXT 2 NUMBER OF STREAMS DETECTED: 2
AUDIO STREAM INDEX: 1
VIDEO STREAM INDEX: 1
START TIME STREAM 1:7083492000
START TIME STREAM 2:4390018000
TIME BASE STREAM 1:0.001
TIME BASE STREAM 2:0.001
Output #0, flv, to 'rtmp://localhost/live/STREAM_NAME3.flv':
    Stream #0:0: Video: h264, none, q=2-31, 200 kb/s
[h264_mf @ 0000019BF6342C80] MFT name: 'H264 Encoder MFT'
[h264_mf @ 0000019BF6342C80] could not set output type (80004005)
[flv @ 0000019BF5F3A540] dimensions not set

I also set up a node media server to see my streams, it detects the output stream, but looks like it has no codecs
enter image description here

Source: Windows Questions C++

LEAVE A COMMENT