Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

FFmpegH264Provider can help you quickly create an H264 Stream. It supports setting the cache size and the cache duration in milliseconds. You can use it for live broadcasts or video recordings. FFmpegH264Provider is dependent on FFmpegVideoSource and FFmpegH264Encoder. It gets YUV data through FFmpegVideoSource and then sends YUV data to FFmpegH264Encoder. H264 data generated by FFmpegH264Encoder will be cached in the queue of FFmpegH264Provider. All of its APIs are thread-safe.

API Instructions

Code Block
languagecpp
namespace com { namespace sunplus { namespace media {

class FFmpegH264Provider {
public:
    FFmpegH264Provider(std::shared_ptr<FFmpegVideoSource> yuvSource, int maxCacheSize = 150, int maxCacheTimeMs = 0);
    ~FFmpegH264Provider();

public:	
    int prepare(VideoStreamParam_t param);
    void destroy();

    AVCodecContext* getAVCodecContext();

    int getFrame(AVPacket*& packet);
    int getAllFrames(std::queue<AVPacket*>& frameQueue);
};
}}}

Constructors

When creating FFmpegH264Provider you can set the cache size or duration.

  • if maxCacheSize > 0 && maxCacheTimeMs > 0, maxCacheTimeMs is valid.

  • if maxCacheSize <=0 && maxCacheTimeMs <=0, will not limit the cache size and the cache duration. It is recommended to use this only when recording, to prevent dropped frames.

Code Block
languagecpp
/**
 * @param yuvSource provide yuv data.
 *
 * @param maxCacheSize >0 is valid.
 *
 * @param maxCacheTimeMs >0 is valid.
 *
 */
FFmpegH264Provider(std::shared_ptr<FFmpegVideoSource> yuvSource, int maxCacheSize = 150, int maxCacheTimeMs = 0);

prepare

Set encoding parameters. Create FFmpegH264Encoder and initialize it. Create FFmpegVideoProvider to get yuv frame. Initialize the queue for cache the h264 frame. You can only getFrame/getAllFrames after preparing.

Code Block
languagecpp
/**
 * Set encoding parameters and initialize all required resources.
 *
 * @param param set parameters of the encoder.
 *
 */
int prepare(VideoStreamParam_t param);

destroy

Release all resources allocated by the prepare method and close the encoder. Empty the cached h264 frame and release the related resources. After destroying, the getFrame/getAllFrames returns a failure.

Code Block
languagecpp
/**
 * Empty the cached data and release all resources.
 */
void destroy();

getAVCodecContext

Get AVCodecContext to get the info of the encoder, such as width, height, spspps, etc.

Code Block
languagecpp
/**
 * get encoder context.
 */
AVCodecContext* getAVCodecContext();

getFrame

Get cached h264 frame from the queue. After successfully obtaining the packet, it must be freed with av_packet_unref()+av_packet_free() when it is no longer needed.

Code Block
languagecpp
/**
 * Get cached frame from the queue.
 * On success, the packet must be freed with av_packet_unref()+av_packet_free() when
 * it is no longer needed. 
 * @return 0 if OK, < 0 on error. 
 */
int getFrame(AVPacket*& packet);

getAllFrames

Get all cached h264 frames from the queue. The packet must be freed with av_packet_unref()+av_packet_free() when it is no longer needed.

Code Block
languagecpp
/**
 * Get all cached frames from the queue.
 * On success, the packet must be freed with av_packet_unref()+av_packet_free() when
 * it is no longer needed. 
 * @return 0 if OK, < 0 on error. 
 */
int getAllFrames(std::queue<AVPacket*>& frameQueue);

Sample Code

This is a sample of how to create the FFmpegH264Provider and get the h264 frame through it.

You can also refer to the Sample of FFmpegAVMuxer.

the flow of encode h264:

create yuv source --> create h264 provider --> provider prepare --> create the thread of get the h264 frame

Code Block
languagecpp
void FFmpegH264Provider_Test() {
    auto videoSource = make_shared<FFmpegV4L2VideoSource>("/dev/video0");
    AVDictionary *options = nullptr;
    av_dict_set(&options, "video_size", "1280x720", 0);
    av_dict_set(&options, "framerate", "30", 0);
    av_dict_set(&options, "pixel_format", "uyvy422", 0);

    int ret = videoSource->open(options);

    auto h264Provider = make_shared<FFmpegH264Provider>(videoSource);

    VideoStreamParam_t param;
    param.width = videoSource->getAVStream()->codecpar->width;
    param.height = videoSource->getAVStream()->codecpar->height;
    param.pix_fmt = (enum AVPixelFormat)videoSource->getAVStream()->codecpar->format;
    param.time_base = videoSource->getAVStream()->time_base;
    param.gop = 30;
    param.bitrate = 1000000;
    param.fps = 30;

    

    ret = h264Provider->prepare(param);

    auto getH264FrameThreadFunc = [&](){
        int index = 0;
        FILE* videofile = fopen("h264provider_test.h264", "wb+");
        while(!is_exit) {
            AVPacket* packet = nullptr;
            auto ret = h264Provider->getFrame(packet);
            if (packet != nullptr) {
                printf("getH264FrameThread, h264 frame[%d] pts: %lld, size: %d, isKeyFrame: %d\n", index, packet->pts, packet->size, packet->flags & AV_PKT_FLAG_KEY);
                index++;
                fwrite(packet->data, packet->size, 1, videofile);

                av_packet_unref(packet);
                av_packet_free(&packet);
            }
            
        }
        fclose(videofile);
    };

    auto thread = make_shared<std::thread>(getH264FrameThreadFunc);

    _wait_exit("FFmpegH264Provider_Test");
    
    if (thread->joinable()) {
        thread->join();
    }

    h264Provider->destroy();
    videoSource->close();

}

Test Result

Code Block
languagecpp
./ffmpeg_sample h264src
FFmpegH264ProviderTestResult.pngImage Modified