Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Current »

FFmpegPreRecordH264Provider is dependent on FFmpegH264Provider. It is designed for pre-recording. It supports setting the cache duration in milliseconds.

API Instructions

class FFmpegPreRecordH264Provider {

public:
    FFmpegPreRecordH264Provider(std::shared_ptr<FFmpegVideoSource> yuvSource, int maxCacheTimeMs = 5000);
    ~FFmpegPreRecordH264Provider();

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

    AVCodecContext* getAVCodecContext();

    int getPreRecordFrames(std::queue<AVPacket*>& frameQueue);
};

}}}

Constructors

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

if maxCacheSize > 0, maxCacheTimeMs is valid, otherwise, use the default value of 5000.

/**
 * @param yuvSource provide yuv data.
 *
 * @param maxCacheTimeMs >0 is valid, otherwise, use the default value of 5000.
 *
 */
FFmpegPreRecordH264Provider(std::shared_ptr<FFmpegVideoSource> yuvSource, int maxCacheTimeMs = 5000);

prepare

Set encoding parameters, and prepare FFmpegH264Provider.

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

destroy

Destroy FFmpegH264Provider.

/**
 * 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.

/**
 * get encoder context.
 */
AVCodecContext* getAVCodecContext();

getPreRecordFrames

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.

/**
 * 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 getPreRecordFrames(std::queue<AVPacket*>& frameQueue);

Sample Code

This is a sample of how to pre-record MP4 dependent on FFmpegPreRecordH264Provider FFmpegH264Provider and FFmpegAVMuxer.

the flow of pre-record MP4:

create yuv source --> create pre-record h264 provider --> pre-record provider prepare --> recording 6s --> create h264 provider --> h264 provider prepare -> create MP4 muxer -> init muxer --> put all pre-record frames to muxer --> create the thread of get the frame from h264 provider to put to muxer --> recording 3s --> uninit muxer

void FFmpegPreRecordMP4Muxer_Test(const char* path) {
    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 preRecordH264Provider = make_shared<FFmpegPreRecordH264Provider>(videoSource, 5000);

    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 = preRecordH264Provider->prepare(param);

    if (ret == 0) {
        std::this_thread::sleep_for(std::chrono::milliseconds(10000));
    } else {
        preRecordH264Provider->destroy();
        videoSource->close();
        return;
    }

    auto h264Provider = make_shared<FFmpegH264Provider>(videoSource);
    auto mp4Muxer = make_shared<FFmpegAVMuxer>(true);
    ret = h264Provider->prepare(param);

    string filepath = "ffmpeg_prerecord_mp4_muxer_test.mp4";
    if (path != nullptr) {
        filepath = string(path);
    }

    auto muxMp4ThreadFunc = [&](){
        int index = 0;
        bool initMuxer = false;
        while(!is_exit) {
            AVPacket* packet = nullptr;
            auto ret = h264Provider->getFrame(packet);
            
            if (ret < 0 || packet == nullptr) {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                continue;
            }

            if (!initMuxer) {
                std::queue<AVPacket*> preRecordFrames;
                ret = preRecordH264Provider->getPreRecordFrames(preRecordFrames);
                ret = mp4Muxer->init(filepath, h264Provider->getAVCodecContext());
                initMuxer = true;
                int preRecordIndex = 0;
                while(!preRecordFrames.empty()) {
                    AVPacket* prePacket = preRecordFrames.front();
                    printf("muxMp4Thread, preRecordFrames get h264 frame[%d] pts: %lld, size: %d, isKeyFrame: %d\n", index, prePacket->pts, prePacket->size, prePacket->flags & AV_PKT_FLAG_KEY);
                    ret = mp4Muxer->putVideoFrame(prePacket);
                    av_packet_unref(prePacket);
                    av_packet_free(&prePacket);
                    preRecordFrames.pop();
                    preRecordIndex++;
                }
            }

            printf("muxMp4Thread, get h264 frame[%d] pts: %lld, size: %d, isKeyFrame: %d\n", index, packet->pts, packet->size, packet->flags & AV_PKT_FLAG_KEY);

            ret = mp4Muxer->putVideoFrame(packet);

            av_packet_unref(packet);
            av_packet_free(&packet);
            index++;
        }
        mp4Muxer->flush();
        mp4Muxer->uninit();
    };
    
    auto thread = make_shared<std::thread>(muxMp4ThreadFunc);

    _wait_exit("FFmpegPreRecordMP4Muxer_Test");

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

}

Test Result

./ffmpeg_sample mp4prerecord
FFmpegPreRecordH264ProviderTestResult_1.pngFFmpegPreRecordH264ProviderTestResult_2.pngFFmpegPreRecordH264ProviderTestResult_3.png

  • No labels