Advanced search

Medias (0)

Tag: - Tags -/organisation

No media matches your criterion on the site.

Other articles (18)

  • Que fait exactement ce script ?

    18 January 2011, by

    Ce script est écrit en bash. Il est donc facilement utilisable sur n’importe quel serveur.
    Il n’est compatible qu’avec une liste de distributions précises (voir Liste des distributions compatibles).
    Installation de dépendances de MediaSPIP
    Son rôle principal est d’installer l’ensemble des dépendances logicielles nécessaires coté serveur à savoir :
    Les outils de base pour pouvoir installer le reste des dépendances Les outils de développements : build-essential (via APT depuis les dépôts officiels); (...)

  • Encodage et transformation en formats lisibles sur Internet

    10 April 2011

    MediaSPIP transforme et ré-encode les documents mis en ligne afin de les rendre lisibles sur Internet et automatiquement utilisables sans intervention du créateur de contenu.
    Les vidéos sont automatiquement encodées dans les formats supportés par HTML5 : MP4, Ogv et WebM. La version "MP4" est également utilisée pour le lecteur flash de secours nécessaire aux anciens navigateurs.
    Les documents audios sont également ré-encodés dans les deux formats utilisables par HTML5 :MP3 et Ogg. La version "MP3" (...)

  • Automated installation script of MediaSPIP

    25 April 2011, by

    To overcome the difficulties mainly due to the installation of server side software dependencies, an "all-in-one" installation script written in bash was created to facilitate this step on a server with a compatible Linux distribution.
    You must have access to your server via SSH and a root account to use it, which will install the dependencies. Contact your provider if you do not have that.
    The documentation of the use of this installation script is available here.
    The code of this (...)

On other websites (5112)

  • ffmpeg record screen and save video file to disk as .mpg

    7 January 2015, by musimbate

    I want to record the screen of my pc (using gdigrab on my windows machine) and store the saved video file on my disk as an mp4 or mpg file .I have found an example piece of code that grabs the screen and shows it in an SDL window here :http://xwk.iteye.com/blog/2125720 (The code is on the bottom of the page and has an english version) and the ffmpeg muxing example https://ffmpeg.org/doxygen/trunk/muxing_8c-source.html seems to be able to help encode audio and video into a desired output video file.

    I have tried to combine these two by having a format context for grabbing the screen (AVFormatContext *pFormatCtx; in my code ) and a separate format context to write the desired video file (AVFormatContext *outFormatContextEncoded;).Within the loop to read packets from the input stream( screen grab stream) I directly encode write packets to the output file as shown in my code.I have kept the SDL code so I can see what I am recording.Below is my code with my modified write_video_frame() function .

    The code builds OK but the output video can’t be played by vlc. When I run the command

    ffmpeg -i filename.mpg

    I get this output

    [mpeg @ 003fed20] probed stream 0 failed
    [mpeg @ 003fed20] Stream #0: not enough frames to estimate rate; consider increasing probesize
    [mpeg @ 003fed20] Could not find codec parameters for stream 0 (Video: none): unknown codec
    Consider increasing the value for the 'analyzeduration' and 'probesize' options
    karamage.mpg: could not find codec parameters
    Input #0, mpeg, from 'karamage.mpg':
     Duration: 19:30:09.25, start: 37545.438756, bitrate: 2 kb/s
       Stream #0:0[0x1e0]: Video: none, 90k tbr, 90k tbn
    At least one output file must be specified

    Am I doing something wrong here? I am new to ffmpeg and any guidance on this is highly appreciated.Thank you for your time.

    int main(int argc, char* argv[])
    {

       AVFormatContext *pFormatCtx;

       int             i, videoindex;
       AVCodecContext  *pCodecCtx;
       AVCodec         *pCodec;

       av_register_all();
       avformat_network_init();

       //Localy defined structure.
       OutputStream outVideoStream = { 0 };

       const char *filename;
       AVOutputFormat *outFormatEncoded;
       AVFormatContext *outFormatContextEncoded;
       AVCodec *videoCodec;

       filename="karamage.mpg";

       int ret1;

       int have_video = 0, have_audio = 0;
       int encode_video = 0, encode_audio = 0;


       AVDictionary *opt = NULL;



       //ASSIGN STH TO THE FORMAT CONTEXT.
       pFormatCtx = avformat_alloc_context();

       //
       //Use this when opening a local file.
       //char filepath[]="src01_480x272_22.h265";
       //avformat_open_input(&pFormatCtx,filepath,NULL,NULL)

       //Register Device
       avdevice_register_all();

       //Use gdigrab
       AVDictionary* options = NULL;
       //Set some options
       //grabbing frame rate
       //av_dict_set(&options,"framerate","5",0);
       //The distance from the left edge of the screen or desktop
       //av_dict_set(&options,"offset_x","20",0);
       //The distance from the top edge of the screen or desktop
       //av_dict_set(&options,"offset_y","40",0);
       //Video frame size. The default is to capture the full screen
       //av_dict_set(&options,"video_size","640x480",0);
       AVInputFormat *ifmt=av_find_input_format("gdigrab");
       if(avformat_open_input(&pFormatCtx,"desktop",ifmt,&options)!=0){
           printf("Couldn't open input stream.\n");
           return -1;
       }

       if(avformat_find_stream_info(pFormatCtx,NULL)<0)
       {
           printf("Couldn't find stream information.\n");
           return -1;
       }
       videoindex=-1;
       for(i=0; inb_streams; i++)
           if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
           {
               videoindex=i;
               break;
           }
       if(videoindex==-1)
       {
           printf("Didn't find a video stream.\n");
           return -1;
       }
       pCodecCtx=pFormatCtx->streams[videoindex]->codec;
       pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
       if(pCodec==NULL)
       {
           printf("Codec not found.\n");
           return -1;
       }
       if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
       {
           printf("Could not open codec.\n");
           return -1;
       }


       AVFrame *pFrame,*pFrameYUV;
       pFrame=avcodec_alloc_frame();
       pFrameYUV=avcodec_alloc_frame();

       //PIX_FMT_YUV420P WHAT DOES THIS SAY ABOUT THE FORMAT??
       uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));


       avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

       //<<<<<<<<<<<-------PREP WORK TO WRITE ENCODED VIDEO FILES-----

       avformat_alloc_output_context2(&outFormatContextEncoded, NULL, NULL, filename);
       if (!outFormatContextEncoded) {
           printf("Could not deduce output format from file extension: using MPEG.\n");
           avformat_alloc_output_context2(&outFormatContextEncoded, NULL, "mpeg", filename);
       }
       if (!outFormatContextEncoded)
           return 1;

       outFormatEncoded=outFormatContextEncoded->oformat;


        //THIS CREATES THE STREAMS(AUDIO AND VIDEO) ADDED TO OUR OUTPUT STREAM

       if (outFormatEncoded->video_codec != AV_CODEC_ID_NONE) {

           //YOUR VIDEO AND AUDIO PROPS ARE SET HERE.
           add_stream(&outVideoStream, outFormatContextEncoded, &videoCodec, outFormatEncoded->video_codec);
           have_video = 1;
           encode_video = 1;
       }


        // Now that all the parameters are set, we can open the audio and
        // video codecs and allocate the necessary encode buffers.
       if (have_video)
           open_video(outFormatContextEncoded, videoCodec, &outVideoStream, opt);

        av_dump_format(outFormatContextEncoded, 0, filename, 1);


         /* open the output file, if needed */
       if (!(outFormatEncoded->flags & AVFMT_NOFILE)) {
           ret1 = avio_open(&outFormatContextEncoded->pb, filename, AVIO_FLAG_WRITE);
           if (ret1 < 0) {
               //fprintf(stderr, "Could not open '%s': %s\n", filename,
               //        av_err2str(ret));
               fprintf(stderr, "Could not open your dumb file.\n");
               return 1;
           }
       }


       /* Write the stream header, if any. */
       ret1 = avformat_write_header(outFormatContextEncoded, &opt);
       if (ret1 < 0) {
           //fprintf(stderr, "Error occurred when opening output file: %s\n",
            //       av_err2str(ret));
           fprintf(stderr, "Error occurred when opening output file\n");
           return 1;
       }


       //<<<<<<<<<<<-------PREP WORK TO WRITE ENCODED VIDEO FILES-----

       //SDL----------------------------
       if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
           printf( "Could not initialize SDL - %s\n", SDL_GetError());
           return -1;
       }
       int screen_w=640,screen_h=360;
       const SDL_VideoInfo *vi = SDL_GetVideoInfo();
       //Half of the Desktop's width and height.
       screen_w = vi->current_w/2;
       screen_h = vi->current_h/2;
       SDL_Surface *screen;
       screen = SDL_SetVideoMode(screen_w, screen_h, 0,0);

       if(!screen) {  
           printf("SDL: could not set video mode - exiting:%s\n",SDL_GetError());  
           return -1;
       }
       SDL_Overlay *bmp;
       bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen);
       SDL_Rect rect;
       //SDL End------------------------
       int ret, got_picture;

       AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));

       //TRY TO INIT THE PACKET HERE
        av_init_packet(packet);


       //Output Information-----------------------------
       printf("File Information---------------------\n");
       av_dump_format(pFormatCtx,0,NULL,0);
       printf("-------------------------------------------------\n");

       struct SwsContext *img_convert_ctx;
       img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
       //------------------------------
       //
       while(av_read_frame(pFormatCtx, packet)>=0)
       {

           if(packet->stream_index==videoindex)
           {
               //HERE WE DECODE THE PACKET INTO THE FRAME
               ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
               if(ret < 0)
               {
                   printf("Decode Error.\n");
                   return -1;
               }
               if(got_picture)
               {

                   //THIS IS WHERE WE DO STH WITH THE FRAME WE JUST GOT FROM THE STREAM
                   //FREE AREA--START
                   //IN HERE YOU CAN WORK WITH THE FRAME OF THE PACKET.
                   write_video_frame(outFormatContextEncoded, &outVideoStream,packet);


                   //FREE AREA--END
                   sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);


                   SDL_LockYUVOverlay(bmp);
                   bmp->pixels[0]=pFrameYUV->data[0];
                   bmp->pixels[2]=pFrameYUV->data[1];
                   bmp->pixels[1]=pFrameYUV->data[2];    
                   bmp->pitches[0]=pFrameYUV->linesize[0];
                   bmp->pitches[2]=pFrameYUV->linesize[1];  
                   bmp->pitches[1]=pFrameYUV->linesize[2];
                   SDL_UnlockYUVOverlay(bmp);
                   rect.x = 0;    
                   rect.y = 0;    
                   rect.w = screen_w;    
                   rect.h = screen_h;  
                   SDL_DisplayYUVOverlay(bmp, &rect);
                   //Delay 40ms----WHY THIS DELAY????
                   SDL_Delay(40);
               }
           }
           av_free_packet(packet);
       }//THE LOOP TO PULL PACKETS FROM THE FORMAT CONTEXT ENDS HERE.

       //AFTER THE WHILE LOOP WE DO SOME CLEANING

       //av_read_pause(context);


        av_write_trailer(outFormatContextEncoded);
        close_stream(outFormatContextEncoded, &outVideoStream);
        if (!(outFormatContextEncoded->flags & AVFMT_NOFILE))
           /* Close the output file. */
           avio_close(outFormatContextEncoded->pb);

       /* free the stream */
       avformat_free_context(outFormatContextEncoded);



       //STOP DOING YOUR CLEANING
       sws_freeContext(img_convert_ctx);



       SDL_Quit();

       av_free(out_buffer);
       av_free(pFrameYUV);
       avcodec_close(pCodecCtx);
       avformat_close_input(&pFormatCtx);

       return 0;
    }



    /*
    * encode one video frame and send it to the muxer
    * return 1 when encoding is finished, 0 otherwise
    */
    static int write_video_frame(AVFormatContext *oc, OutputStream *ost,AVPacket * pkt11)
    {
       int ret;
       AVCodecContext *c;
       AVFrame *frame;
       int got_packet = 0;

       c = ost->st->codec;

       //DO NOT NEED THIS FRAME.
       //frame = get_video_frame(ost);

       if (oc->oformat->flags & AVFMT_RAWPICTURE) {

           //IGNORE THIS FOR A MOMENT
           /* a hack to avoid data copy with some raw video muxers */
           AVPacket pkt;
           av_init_packet(&pkt);

           if (!frame)
               return 1;

           pkt.flags        |= AV_PKT_FLAG_KEY;
           pkt.stream_index  = ost->st->index;
           pkt.data          = (uint8_t *)frame;
           pkt.size          = sizeof(AVPicture);

           pkt.pts = pkt.dts = frame->pts;
           av_packet_rescale_ts(&pkt, c->time_base, ost->st->time_base);

           ret = av_interleaved_write_frame(oc, &pkt);
       } else {

               ret = write_frame(oc, &c->time_base, ost->st, pkt11);

       }

       if (ret < 0) {
           fprintf(stderr, "Error while writing video frame: %s\n");
           exit(1);
       }


       return 1;
    }
  • Problems with outputting stream format as RTMP

    27 November 2023, by dongrixinyu

    I am using FFmpeg's C API to push video streams rtmp://.... into an SRS server.
    
The input stream is an MP4 file named juren-30s.mp4.
    
The output stream is also an MP4 file named juren-30s-5.mp4.

    


    My piece of code (see further down) works fine when used in the following steps:
    
mp4 -> demux -> decode -> rgb images -> encode -> mux -> mp4.

    


    Problem:

    


    When I changed the output stream to an online RTMP url named rtmp://ip:port/live/stream_nb_23 (just an example, you can change it according to your server and rules.)

    


    result: This code would be corrupted mp4 -> rtmp(flv).

    


    What I've tried:

    


    Changing the output format
    
I changed the output format param to become flv when I initialized the avformat_alloc_output_context2. But this didn't help.

    


    Debugging the output
    
When I executed ffprobe rtmp://ip:port/live/xxxxxxx, I got the following errors and did not know why:

    


    [h264 @ 0x55a925e3ba80] luma_log2_weight_denom 12 is out of range
[h264 @ 0x55a925e3ba80] Missing reference picture, default is 2
[h264 @ 0x55a925e3ba80] concealing 8003 DC, 8003 AC, 8003 MV errors in P frame
[h264 @ 0x55a925e3ba80] QP 4294966938 out of range
[h264 @ 0x55a925e3ba80] decode_slice_header error
[h264 @ 0x55a925e3ba80] no frame!
[h264 @ 0x55a925e3ba80] luma_log2_weight_denom 21 is out of range
[h264 @ 0x55a925e3ba80] luma_log2_weight_denom 10 is out of range
[h264 @ 0x55a925e3ba80] chroma_log2_weight_denom 12 is out of range
[h264 @ 0x55a925e3ba80] Missing reference picture, default is 0
[h264 @ 0x55a925e3ba80] decode_slice_header error
[h264 @ 0x55a925e3ba80] QP 4294967066 out of range
[h264 @ 0x55a925e3ba80] decode_slice_header error
[h264 @ 0x55a925e3ba80] no frame!
[h264 @ 0x55a925e3ba80] QP 341 out of range
[h264 @ 0x55a925e3ba80] decode_slice_header error


    


    I am confused about the difference between MP4 and RTMP of how to use FFmpeg C-API to produce a correct output stream format.

    


    Besides, I also wanna learn how to convert video and audio streams into other formats using FFmpeg C-api, such as flv, ts, rtsp, etc.

    


    Code to reproduce the problem:

    


    


    So how to make this code output to RTMP without getting issue of an unplayable video?

    


    #include 
#include "libavformat/avformat.h"
int main()
{
    int ret = 0; int err;

    //Open input file
    char filename[] = "juren-30s.mp4";
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    if (!fmt_ctx) {
        printf("error code %d \n",AVERROR(ENOMEM));
        return ENOMEM;
    }
    if((err = avformat_open_input(&fmt_ctx, filename,NULL,NULL)) < 0){
        printf("can not open file %d \n",err);
        return err;
    }

    //Open the decoder
    AVCodecContext *avctx = avcodec_alloc_context3(NULL);
    ret = avcodec_parameters_to_context(avctx, fmt_ctx->streams[0]->codecpar);
    if (ret < 0){
        printf("error code %d \n",ret);
        return ret;
    }
    AVCodec *codec = avcodec_find_decoder(avctx->codec_id);
    if ((ret = avcodec_open2(avctx, codec, NULL)) < 0) {
        printf("open codec faile %d \n",ret);
        return ret;
    }

    //Open the output file container
    char filename_out[] = "juren-30s-5.mp4";
    AVFormatContext *fmt_ctx_out = NULL;
    err = avformat_alloc_output_context2(&fmt_ctx_out, NULL, NULL, filename_out);
    if (!fmt_ctx_out) {
        printf("error code %d \n",AVERROR(ENOMEM));
        return ENOMEM;
    }
    //Add all the way to the container context
    AVStream *st = avformat_new_stream(fmt_ctx_out, NULL);
    st->time_base = fmt_ctx->streams[0]->time_base;

    AVCodecContext *enc_ctx = NULL;
    
    AVPacket *pt = av_packet_alloc();
    AVFrame *frame = av_frame_alloc();
    AVPacket *pkt_out = av_packet_alloc();

    int frame_num = 0; int read_end = 0;
    
    for(;;){
        if( 1 == read_end ){ break;}

        ret = av_read_frame(fmt_ctx, pkt);
        //Skip and do not process audio packets
        if( 1 == pkt->stream_index ){
            av_packet_unref(pt);
            continue;
        }

        if ( AVERROR_EOF == ret) {
            //After reading the file, the data and size of pkt should be null at this time
            avcodec_send_packet(avctx, NULL);
        }else {
            if( 0 != ret){
                printf("read error code %d \n",ret);
                return ENOMEM;
            }else{
                retry:
                if (avcodec_send_packet(avctx, pkt) == AVERROR(EAGAIN)) {
                    printf("Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
                    //Here you can consider sleeping for 0.1 seconds and returning EAGAIN. This is usually because there is a bug in ffmpeg's internal API.
                    goto retry;
                }
                //Release the encoded data in pkt
                av_packet_unref(pt);
            }

        }

        //The loop keeps reading data from the decoder until there is no more data to read.
        for(;;){
            //Read AVFrame
            ret = avcodec_receive_frame(avctx, frame);
            /* Release the YUV data in the frame,
             * Since av_frame_unref is called in the avcodec_receive_frame function, the following code can be commented.
             * So we don't need to manually unref this AVFrame
             * */
            //off_frame_unref(frame);

            if( AVERROR(EAGAIN) == ret ){
                //Prompt EAGAIN means the decoder needs more AVPackets
                //Jump out of the first layer of for and let the decoder get more AVPackets
                break;
            }else if( AVERROR_EOF == ret ){
                /* The prompt AVERROR_EOF means that an AVPacket with both data and size NULL has been sent to the decoder before.
                 * Sending NULL AVPacket prompts the decoder to flush out all cached frames.
                 * Usually a NULL AVPacket is sent only after reading the input file, or when another video stream needs to be decoded with an existing decoder.
                 *
                 * */

                /* Send null AVFrame to the encoder and let the encoder flush out the remaining data.
                 * */
                ret = avcodec_send_frame(enc_ctx, NULL);
                for(;;){
                    ret = avcodec_receive_packet(enc_ctx, pkt_out);
                    //It is impossible to return EAGAIN here, if there is any, exit directly.
                    if (ret == AVERROR(EAGAIN)){
                        printf("avcodec_receive_packet error code %d \n",ret);
                        return ret;
                    }
                    
                    if ( AVERROR_EOF == ret ){ break; }
                    
                    //Encode the AVPacket, print some information first, and then write it to the file.
                    printf("pkt_out size : %d \n",pkt_out->size);
                    //Set the stream_index of AVPacket so that you know which stream it is.
                    pkt_out->stream_index = st->index;
                    //Convert the time base of AVPacket to the time base of the output stream.
                    pkt_out->pts = av_rescale_q_rnd(pkt_out->pts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->dts = av_rescale_q_rnd(pkt_out->dts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->duration = av_rescale_q_rnd(pkt_out->duration, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);


                    ret = av_interleaved_write_frame(fmt_ctx_out, pkt_out);
                    if (ret < 0) {
                        printf("av_interleaved_write_frame faile %d \n",ret);
                        return ret;
                    }
                    av_packet_unref(pt_out);
                }
                av_write_trailer(fmt_ctx_out);
                //Jump out of the second layer of for, the file has been decoded.
                read_end = 1;
                break;
            }else if( ret >= 0 ){
                //Only when a frame is decoded can the encoder be initialized.
                if( NULL == enc_ctx ){
                    //Open the encoder and set encoding information.
                    AVCodec *encode = avcodec_find_encoder(AV_CODEC_ID_H264);
                    enc_ctx = avcodec_alloc_context3(encode);
                    enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
                    enc_ctx->bit_rate = 400000;
                    enc_ctx->framerate = avctx->framerate;
                    enc_ctx->gop_size = 30;
                    enc_ctx->max_b_frames = 10;
                    enc_ctx->profile = FF_PROFILE_H264_MAIN;
                   
                    /*
                     * In fact, the following information is also available in the container. You can also open the encoder directly in the container at the beginning.
                     * I took these encoder parameters from AVFrame because the difference in the container is final.
                     * Because the AVFrame you decoded may go through a filter, the information will be transformed after the filter, but this article does not use filters.
                     */
                     
                    //The time base of the encoder should be the time base of AVFrame, because AVFrame is the input. The time base of AVFrame is the time base of the stream.
                    enc_ctx->time_base = fmt_ctx->streams[0]->time_base;
                    enc_ctx->width = fmt_ctx->streams[0]->codecpar->width;
                    enc_ctx->height = fmt_ctx->streams[0]->codecpar->height;
                    enc_ctx->sample_aspect_ratio = st->sample_aspect_ratio = frame->sample_aspect_ratio;
                    enc_ctx->pix_fmt = frame->format;
                    enc_ctx->color_range            = frame->color_range;
                    enc_ctx->color_primaries        = frame->color_primaries;
                    enc_ctx->color_trc              = frame->color_trc;
                    enc_ctx->colorspace             = frame->colorspace;
                    enc_ctx->chroma_sample_location = frame->chroma_location;

                    /* Note that the value of this field_order is different for different videos. I have written it here.
                     * Because the video in this article is AV_FIELD_PROGRESSIVE
                     * The production environment needs to process different videos
                     */
                    enc_ctx->field_order = AV_FIELD_PROGRESSIVE;

                    /* Now we need to copy the encoder parameters to the stream. When decoding, assign parameters from the stream to the decoder.
                     * Now let’s do it in reverse.
                     * */
                    ret = avcodec_parameters_from_context(st->codecpar,enc_ctx);
                    if (ret < 0){
                        printf("error code %d \n",ret);
                        return ret;
                    }
                    if ((ret = avcodec_open2(enc_ctx, encode, NULL)) < 0) {
                        printf("open codec faile %d \n",ret);
                        return ret;
                    }

                    //Formally open the output file
                    if ((ret = avio_open2(&fmt_ctx_out->pb, filename_out, AVIO_FLAG_WRITE,&fmt_ctx_out->interrupt_callback,NULL)) < 0) {
                        printf("avio_open2 fail %d \n",ret);
                        return ret;
                    }

                    //Write the file header first.
                    ret = avformat_write_header(fmt_ctx_out,NULL);
                    if (ret < 0) {
                        printf("avformat_write_header fail %d \n",ret);
                        return ret;
                    }

                }

                //Send AVFrame to the encoder, and then continuously read AVPacket
                ret = avcodec_send_frame(enc_ctx, frame);
                if (ret < 0) {
                    printf("avcodec_send_frame fail %d \n",ret);
                    return ret;
                }
                for(;;){
                    ret = avcodec_receive_packet(enc_ctx, pkt_out);
                    if (ret == AVERROR(EAGAIN)){ break; }
                    
                    if (ret < 0){
                    printf("avcodec_receive_packet fail %d \n",ret);
                    return ret;
                    }
                    
                    //Encode the AVPacket, print some information first, and then write it to the file.
                    printf("pkt_out size : %d \n",pkt_out->size);

                    //Set the stream_index of AVPacket so that you know which stream it is.
                    pkt_out->stream_index = st->index;
                    
                    //Convert the time base of AVPacket to the time base of the output stream.
                    pkt_out->pts = av_rescale_q_rnd(pkt_out->pts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->dts = av_rescale_q_rnd(pkt_out->dts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->duration = av_rescale_q_rnd(pkt_out->duration, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

                    ret = av_interleaved_write_frame(fmt_ctx_out, pkt_out);
                    if (ret < 0) {
                        printf("av_interleaved_write_frame faile %d \n",ret);
                        return ret;
                    }
                    av_packet_unref(pt_out);
                }

            }
            else{ printf("other fail \n"); return ret;}
        }
    }
    
    av_frame_free(&frame); av_packet_free(&pt); av_packet_free(&pkt_out);
    
    //Close the encoder and decoder.
    avcodec_close(avctx); avcodec_close(enc_ctx);

    //Release container memory.
    avformat_free_context(fmt_ctx);

    //Must adjust avio_closep, otherwise the data may not be written in, it will be 0kb
    avio_closep(&fmt_ctx_out->pb);
    avformat_free_context(fmt_ctx_out);
    printf("done \n");

    return 0;
}


    


  • Problems with outputting stream format as RTMP about FFmpeg C-API

    27 November 2023, by dongrixinyu

    I am using FFmpeg's C API to push video streams rtmp://.... into an SRS server.
    
The input stream is an MP4 file named juren-30s.mp4.
    
The output stream is also an MP4 file named juren-30s-5.mp4.

    


    My piece of code (see further down) works fine when used in the following steps:
    
mp4 -> demux -> decode -> rgb images -> encode -> mux -> mp4.

    


    Problem:

    


    When I changed the output stream to an online RTMP url named rtmp://ip:port/live/stream_nb_23 (just an example, you can change it according to your server and rules.)

    


    result: This code would be corrupted mp4 -> rtmp(flv).

    


    What I've tried:

    


    Changing the output format
    
I changed the output format param to become flv when I initialized the avformat_alloc_output_context2. But this didn't help.

    


    Debugging the output
    
When I executed ffprobe rtmp://ip:port/live/xxxxxxx, I got the following errors and did not know why:

    


    [h264 @ 0x55a925e3ba80] luma_log2_weight_denom 12 is out of range
[h264 @ 0x55a925e3ba80] Missing reference picture, default is 2
[h264 @ 0x55a925e3ba80] concealing 8003 DC, 8003 AC, 8003 MV errors in P frame
[h264 @ 0x55a925e3ba80] QP 4294966938 out of range
[h264 @ 0x55a925e3ba80] decode_slice_header error
[h264 @ 0x55a925e3ba80] no frame!
[h264 @ 0x55a925e3ba80] luma_log2_weight_denom 21 is out of range
[h264 @ 0x55a925e3ba80] luma_log2_weight_denom 10 is out of range
[h264 @ 0x55a925e3ba80] chroma_log2_weight_denom 12 is out of range
[h264 @ 0x55a925e3ba80] Missing reference picture, default is 0
[h264 @ 0x55a925e3ba80] decode_slice_header error
[h264 @ 0x55a925e3ba80] QP 4294967066 out of range
[h264 @ 0x55a925e3ba80] decode_slice_header error
[h264 @ 0x55a925e3ba80] no frame!
[h264 @ 0x55a925e3ba80] QP 341 out of range
[h264 @ 0x55a925e3ba80] decode_slice_header error


    


    I am confused about the difference between MP4 and RTMP of how to use FFmpeg C-API to produce a correct output stream format.

    


    Besides, I also wanna learn how to convert video and audio streams into other formats using FFmpeg C-api, such as flv, ts, rtsp, etc.

    


    Code to reproduce the problem:

    


    


    So how to make this code output to RTMP without getting issue of an unplayable video?

    


    #include 
#include "libavformat/avformat.h"
int main()
{
    int ret = 0; int err;

    //Open input file
    char filename[] = "juren-30s.mp4";
    AVFormatContext *fmt_ctx = avformat_alloc_context();
    if (!fmt_ctx) {
        printf("error code %d \n",AVERROR(ENOMEM));
        return ENOMEM;
    }
    if((err = avformat_open_input(&fmt_ctx, filename,NULL,NULL)) < 0){
        printf("can not open file %d \n",err);
        return err;
    }

    //Open the decoder
    AVCodecContext *avctx = avcodec_alloc_context3(NULL);
    ret = avcodec_parameters_to_context(avctx, fmt_ctx->streams[0]->codecpar);
    if (ret < 0){
        printf("error code %d \n",ret);
        return ret;
    }
    AVCodec *codec = avcodec_find_decoder(avctx->codec_id);
    if ((ret = avcodec_open2(avctx, codec, NULL)) < 0) {
        printf("open codec faile %d \n",ret);
        return ret;
    }

    //Open the output file container
    char filename_out[] = "juren-30s-5.mp4";
    AVFormatContext *fmt_ctx_out = NULL;
    err = avformat_alloc_output_context2(&fmt_ctx_out, NULL, NULL, filename_out);
    if (!fmt_ctx_out) {
        printf("error code %d \n",AVERROR(ENOMEM));
        return ENOMEM;
    }
    //Add all the way to the container context
    AVStream *st = avformat_new_stream(fmt_ctx_out, NULL);
    st->time_base = fmt_ctx->streams[0]->time_base;

    AVCodecContext *enc_ctx = NULL;
    
    AVPacket *pt = av_packet_alloc();
    AVFrame *frame = av_frame_alloc();
    AVPacket *pkt_out = av_packet_alloc();

    int frame_num = 0; int read_end = 0;
    
    for(;;){
        if( 1 == read_end ){ break;}

        ret = av_read_frame(fmt_ctx, pkt);
        //Skip and do not process audio packets
        if( 1 == pkt->stream_index ){
            av_packet_unref(pt);
            continue;
        }

        if ( AVERROR_EOF == ret) {
            //After reading the file, the data and size of pkt should be null at this time
            avcodec_send_packet(avctx, NULL);
        }else {
            if( 0 != ret){
                printf("read error code %d \n",ret);
                return ENOMEM;
            }else{
                retry:
                if (avcodec_send_packet(avctx, pkt) == AVERROR(EAGAIN)) {
                    printf("Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
                    //Here you can consider sleeping for 0.1 seconds and returning EAGAIN. This is usually because there is a bug in ffmpeg's internal API.
                    goto retry;
                }
                //Release the encoded data in pkt
                av_packet_unref(pt);
            }

        }

        //The loop keeps reading data from the decoder until there is no more data to read.
        for(;;){
            //Read AVFrame
            ret = avcodec_receive_frame(avctx, frame);
            /* Release the YUV data in the frame,
             * Since av_frame_unref is called in the avcodec_receive_frame function, the following code can be commented.
             * So we don't need to manually unref this AVFrame
             * */
            //off_frame_unref(frame);

            if( AVERROR(EAGAIN) == ret ){
                //Prompt EAGAIN means the decoder needs more AVPackets
                //Jump out of the first layer of for and let the decoder get more AVPackets
                break;
            }else if( AVERROR_EOF == ret ){
                /* The prompt AVERROR_EOF means that an AVPacket with both data and size NULL has been sent to the decoder before.
                 * Sending NULL AVPacket prompts the decoder to flush out all cached frames.
                 * Usually a NULL AVPacket is sent only after reading the input file, or when another video stream needs to be decoded with an existing decoder.
                 *
                 * */

                /* Send null AVFrame to the encoder and let the encoder flush out the remaining data.
                 * */
                ret = avcodec_send_frame(enc_ctx, NULL);
                for(;;){
                    ret = avcodec_receive_packet(enc_ctx, pkt_out);
                    //It is impossible to return EAGAIN here, if there is any, exit directly.
                    if (ret == AVERROR(EAGAIN)){
                        printf("avcodec_receive_packet error code %d \n",ret);
                        return ret;
                    }
                    
                    if ( AVERROR_EOF == ret ){ break; }
                    
                    //Encode the AVPacket, print some information first, and then write it to the file.
                    printf("pkt_out size : %d \n",pkt_out->size);
                    //Set the stream_index of AVPacket so that you know which stream it is.
                    pkt_out->stream_index = st->index;
                    //Convert the time base of AVPacket to the time base of the output stream.
                    pkt_out->pts = av_rescale_q_rnd(pkt_out->pts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->dts = av_rescale_q_rnd(pkt_out->dts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->duration = av_rescale_q_rnd(pkt_out->duration, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);


                    ret = av_interleaved_write_frame(fmt_ctx_out, pkt_out);
                    if (ret < 0) {
                        printf("av_interleaved_write_frame faile %d \n",ret);
                        return ret;
                    }
                    av_packet_unref(pt_out);
                }
                av_write_trailer(fmt_ctx_out);
                //Jump out of the second layer of for, the file has been decoded.
                read_end = 1;
                break;
            }else if( ret >= 0 ){
                //Only when a frame is decoded can the encoder be initialized.
                if( NULL == enc_ctx ){
                    //Open the encoder and set encoding information.
                    AVCodec *encode = avcodec_find_encoder(AV_CODEC_ID_H264);
                    enc_ctx = avcodec_alloc_context3(encode);
                    enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
                    enc_ctx->bit_rate = 400000;
                    enc_ctx->framerate = avctx->framerate;
                    enc_ctx->gop_size = 30;
                    enc_ctx->max_b_frames = 10;
                    enc_ctx->profile = FF_PROFILE_H264_MAIN;
                   
                    /*
                     * In fact, the following information is also available in the container. You can also open the encoder directly in the container at the beginning.
                     * I took these encoder parameters from AVFrame because the difference in the container is final.
                     * Because the AVFrame you decoded may go through a filter, the information will be transformed after the filter, but this article does not use filters.
                     */
                     
                    //The time base of the encoder should be the time base of AVFrame, because AVFrame is the input. The time base of AVFrame is the time base of the stream.
                    enc_ctx->time_base = fmt_ctx->streams[0]->time_base;
                    enc_ctx->width = fmt_ctx->streams[0]->codecpar->width;
                    enc_ctx->height = fmt_ctx->streams[0]->codecpar->height;
                    enc_ctx->sample_aspect_ratio = st->sample_aspect_ratio = frame->sample_aspect_ratio;
                    enc_ctx->pix_fmt = frame->format;
                    enc_ctx->color_range            = frame->color_range;
                    enc_ctx->color_primaries        = frame->color_primaries;
                    enc_ctx->color_trc              = frame->color_trc;
                    enc_ctx->colorspace             = frame->colorspace;
                    enc_ctx->chroma_sample_location = frame->chroma_location;

                    /* Note that the value of this field_order is different for different videos. I have written it here.
                     * Because the video in this article is AV_FIELD_PROGRESSIVE
                     * The production environment needs to process different videos
                     */
                    enc_ctx->field_order = AV_FIELD_PROGRESSIVE;

                    /* Now we need to copy the encoder parameters to the stream. When decoding, assign parameters from the stream to the decoder.
                     * Now let’s do it in reverse.
                     * */
                    ret = avcodec_parameters_from_context(st->codecpar,enc_ctx);
                    if (ret < 0){
                        printf("error code %d \n",ret);
                        return ret;
                    }
                    if ((ret = avcodec_open2(enc_ctx, encode, NULL)) < 0) {
                        printf("open codec faile %d \n",ret);
                        return ret;
                    }

                    //Formally open the output file
                    if ((ret = avio_open2(&fmt_ctx_out->pb, filename_out, AVIO_FLAG_WRITE,&fmt_ctx_out->interrupt_callback,NULL)) < 0) {
                        printf("avio_open2 fail %d \n",ret);
                        return ret;
                    }

                    //Write the file header first.
                    ret = avformat_write_header(fmt_ctx_out,NULL);
                    if (ret < 0) {
                        printf("avformat_write_header fail %d \n",ret);
                        return ret;
                    }

                }

                //Send AVFrame to the encoder, and then continuously read AVPacket
                ret = avcodec_send_frame(enc_ctx, frame);
                if (ret < 0) {
                    printf("avcodec_send_frame fail %d \n",ret);
                    return ret;
                }
                for(;;){
                    ret = avcodec_receive_packet(enc_ctx, pkt_out);
                    if (ret == AVERROR(EAGAIN)){ break; }
                    
                    if (ret < 0){
                    printf("avcodec_receive_packet fail %d \n",ret);
                    return ret;
                    }
                    
                    //Encode the AVPacket, print some information first, and then write it to the file.
                    printf("pkt_out size : %d \n",pkt_out->size);

                    //Set the stream_index of AVPacket so that you know which stream it is.
                    pkt_out->stream_index = st->index;
                    
                    //Convert the time base of AVPacket to the time base of the output stream.
                    pkt_out->pts = av_rescale_q_rnd(pkt_out->pts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->dts = av_rescale_q_rnd(pkt_out->dts, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
                    pkt_out->duration = av_rescale_q_rnd(pkt_out->duration, fmt_ctx->streams[0]->time_base, st->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

                    ret = av_interleaved_write_frame(fmt_ctx_out, pkt_out);
                    if (ret < 0) {
                        printf("av_interleaved_write_frame faile %d \n",ret);
                        return ret;
                    }
                    av_packet_unref(pt_out);
                }

            }
            else{ printf("other fail \n"); return ret;}
        }
    }
    
    av_frame_free(&frame); av_packet_free(&pt); av_packet_free(&pkt_out);
    
    //Close the encoder and decoder.
    avcodec_close(avctx); avcodec_close(enc_ctx);

    //Release container memory.
    avformat_free_context(fmt_ctx);

    //Must adjust avio_closep, otherwise the data may not be written in, it will be 0kb
    avio_closep(&fmt_ctx_out->pb);
    avformat_free_context(fmt_ctx_out);
    printf("done \n");

    return 0;
}