Newest 'libx264' Questions - Stack Overflow

http://stackoverflow.com/questions/tagged/libx264

Les articles publiés sur le site

  • ffmpeg/libx264 C API : frames dropped from end of short MP4

    19 juillet 2017, par Blake McConnell

    In my C++ application, I am taking a series of JPEG images, manipulating their data using FreeImage, and then encoding the bitmaps as H264 using the ffmpeg/libx264 C API. The output is an MP4 which shows the series of 22 images at 12fps. My code is adapted from the "muxing" example that comes with ffmpeg C source code.

    My problem: no matter how I tune the codec parameters, a certain number of frames at the end of the sequence which are passed to the encoder do not appear in the final output. I've set the AVCodecContext parameters like this:

    //set context params
    ctx->codec_id = AV_CODEC_ID_H264;
    ctx->bit_rate = 4000 * 1000;
    ctx->width = _width;
    ctx->height = _height;
    ost->st->time_base = AVRational{ 1, 12 };
    ctx->time_base = ost->st->time_base;
    ctx->gop_size = 1;
    ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    

    I have found that the higher the gop_size the more frames are dropped from the end of the video. I can also see from the output that, with this gop size (where I'm essentially directing that all output frames be I frames) that only 9 frames are written.

    I'm not sure why this is occurring. I experimented with encoding duplicate frames and making a much longer video. This resulted in no frames being dropped. I know with the ffmpeg command line tool there is a concatenation command that accomplishes what I am trying to do, but I'm not sure how to accomplish the same goal using the C API.

    Here's the output I'm getting from the console:

    [libx264 @ 026d81c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 [libx264 @ 026d81c0] profile High, level 3.1 [libx264 @ 026d81c0] 264 - core 152 r2851 ba24899 - H.264/MPEG-4 AVC codec - Cop yleft 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=1 deb lock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=0 m e_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chro ma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=0 keyint=1 ke yint_min=1 scenecut=40 intra_refresh=0 rc=abr mbtree=0 bitrate=4000 ratetol=1.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 Output #0, mp4, to '....\images\c411a991-46f6-400c-8bb0-77af3738559a.mp4': Stream #0:0: Video: h264, yuv420p, 700x700, q=2-31, 4000 kb/s, 12 tbn

    [libx264 @ 026d81c0] frame I:9 Avg QP:17.83 size:111058 [libx264 @ 026d81c0] mb I I16..4: 1.9% 47.7% 50.5% [libx264 @ 026d81c0] final ratefactor: 19.14 [libx264 @ 026d81c0] 8x8 transform intra:47.7% [libx264 @ 026d81c0] coded y,uvDC,uvAC intra: 98.4% 96.9% 89.5% [libx264 @ 026d81c0] i16 v,h,dc,p: 64% 6% 2% 28% [libx264 @ 026d81c0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 32% 15% 9% 5% 5% 6% 8% 10% 10% [libx264 @ 026d81c0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 28% 18% 7% 6% 8% 8% 8% 9% 8% [libx264 @ 026d81c0] i8c dc,h,v,p: 43% 22% 25% 10% [libx264 @ 026d81c0] kb/s:10661.53

    Code included below:

    MP4Writer.h

    #ifndef MPEG_WRITER
    #define MPEG_WRITER
    
    #include 
    #include 
    #include 
    #include 
    extern "C" {
        #include avformat.h>
        #include swscale.h>
        #include swresample.h>
        #include swscale.h>
    }
    
    typedef struct OutputStream 
    {
        AVStream *st;
        AVCodecContext *enc;
    
        //pts of the next frame that will be generated
        int64_t next_pts;
        int samples_count;
    
        AVFrame *frame;
        AVFrame *tmp_frame;
    
        float t, tincr, tincr2;
    
        struct SwsContext *sws_ctx;
        struct SwrContext *swr_ctx;
    };
    
    class MP4Writer {
        public:
            MP4Writer();
            void Init();
            int16_t SetOutput( const std::string & path );
            int16_t AddFrame( uint8_t * imgData );
            int16_t Write( std::vector & imgData );
            int16_t Finalize();
            void SetHeight( const int height ) { _height = _width = height; } //assuming 1:1 aspect ratio
    
        private:
            int16_t AddStream( OutputStream * ost, AVFormatContext * formatCtx, AVCodec ** codec, enum AVCodecID codecId );
            int16_t OpenVideo( AVFormatContext * formatCtx, AVCodec *codec, OutputStream * ost, AVDictionary * optArg );
            static AVFrame * AllocPicture( enum AVPixelFormat pixFmt, int width, int height );
            static AVFrame * GetVideoFrame( uint8_t * imgData, OutputStream * ost, const int width, const int height );
            static int WriteFrame( AVFormatContext * formatCtx, const AVRational * timeBase, AVStream * stream, AVPacket * packet );
    
            int _width;
            int _height;
            OutputStream _ost;
            AVFormatContext * _formatCtx;
            AVDictionary * _dict;
    };
    
    #endif //MPEG_WRITER
    

    MP4Writer.cpp

    #include 
    #include 
    
    MP4Writer::MP4Writer()
    {
        _width = 0;
        _height = 0;
    }
    
    void MP4Writer::Init()
    {
        av_register_all();
    }
    
    /**
     sets up output stream for the specified path.
     note that the output format is deduced automatically from the file extension passed
     @param path: output file path
     @returns: -1 = output could not be deduced, -2 = invalid codec, -3 = error opening output file,
               -4 = error writing header
    */
    int16_t MP4Writer::SetOutput( const std::string & path )
    {
        int error;
        AVCodec * codec;
        AVOutputFormat * format;
    
        _ost = OutputStream{}; //TODO reset state in a more focused way?
    
        //allocate output media context
        avformat_alloc_output_context2( &_formatCtx, NULL, NULL, path.c_str() );
        if ( !_formatCtx ) {
            std::cout << "could not deduce output format from file extension.  aborting" << std::endl;
            return -1;
        }
        //set format
        format = _formatCtx->oformat;
        if ( format->video_codec != AV_CODEC_ID_NONE ) {
            AddStream( &_ost, _formatCtx, &codec, format->video_codec );
        }
        else {
            std::cout << "there is no video codec set.  aborting" << std::endl;
            return -2;
        }
    
        OpenVideo( _formatCtx, codec, &_ost, _dict );
    
        av_dump_format( _formatCtx, 0, path.c_str(), 1 );
    
        //open output file
        if ( !( format->flags & AVFMT_NOFILE )) {
            error = avio_open( &_formatCtx->pb, path.c_str(), AVIO_FLAG_WRITE );
            if ( error < 0 ) {
                std::cout << "there was an error opening output file " << path << ".  aborting" << std::endl;
                return -3;
            }
        }
    
        //write header
        error = avformat_write_header( _formatCtx, &_dict );
        if ( error < 0 ) {
            std::cout << "an error occurred writing header. aborting" << std::endl;
            return -4;
        }
    
        return 0;
    }
    
    /**
     initialize the output stream
     @param ost: the output stream
     @param formatCtx: the context format
     @param codec: the output codec
     @param codec: the ffmpeg enumerated id of the codec
     @returns: -1 = encoder not found, -2 = stream could not be allocated, -3 = encoding context could not be allocated
    */
    int16_t MP4Writer::AddStream( OutputStream * ost, AVFormatContext * formatCtx, AVCodec ** codec, enum AVCodecID codecId )
    {
        AVCodecContext * ctx; //TODO not sure why this is here, could just set ost->enc directly
        int i;
    
        //detect the encoder
        *codec = avcodec_find_encoder( codecId );
        if ( (*codec) == NULL ) {
            std::cout << "could not find encoder.  aborting" << std::endl;
            return -1;
        }
    
        //allocate stream
        ost->st = avformat_new_stream( formatCtx, NULL );
        if ( ost->st == NULL ) {
            std::cout << "could not allocate stream.  aborting" << std::endl;
            return -2;
        }
    
        //allocate encoding context
        ost->st->id = formatCtx->nb_streams - 1;
        ctx = avcodec_alloc_context3( *codec );
        if ( ctx == NULL ) {
            std::cout << "could not allocate encoding context.  aborting" << std::endl;
            return -3;
        }
    
        ost->enc = ctx;
    
        //set context params
        ctx->codec_id = AV_CODEC_ID_H264;
        ctx->bit_rate = 4000 * 1000;
        ctx->width = _width;
        ctx->height = _height;
        ost->st->time_base = AVRational{ 1, 12 };
        ctx->time_base = ost->st->time_base;
        ctx->gop_size = 1;
        ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    
        //if neccesary, set stream headers and formats separately
        if ( formatCtx->oformat->flags & AVFMT_GLOBALHEADER ) {
            std::cout << "setting stream and headers to be separate" << std::endl;
            ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
        }
    
        return 0;
    }
    
    /**
     open the video for writing
     @param formatCtx: the format context
     @param codec: output codec
     @param ost: output stream
     @param optArg: dictionary
     @return: -1 = error opening codec, -2 = allocate new frame, -3 = copy stream params
    */
    int16_t MP4Writer::OpenVideo( AVFormatContext * formatCtx, AVCodec *codec, OutputStream * ost, AVDictionary * optArg )
    {
        int error;
        AVCodecContext * ctx = ost->enc;
        AVDictionary * dict = NULL;
        av_dict_copy( &dict, optArg, 0 );
    
        //open codec
        error = avcodec_open2( ctx, codec, &dict );
        av_dict_free( &dict );
        if ( error < 0 ) {
            std::cout << "there was an error opening the codec.  aborting" << std::endl;
            return -1;
        }
    
        //allocate new frame
        ost->frame = AllocPicture( ctx->pix_fmt, ctx->width, ctx->height );
        if ( ost->frame == NULL ) {
            std::cout << "there was an error allocating a new frame.  aborting" << std::endl;
            return -2;
        }
    
        //copy steam params
        error = avcodec_parameters_from_context( ost->st->codecpar, ctx );
        if ( error < 0 ) {
            std::cout << "could not copy stream parameters.  aborting" << std::endl;
            return -3;
        }
    
        return 0;
    }
    
    /**
     allocate a new frame
     @param pixFmt: ffmpeg enumerated pixel format
     @param width: output width
     @param height: output height
     @returns: an inititalized frame
    */
    AVFrame * MP4Writer::AllocPicture( enum AVPixelFormat pixFmt, int width, int height )
    {
        AVFrame * picture;
        int error;
    
        //allocate the frame
        picture = av_frame_alloc();
        if ( picture == NULL ) {
            std::cout << "there was an error allocating the picture" << std::endl;
            return NULL;
        }
    
        picture->format = pixFmt;
        picture->width = width;
        picture->height = height;
    
        //allocate the frame's data buffer
        error = av_frame_get_buffer( picture, 32 );
        if ( error < 0 ) {
            std::cout << "could not allocate frame data" << std::endl;
            return NULL;
        }
        picture->pts = 0;
        return picture;
    }
    
    /**
     convert raw RGB buffer to YUV frame
     @return: frame that contains image data
    */
    AVFrame * MP4Writer::GetVideoFrame( uint8_t * imgData, OutputStream * ost, const int width, const int height )
    {
        int error;
        AVCodecContext * ctx = ost->enc;
    
        //prepare the frame
        error = av_frame_make_writable( ost->frame );
        if ( error < 0 ) {
            std::cout << "could not make frame writeable" << std::endl;
            return NULL;
        }
    
        //TODO set this context one time per run, or even better, one time at init
        //convert RGB to YUV
        struct SwsContext* fooContext = sws_getContext( width, height, AV_PIX_FMT_BGR24, 
            width, height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL );
        int inLinesize[1] = { 3 * width }; // RGB stride
        uint8_t * inData[1] = { imgData };
        int sliceHeight = sws_scale( fooContext, inData, inLinesize, 0, height, ost->frame->data, ost->frame->linesize );
        sws_freeContext( fooContext );
    
        ost->frame->pts = ost->next_pts++;
        //TODO does the frame need to be returned here as it is available at the class level?
        return ost->frame;
    }
    
    /**
     write frame to file
     @param formatCtx: the output format context
     @param timeBase: the framerate
     @param stream: output stream
     @param packet: data packet
     @returns: see return values for av_interleaved_write_frame
    */
    int MP4Writer::WriteFrame( AVFormatContext * formatCtx, const AVRational * timeBase, AVStream * stream, AVPacket * packet )
    {
        av_packet_rescale_ts( packet, *timeBase, stream->time_base );
        packet->stream_index = stream->index;
    
        //write compressed file to media file
        return av_interleaved_write_frame( formatCtx, packet );
    }
    
    int16_t MP4Writer::Write( std::vector & imgData )
    {
        int16_t errorCount = 0;
        int16_t retVal = 0;
        bool countingUp = true;
        size_t i = 0;
        while ( true ) {
            //don't show first frame again when counting back down
            if ( !countingUp && i == 0 ) {
                break;
            }
            uint8_t * pixels = imgData[i].GetBits( imgData[i].mp4Input );
            AddFrame( pixels );
    
            //handle inc/dec without repeating last frame
            if ( countingUp ) {
                if ( i == imgData.size() -1 ) {
                    countingUp = false;
                    i--;
                }
                else {
                    i++;
                }
            }
            else {
                i--;
            }
        }
        Finalize();
        return 0; //TODO return error code
    }
    
    /**
     add another frame to output video
     @param imgData: the raw image data
     @returns -1 = error encoding video frame, -2 = error writing frame
    */
    int16_t MP4Writer::AddFrame( uint8_t * imgData )
    {
        int error;
        AVCodecContext * ctx;
        AVFrame * frame;
        int gotPacket = 0;
        AVPacket pkt = { 0 };
    
        ctx = _ost.enc;
        av_init_packet( &pkt );
    
        frame = GetVideoFrame( imgData, &_ost, _width, _height );
    
        //encode the image
        error = avcodec_encode_video2( ctx, &pkt, frame, &gotPacket );
        if ( error < 0 ) {
            std::cout << "there was an error encoding the video frame" << std::endl;
            return -1;
        }
    
        //write the frame.  NOTE: this doesn't kick in until the encoder has received a certain number of frames
        if ( gotPacket ) {
            error = WriteFrame( _formatCtx, &ctx->time_base, _ost.st, &pkt );
            if ( error < 0 ) {
                std::cout << "the video frame could not be written" << std::endl;
                return -2;
            }
        }
        return 0;
    }
    
    /**
     finalize output video and cleanup
    */
    int16_t MP4Writer::Finalize()
    {
        av_write_trailer( _formatCtx );
        avcodec_free_context( &_ost.enc );
        av_frame_free( &_ost.frame);
        av_frame_free( &_ost.tmp_frame );
        avio_closep( &_formatCtx->pb );
        avformat_free_context( _formatCtx );
        sws_freeContext( _ost.sws_ctx );
        swr_free( &_ost.swr_ctx);
        return 0;
    }
    

    usage

    #include 
    #include 
    #include 
    
    struct ImgData
    {
        unsigned int width;
        unsigned int height;
        std::string path;
        FIBITMAP * mp4Input;
    
        uint8_t * GetBits( FIBITMAP * bmp ) { return FreeImage_GetBits( bmp ); }
    };
    
    int main()
    {
         std::vector imgDataVec;
         //load images and push to imgDataVec
         MP4Writer mp4Writer;
         mp4Writer.SetHeight( 1200 ); //assumes 1:1 aspect ratio
         mp4Writer.Init();
         mp4Writer.SetOutput( "test.mp4" );
         mp4Writer.Write( imgDataVec );
    }
    
  • ffmpeg -movflags +faststart in clipbucket video script

    13 juillet 2017, par Spirog

    i am a little new at ffmpeg.

    Have a video script ( ClipBucket ) and would like to know how to add -movflags +faststart to the script to take advantage of this for .mp4 videos being converted.

    here is the code ffmpeg.class.php. Not sure where I can add this to work properly

    https://github.com/arslancb/clipbucket/tree/master/upload/includes/classes/conversion

    ffmpeg.class.php and conversion.class.php

    Seems to be the correct file(s), just not sure where to add it

    Thanks so much in advance.

    Spiro

  • DCT coefficients and MV extraction in ffmpeg Mpeg-4 encoding

    30 juin 2017, par Giacomo Calvigioni

    I'm using ffmpeg and libx264 to encode a video and I want to extract the DCT coefficients and motion vector of each frame during the encoding process.

    What is the best way to do this?

    I read in the ffmpeg manual that is possible to use the debug mode with some flags to extract these values. I tried ffmpeg -debug dct_coeff to output the dct coefficients but this option doesn't work for me; is it deprecated or related to a specific ffmpeg version?

    Another option would be to modify and recompile ffmpeg source code but I don't know in which part of the code DCT and MV are calculated.

    Any help with the debug mode or code modification suggestions would be appreciated.

  • ffmpeg libx264 settings to keep exact colors

    21 juin 2017, par vinni

    does anyone have an idea how I need to edit these ffmpeg settings to keep the original colors? I'm trying to convert a video, but need to absolutely keep the rgb colors, as it's going to be embedded into a website with a background color.

    The parameters look currently like this:

    '-acodec aac -ac 2 -ab 160k  '
    '-vcodec libx264 -preset slow -profile:v baseline -level 25 '
    '-maxrate 10000000 -bufsize 10000000 -vb 1200k -f mp4 '
    '-threads 0'
    

    Thanks!

  • Transcode video with ffmpeg can't play by Win10 system player ?

    16 juin 2017, par wzjing

          I'm doing a video transcoder demo with ffmpeg lib and libx264 lib. I already can transcode video successully, but the output video can only play by some powerful player like VLC. I need it can be played by the Win10 system player and the Android system player. I hava found the reason may be encode AVCodecContext args. I try to copy those args frome decode AVCodecContext, the output can be played by Win10 defualt player, but the video became totally black.
          Here is my encode AVCodecContext args:

            encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
    
            if (!encoder) {
                av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
                return AVERROR_INVALIDDATA;
            }
            enc_ctx = avcodec_alloc_context3(encoder);
            enc_ctx->height = output_height;
            enc_ctx->width = output_width;
            enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
            enc_ctx->bit_rate = 1000000;
    
            /* take first format from list of supported formats */
            if (encoder->pix_fmts)
                enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
            else
                enc_ctx->pix_fmt = dec_ctx->pix_fmt;
    
            enc_ctx->time_base = av_inv_q(dec_ctx->framerate);
            enc_ctx->gop_size = 12;
            av_opt_set(enc_ctx->priv_data, "preset", "slow", 0);
            av_opt_set(enc_ctx->priv_data, "tune", "zerolatency", 0);
    
            enc_ctx->profile = FF_PROFILE_H264_HIGH;
            enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO;       
    
            enc_ctx->codec_tag = 0;