Как правильно писать фреймы в ffmpeg? - PullRequest
0 голосов
/ 06 февраля 2020

Я работаю над реализацией некоторых писателей 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, который кажется правильным (я могу правильно визуализировать кадры из одного и того же указателя).

Спасибо за помощь!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...