FFmpegPreRecordH264Provider
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
Â