Я работаю над реализацией некоторых писателей ffmpeg и не могу понять, что я делаю неправильно. У меня есть файл mdf (медиа цифровой файл), который мне нужно конвертировать в avi, и у меня есть программное обеспечение, которое делает это. Тестовый пример: Avi-файл, который я получаю из своего программного обеспечения, и AVI-файл, который я получаю из программного обеспечения, идентичны. Я могу получить кадры из входного mdf-файла и правильно конвертировать их в bmp. Так что, я полагаю, что-то не так с ffmpeg. Мне также нужно использовать необработанный код RGB c в ffmpeg.
Вот код, который я написал, чтобы заполнить avi-файлы фреймами:
if (hOffLoaderDVR && m_hDeviceCollection && device && hDriveSetDVR && hFile)
{
std::string camSuffix = "_cam_";
std::string cameraName = hFile->streamByIndex(streamC)->cameraPortName().c_str();
std::string fileName = pathToAviDir + hFile->parameters()->name.c_str() + camSuffix + cameraName + std::to_string(streamC).c_str() + ".avi";
Offload::Request request;
Common::DataTypeHandle cameraParams = hFile->streamByIndex(streamC)->streamView()->dataType();
AVFrame* frame = m_ffwriter.alloc_picture(AV_PIX_FMT_BGR24, cameraParams->width(), cameraParams->height());
size_t datasize = hFile->streamByIndex(streamC)->streamView()->frameAtIndex(0)->buffer()->size(); // size in bytes
RecordingParams params(fileName, cameraParams->width(), cameraParams->height(), 50,
AV_PIX_FMT_BGR24, datasize);
frame->pkt_size = datasize;
m_ffwriter.delayedOpen(params);
for (unsigned int frameC = 0; frameC < hFile->streamByIndex(streamC)->streamView()->frameCount(); frameC++)
{
m_ffwriter.fill_rgb_image(frame, hFile->streamByIndex(streamC)->streamView()->frameAtIndex(frameC)->buffer()->data());
m_ffwriter.putImage(frame);
}
m_ffwriter.close();
av_frame_free(&frame);
}
Чтобы открыть файл AVI, я использую function ffmpegWriter :: delayedOpen:
bool FfmpegWriter::delayedOpen(const RecordingParams & params) {
unsigned int w = params.getWidth();
unsigned int h = params.getHeight();
unsigned int framerate = params.getFramerate();
unsigned int datasize = params.getDataSize();
m_filename = params.getPath();
unsigned int sample_rate = 0; //default
unsigned int channels = 0; //default
m_delayed = false;
if (w <= 0 || h <= 0) {
m_delayed = true;
return true;
}
m_ready = true;
// auto detect the output format from the name. default is mpeg.
m_fmt = av_guess_format(nullptr, m_filename.c_str(), nullptr);
m_fmt->video_codec = AV_CODEC_ID_RAWVIDEO; //can be moved to a parameter if required
if (!m_fmt) {
printf("Could not deduce output format from file extension: using MPEG.\n");
m_fmt = av_guess_format("mpeg", nullptr, nullptr);
}
if (!m_fmt) {
fprintf(stderr, "Could not find suitable output format\n");
::exit(1);
}
// allocate the output media context
m_oc = avformat_alloc_context();
if (!m_oc) {
fprintf(stderr, "Memory error\n");
::exit(1);
}
m_oc->oformat = m_fmt;
m_fmt->flags = AVFMT_NOTIMESTAMPS;
snprintf(m_oc->filename, sizeof(m_oc->filename), "%s", m_filename.c_str());
// add the audio and video streams using the default format codecs
// and initialize the codecs
m_video_st = nullptr;
m_audio_st = nullptr;
if (m_fmt->video_codec != AV_CODEC_ID_NONE) {
m_video_st = add_video_stream(m_oc, m_fmt->video_codec, w, h, framerate);
}
av_dump_format(m_oc, 0, m_filename.c_str(), 1);
// now that all the parameters are set, we can open
// video codecs and allocate the necessary encode buffers
if (m_video_st) {
open_video(m_oc, m_video_st, datasize);
}
// open the output file, if needed
if (!(m_fmt->flags & AVFMT_NOFILE)) {
if (avio_open(&m_oc->pb, m_filename.c_str(), AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "Could not open '%s'\n", m_filename.c_str());
::exit(1);
}
}
// write the stream header, if any
avformat_write_header(m_oc, NULL);
return true;
}
И для заполнения изображений и помещения их в AVI я использую следующие функции:
void FfmpegWriter::fill_rgb_image(AVFrame *pict, void *p)
{
memcpy(pict->data[0], p, pict->pkt_size);
}
bool FfmpegWriter::putImage(AVFrame * newFrame) {
if (m_delayed) {
// savedConfig.put("width",Value((int)image.width()));
// savedConfig.put("height",Value((int)image.height()));
}
if (!isOk()) {
return false;
}
if (m_video_st) {
m_video_pts = (double)av_stream_get_end_pts(m_video_st) *m_video_st->time_base.num / m_video_st->time_base.den;
}
else {
m_video_pts = 0.0;
}
if (!(m_video_st)) {
return false;
}
// write interleaved video frame
write_video_frame(m_oc, m_video_st, newFrame);
return true;
}
Не правильно ли открыть контекст? Или где может быть проблема? Проблемы, которые я вижу, состоят в том, что выход AVI имеет примерно минутную задержку в начале без смены кадров, а видео каналы ведут себя по-разному (кажется, что красный и синий исчезли). Есть ли разница в использовании другого формата? В настоящее время я использую AV_PIX_FMT_BGR24, который кажется правильным (я могу правильно визуализировать кадры из одного и того же указателя).
Спасибо за помощь!