[Libav-user] Grabbing packets from avfoundation with reencoding and muxing

Valeriy Shtoma shtomavaleriy at gmail.com
Thu Dec 14 16:49:57 EET 2017


Hi to all guys,

I don’t understand what I do wrong? I saw all examples,
saw headers with API description… Where is my fault?

To begin with this, my code:

#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>

int open_input_device(AVFormatContext **ifmt_ctx, 
					const char* device_name, 
					AVInputFormat **ifmt, 
					AVDictionary *iopt) {
    // Open input video file
    if (avformat_open_input(ifmt_ctx, device_name, *ifmt, &iopt) != 0) {
        printf("%s\n", "Couldn't open input file");
        return -1;
    }
    // Retrieve stream information
    if (avformat_find_stream_info(*ifmt_ctx, NULL) < 0) {
        printf("%s\n", "Couldn't find stream information");
        return -1;
    }
    
    // Dump information about input media onto standard error
    av_dump_format(*ifmt_ctx, 0, device_name, 0);
    
    return 0;
}

int main(void) {
    /* Inputs */
    AVFormatContext *ifmt_ctx = NULL;
    AVInputFormat *ifmt = NULL;
    AVDictionary *iopt = NULL;
    AVDictionary *libx264opt = NULL;
    AVCodec *ivcdc = NULL;
    AVCodecContext *ivcdc_ctx = NULL;
    AVCodec *iacdc = NULL;
    AVCodecContext *iacdc_ctx = NULL;
    AVPacket ipkt;
    
    /* Outputs */
    const char *rtmpUrl = "test.flv";
    AVFormatContext *ofmt_ctx;
    AVOutputFormat *ofmt;
    AVCodec *ovcdc = NULL;
    AVCodecContext *ovcdc_ctx = NULL;
    AVCodec *oacdc = NULL;
    AVCodecContext *oacdc_ctx = NULL;
    AVPacket opkt;
    
    /* Utils */
    int i, ret = -1, vindex = -1, aindex = -1;
    
    av_register_all();
    avformat_network_init();
    avdevice_register_all();
    avcodec_register_all();

    //Grab AVFoundation settings
    ifmt = av_find_input_format("avfoundation");
    av_dict_set(&iopt, "video_size", "1280x720", 0);
    av_dict_set(&iopt, "probesize", "100M", 0);
    av_dict_set(&iopt, "analyzeduration", "100M", 0);

    open_input_device(&ifmt_ctx, "0:1", &ifmt, iopt);

    ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", rtmpUrl);
    if (!ofmt_ctx || ret < 0) {
        printf("%s\n", "Can't allocate the output media context");
        return -1;
    }

    ofmt_ctx->probesize = 100000000;
    ofmt_ctx->max_analyze_duration = 100000000;
    ofmt = ofmt_ctx->oformat;
    ofmt->video_codec = AV_CODEC_ID_H264;
    ofmt->audio_codec = AV_CODEC_ID_MP3;
    ofmt->flags |= AVFMT_GLOBALHEADER;

   for (i = 0; i < ifmt_ctx->nb_streams; i++) {
        if (ifmt_ctx->streams[i]->codecpar->codec_type == 
							AVMEDIA_TYPE_VIDEO) {
            vindex = i;
            ivcdc = avcodec_find_decoder(ifmt_ctx->streams[i]->
								codecpar->codec_id);
            if (!ivcdc) {
                printf("%s\n", "Failed to find decoder for input video stream");
                return -1;
            }
            ivcdc_ctx = avcodec_alloc_context3(ivcdc);
            if (!ivcdc_ctx) {
                printf("%s\n", "Failed to allocate the decoder 
								context for input video stream");
                return -1;
            }
            ret = avcodec_parameters_to_context(ivcdc_ctx, ifmt_ctx->
											streams[i]->codecpar);
            if (ret < 0) {
                printf("%s\n", "Failed to copy decoder parameters 
								to video input decoder context");
                return -1;
            }
            /* Open decoder */
            ret = avcodec_open2(ivcdc_ctx, ivcdc, NULL);
            if (ret < 0) {
                printf("%s\n", "Failed to open decoder for video input stream");
                return -1;
            }
            
            // Output
            ovcdc = avcodec_find_encoder(ofmt->video_codec);
            if (!ovcdc) {
                printf("%s\n", "Failed to find encoder for output video stream");
                return -1;
            }
            ovcdc_ctx = avcodec_alloc_context3(ovcdc);
            if (!ovcdc_ctx) {
                printf("%s\n", "Failed to allocate the encoder context 
			for output video stream");
                return -1;
            }
            ovcdc_ctx->width = 1280;
            ovcdc_ctx->height = 720;
            ovcdc_ctx->coded_width = 1280;
            ovcdc_ctx->coded_height = 720;
            ovcdc_ctx->bit_rate = 2000000;
            ovcdc_ctx->gop_size = 60;
            ovcdc_ctx->pix_fmt = AV_PIX_FMT_YUV422P;
            ovcdc_ctx->time_base = (AVRational){1, 30};
            ovcdc_ctx->framerate = (AVRational){30, 1};
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
                ovcdc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            }
            
            AVStream *ost = avformat_new_stream(ofmt_ctx, ovcdc);
            if (!ost) {
                printf("%s\n", "Failed add new video stream to output");
                return -1;
            }
            ost->id = ofmt_ctx->nb_streams - 1;
            ret = avcodec_parameters_from_context(ost->codecpar, ovcdc_ctx);
            if (ret < 0) {
                printf("%s\n", "Failed to copy video encoder 
						parameters to output video encoder context");
                return -1;
            }
            ost->avg_frame_rate = ovcdc_ctx->framerate;
            ost->r_frame_rate = ovcdc_ctx->framerate;
            ost->time_base = ovcdc_ctx->time_base;

            /* Open encoder */
            av_dict_set(&libx264opt, "profile:v", "high422", 0);
            av_dict_set(&libx264opt, "level", "41", 0);
            av_dict_set(&libx264opt, "preset", "ultrafast", 0);
            av_dict_set(&libx264opt, "tune", "zerolatency", 0);
            av_dict_set(&libx264opt, "crf", "23", 0);
            av_dict_set(&libx264opt, "g", "60", 0);
            av_dict_set(&libx264opt, "maxrate", "2500k", 0);
            av_dict_set(&libx264opt, "bufsize", "2500k", 0);
            
            ret = avcodec_open2(ovcdc_ctx, ovcdc, &libx264opt);
            if (ret < 0) {
                printf("%s\n", "Failed to open encoder for video output stream");
                return -1;
            }
        } else if (ifmt_ctx->streams[i]->codecpar->codec_type
									 == AVMEDIA_TYPE_AUDIO) {
            aindex = i;
            iacdc = avcodec_find_decoder(ifmt_ctx->streams[i]->
										codecpar->codec_id);
            if (!iacdc) {
                printf("%s\n", "Failed to find decoder for input audio stream");
                return -1;
            }
            iacdc_ctx = avcodec_alloc_context3(iacdc);
            if (!iacdc_ctx) {
                printf("%s\n", "Failed to allocate the decoder
								 context for input audio stream");
                return -1;
            }
            ret = avcodec_parameters_to_context(iacdc_ctx, ifmt_ctx->
											streams[i]->codecpar);
            if (ret < 0) {
                printf("%s\n", "Failed to copy decoder parameters 
									to audio input decoder context");
                return -1;
            }
            /* Open decoder */
            ret = avcodec_open2(iacdc_ctx, iacdc, NULL);
            if (ret < 0) {
                printf("%s\n", "Failed to open decoder for audio input stream");
                return -1;
            }
            
            // Output
            oacdc = avcodec_find_encoder(ofmt->audio_codec);
            if (!oacdc) {
                printf("%s\n", "Failed to find encoder for output audio stream");
                return -1;
            }
            oacdc_ctx = avcodec_alloc_context3(oacdc);
            if (!oacdc_ctx) {
                printf("%s\n", "Failed to allocate the encoder context for
									 output audio stream");
                return -1;
            }
            oacdc_ctx->sample_fmt = oacdc->sample_fmts ? 
					oacdc->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
            oacdc_ctx->bit_rate = 192000;
            if (oacdc->supported_samplerates) {
                oacdc_ctx->sample_rate = oacdc->supported_samplerates[0];
                for (int j = 0; oacdc->supported_samplerates[j]; j++) {
                    if (oacdc->supported_samplerates[j] == 44100)
                        oacdc_ctx->sample_rate = 44100;
                }
            }
            oacdc_ctx->channels = av_get_channel_layout_nb_channels(iacdc_ctx->
													channel_layout);
            if (oacdc->channel_layouts) {
                oacdc_ctx->channel_layout = oacdc->channel_layouts[0];
                for (int j = 0; oacdc->channel_layouts[j]; j++) {
                    if (oacdc->channel_layouts[j] == AV_CH_LAYOUT_STEREO)
                        oacdc_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
                }
            }
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
                oacdc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            }
            
            AVStream *ost = avformat_new_stream(ofmt_ctx, oacdc);
            if (!ost) {
                printf("%s\n", "Failed add new audio stream to output");
                return -1;
            }
            ost->id = ofmt_ctx->nb_streams - 1;
            ret = avcodec_parameters_from_context(ost->codecpar, oacdc_ctx);
            if (ret < 0) {
                printf("%s\n", "Failed to copy audio encoder parameters to 
									output audio encoder context");
                return -1;
            }
            ost->time_base = (AVRational){1, oacdc_ctx->sample_rate};
            
            /* Open encoder */
            ret = avcodec_open2(oacdc_ctx, oacdc, NULL);
            if (ret < 0) {
                printf("%s\n", "Failed to open encoder for audio output stream");
                return -1;
            }
        }
    }
    if (vindex == -1 || aindex == -1) {
        printf("%s\n", "Didn't find a video or audio input stream");
        return -1;
    }

    
    /* open the output file, if needed */
    if (!(ofmt_ctx->flags & AVFMT_NOFILE)) {
        ret = avio_open(&ofmt_ctx->pb, rtmpUrl, AVIO_FLAG_WRITE);
        if (ret < 0) {
            printf("Could not open '%s': %s\n", rtmpUrl, av_err2str(ret));
            return -1;
        }
    }
    /* Write the stream header, if any. */
    ret = avformat_write_header(ofmt_ctx, NULL);
    if (ret < 0) {
        printf("Error occurred when opening output file: %s\n", av_err2str(ret));
        return -1;
    }
    
    // Dump information about output media onto standard error
    av_dump_format(ofmt_ctx, 0, rtmpUrl, 1);
    

   // Init frames for streaming loop
    AVFrame *ivframe = av_frame_alloc();
    AVFrame *ovframe_yuv422p = av_frame_alloc();
    ovframe_yuv422p->width = ovcdc_ctx->width;
    ovframe_yuv422p->height = ovcdc_ctx->height;
    ovframe_yuv422p->format = ovcdc_ctx->pix_fmt;
    int numBytes;
    numBytes = av_image_get_buffer_size(ovframe_yuv422p->format, 
				ovframe_yuv422p->width, ovframe_yuv422p->height, 32);
    if (numBytes < 0) {
        printf("%s\n", "Didn't count number of bytes for buffer 
						in process of convertation to yuv422p");
        return -1;
    }
    uint8_t *buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
    ret = av_image_fill_arrays(ovframe_yuv422p->data, ovframe_yuv422p->
						linesize, buffer, ovframe_yuv422p->format,
                               ovframe_yuv422p->width, ovframe_yuv422p->height, 32);
    if (ret < 0) {
        printf("%s\n", "Error occured in av_image_fill_arrays()");
        return -1;
    }
    struct SwsContext *sws_ctx = sws_getContext(ivcdc_ctx->width,
								 ivcdc_ctx->height, ivcdc_ctx->pix_fmt,
                                                ovframe_yuv422p->width, 
						ovframe_yuv422p->height, ovframe_yuv422p->format,
                                                SWS_BILINEAR, NULL, NULL, NULL);
    if (!sws_ctx) {
        printf("%s\n", "Error occured in sws_getContext()");
        return -1;
    }
    
    AVFrame *iaframe = av_frame_alloc();
    AVFrame *oaframe = av_frame_alloc();
    oaframe->format = oacdc_ctx->sample_fmt;
    oaframe->channel_layout = oacdc_ctx->channel_layout;
    oaframe->sample_rate = oacdc_ctx->sample_rate;
    if (oacdc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) {
        oaframe->nb_samples = 10000;
    } else {
        oaframe->nb_samples = oacdc_ctx->frame_size;
    }
    if (oaframe->nb_samples) {
        ret = av_frame_get_buffer(oaframe, 0);
        if (ret < 0) {
            printf("%s\n", "Error allocating an audio buffer");
            return -1;
        }
    }
    struct SwrContext *swr_ctx = swr_alloc();
    if (!swr_ctx) {
        printf("%s\n", "Could not allocate resampler context");
        return -1;
    }
    /* set options */
    av_opt_set_int(swr_ctx, "in_channel_count", iacdc_ctx->channels, 0);
    av_opt_set_int(swr_ctx, "in_sample_rate", iacdc_ctx->sample_rate, 0);
    av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", iacdc_ctx->sample_fmt, 0);
    av_opt_set_int(swr_ctx, "out_channel_count", oacdc_ctx->channels, 0);
    av_opt_set_int(swr_ctx, "out_sample_rate", oacdc_ctx->sample_rate, 0);
    av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", oacdc_ctx->sample_fmt, 0);
    
    /* initialize the resampling context */
    if ((ret = swr_init(swr_ctx)) < 0) {
        printf("%s\n", "Failed to initialize the resampling context");
        return -1;
    }

   while (av_read_frame(ifmt_ctx, &ipkt) >= 0) {
        if (ipkt.stream_index == vindex) {
            ret = avcodec_send_packet(ivcdc_ctx, &ipkt);
            if (ret != 0) {
                printf("%s\n", "Error on send packet to decoder");
                printf("%s\n", av_err2str(ret));
            }
            ret = avcodec_receive_frame(ivcdc_ctx, ivframe);
            if (ret != 0) {
                printf("%s\n", "Error on recieve frame from decoder");
                printf("%s\n", av_err2str(ret));
            }
            
            ovframe_yuv422p->pict_type = ivframe->pict_type;
            ovframe_yuv422p->key_frame = ivframe->key_frame;
            ovframe_yuv422p->pts = ivframe->pts;
            ovframe_yuv422p->pkt_dts = ivframe->pkt_dts;
            ovframe_yuv422p->pts = av_rescale_q(ovframe_yuv422p->
						pts, ifmt_ctx->streams[vindex]->time_base,
                                                ofmt_ctx->streams[vindex]->time_base);
            // change to yuv422p
            sws_scale(sws_ctx, (uint8_t const * const *)ivframe->data, 
					ivframe->linesize, 0, ivcdc_ctx->height,
                      ovframe_yuv422p->data, ovframe_yuv422p->linesize);
            
            // encode to libx264
            ret = avcodec_send_frame(ovcdc_ctx, ovframe_yuv422p);
            if (ret != 0) {
                printf("%s\n", "Error on send frame to encoder");
                printf("%s\n", av_err2str(ret));
            }
            do {
                ret = avcodec_receive_packet(ovcdc_ctx, &opkt);
                if (ret < 0) {
                    if (ret != AVERROR(EAGAIN)) {
                        printf("%s\n", "Error on recieve packet from encoder");
                        printf("%s\n", av_err2str(ret));
                    }
                    break;
                }

                opkt.stream_index = ipkt.stream_index;
                av_packet_rescale_ts(&opkt, ifmt_ctx->streams[vindex]->time_base, 
								ofmt_ctx->streams[vindex]->time_base);
                ret = av_interleaved_write_frame(ofmt_ctx, &opkt);
                if (ret < 0) {
                    printf("%s\n", "Error muxing video packet");
                    break;
                }
            } while (ret >= 0);
        } else if (ipkt.stream_index == aindex) {
            ret = avcodec_send_packet(iacdc_ctx, &ipkt);
            if (ret != 0) {
                printf("%s\n", "Error on send packet to decoder(audio)");
                printf("%s\n", av_err2str(ret));
            }
            ret = avcodec_receive_frame(iacdc_ctx, iaframe);
            if (ret != 0) {
                printf("%s\n", "Error on recieve frame from decoder(audio)");
                printf("%s\n", av_err2str(ret));
            }

            /* convert to destination format */
            ret = swr_convert(swr_ctx, oaframe->data, oaframe->nb_samples, 
									(const uint8_t **)iaframe->data,
                           						   iaframe->nb_samples);
            if (ret < 0) {
                printf("%s\n", "Error while converting audio frame");
                break;
            }
            
            oaframe->pts = iaframe->pts;
            oaframe->pkt_dts = iaframe->pkt_dts;
            oaframe->pts = av_rescale_q(oaframe->pts, 
							ifmt_ctx->streams[aindex]->time_base, 
							ofmt_ctx->streams[aindex]->time_base);
            
            ret = avcodec_send_frame(oacdc_ctx, oaframe);
            if (ret != 0) {
                printf("%s\n", "Error on send frame to encoder");
                printf("%s\n", av_err2str(ret));
            }
            do {
                ret = avcodec_receive_packet(oacdc_ctx, &opkt);
                if (ret < 0) {
                    if (ret != AVERROR(EAGAIN)) {
                        printf("%s\n", "Error on recieve packet from encoder");
                        printf("%s\n", av_err2str(ret));
                    }
                    break;
                }
                
                opkt.stream_index = ipkt.stream_index;
                av_packet_rescale_ts(&opkt, ifmt_ctx->streams[aindex]->time_base, ofmt_ctx->streams[aindex]->time_base);
                ret = av_interleaved_write_frame(ofmt_ctx, &opkt);
                if (ret < 0) {
                    printf("%s\n", "Error muxing audio packet");
                    break;
                }
            } while (ret >= 0);
        }
        
        av_packet_unref(&ipkt);
    }

…
free resources...

I don’t understand why my output file don’t have a keyframe and
video codec info, what’s I do wrong?

So sorry if something is wrong, it’s my first letter to community and 
thanks at all.

Kind Regards,
Valeriy V Shtoma


More information about the Libav-user mailing list