mux / remux / box в памяти h264 фреймы в mp4 через C / C ++ (без ffmpeg cmdline) - PullRequest
0 голосов
/ 28 февраля 2019

Я посмотрел различные учебные пособия и все еще пытаюсь правильно скомпоновать raw h264 в контейнер mp4.Проблема в том, что поток не имеет конца (в реальном времени) и находится в памяти, во многих доступных примерах мультиплексоров предполагается, что потоки расположены на диске в виде файлов.

Я пробовал и смотрел http://www.ffmpeg.org/doxygen/trunk/doc_2examples_2remuxing_8c-example.html
https://ffmpeg.org/doxygen/trunk/muxing_8c-source.html
и бесчисленное множество других примеров.

Вот что у меня сейчас:

AVFormatContext *outFmtCtx = NULL;
AVFormatContext *inFmtCtx = NULL;
std::vector<uint8_t> g_p;

static int read_packet(void *opaque, uint8_t *pBuf, int nBuf) {
    printf("read_packet %d\n", g_p.size());
    memcpy(pBuf, &g_p[0], g_p.size());
    return g_p.size();
}

static int write_packet(void *opaque, uint8_t *buf, int buf_size) {
    printf("write_packet %d %lld\n", buf_size, timestamp_micro());
    return buf_size;
}

static int64_t seek_packet(void *opaque, int64_t offset, int whence) {
    printf("seek_packet\n");
    exit(0);
    return 0;
}

void create_mp4() {
    av_log_set_level(AV_LOG_DEBUG);

    //alloc memory buffer
    uint8_t *avioc_buffer = NULL;
    int avioc_buffer_size = 8 * 1024 * 1024;
    avioc_buffer = (uint8_t *)av_malloc(avioc_buffer_size);
    if (!avioc_buffer) {
        printf("failed make avio buffer\n");
        exit(1);
    }
    AVIOContext* pIOCtx = avio_alloc_context(avioc_buffer, avioc_buffer_size, 1, 
        NULL/*outptr*/, &read_packet, &write_packet, &seek_packet);
    if (!pIOCtx) {
        printf("failed make avio context\n");
        exit(1);
    }

    inFmtCtx = avformat_alloc_context();
    inFmtCtx->pb = pIOCtx;
    inFmtCtx->iformat = av_find_input_format("h264");
    avformat_open_input(&inFmtCtx, "", inFmtCtx->iformat, NULL);

    AVOutputFormat* outFmt = av_guess_format("mp4", NULL, NULL);
    avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL);

    //set the AIO buffer to the memory one
    outFmtCtx->pb = pIOCtx;
    //outFmtCtx->flags = AVFMT_FLAG_CUSTOM_IO;//pIOCtx;

    AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    AVStream * outStrm = avformat_new_stream(outFmtCtx, codec);

    avcodec_get_context_defaults3(outStrm->codec, codec);
    outStrm->id = 0;
    outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO;
    outStrm->codec->codec_id = AV_CODEC_ID_H264;
    outStrm->codec->bit_rate = 8000000;
    outStrm->codec->width = 1280;
    outStrm->codec->height = 720;
    outStrm->codec->time_base.den = 60;
    outStrm->codec->time_base.num = 1;
    outStrm->codec->gop_size = 0xffffffff;
    outStrm->codec->pix_fmt = AV_PIX_FMT_NV12;
    outStrm->duration = 0;

    //Allow it to play immediately
    AVDictionary* options = nullptr;
    av_dict_set( &options, "movflags", "empty_moov+default_base_moof+frag_keyframe", 0 );

    avformat_write_header(outFmtCtx, &options);
    printf("mp4 muxer created\n");
}

//set the first raw h264 frame from capture
g_p = raw_h264_frame;
AVPacket pkt;
//call av_read_frame (infinite loop here on read_packet)
int wret = av_read_frame(inFmtCtx, &pkt);

Я получаю бесконечный цикл на read_packet после вызова av_read_frame, я пыталсячтобы создать пакеты самостоятельно, также выполнив

AVPacket pkt;
av_init_packet(&pkt);
if (nFrame == 0) {
    pkt.flags        |= AV_PKT_FLAG_KEY;
}
pkt.stream_index  = 0;
pkt.data          = &raw_h264_frame[0];
pkt.size          = raw_h264_frame.size();
//pkt.dts = AV_NOPTS_VALUE;
//pkt.pts = AV_NOPTS_VALUE;
pkt.dts = nFrame;
pkt.pts = nFrame;

int ret = av_interleaved_write_frame(outFmtCtx, &pkt);
if (ret < 0) {
    printf("error av_write_frame\n");
    exit(1);
}

Но это тоже не работает.Буду признателен за некоторую помощь или руководство, где искать (возможно, сбросьте libFFMPEG и посмотрите где-нибудь еще, и т. Д.).

Ошибки VLC выглядят так:

mp4 warning: out of bound child    �
mp4 warning: out of bound child    �
mp4 warning: no chunk defined
mp4 warning: STTS table of 0 entries
mp4 warning: cannot select track[Id 0x1]

или

mp4 warning: no chunk defined
mp4 warning: STTS table of 0 entries
mp4: Fragment sequence discontinuity detected 1 != 0
avcodec warning: thread type 1: disabling hardware acceleration
main warning: picture is too late to be displayed (missing 14 ms)
main warning: picture is too late to be displayed (missing 14 ms)
main warning: picture is too late to be displayed (missing 14 ms)
...