Api 如何使用ffmpeg av交织写入帧()写入x264编码器encode()生成的NAL

Api 如何使用ffmpeg av交织写入帧()写入x264编码器encode()生成的NAL,api,ffmpeg,decode,encode,x264,Api,Ffmpeg,Decode,Encode,X264,我一直在尝试按以下顺序制作“flv”视频文件: av_register_all(); // Open video file if (avformat_open_input(&pFormatCtx, "6.mp4", NULL, NULL) != 0) return -1; // Couldn't open file // Retrieve stream information if (avformat_find_stream_info(pFormatCtx, NULL) &l

我一直在尝试按以下顺序制作“flv”视频文件:

av_register_all();

// Open video file
if (avformat_open_input(&pFormatCtx, "6.mp4", NULL, NULL) != 0)
    return -1; // Couldn't open file

// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
    return -1; // Couldn't find stream information

// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, "input_file.mp4", 0);

// Find the first video stream
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
    if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
        videoStream = i;
        break;
    }
if (videoStream == -1)
    return -1; // Didn't find a video stream

// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;

// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    return -1; // Could not open codec

// Allocate video frame
pFrame = avcodec_alloc_frame();

// Allocate video frame
pFrame = avcodec_alloc_frame();

// Allocate an AVFrame structure
pFrameYUV420 = avcodec_alloc_frame();
if (pFrameYUV420 == NULL)
    return -1;

// Determine required buffer size and allocate buffer
numBytes = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));

// Assign appropriate parts of buffer to image planes in pFrameYUV420
// Note that pFrameYUV420 is an AVFrame, but AVFrame is a superset of AVPicture
avpicture_fill((AVPicture *) pFrameRGB, buffer, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);

// Setup scaler
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, SWS_BILINEAR, 0, 0, 0);
if (img_convert_ctx == NULL) {
    fprintf(stderr, "Cannot initialize the conversion context!\n");
    exit(1);
}

// Setup encoder/muxing now
filename = "output_file.flv";
fmt = av_guess_format("flv", filename, NULL);
if (fmt == NULL) {
    printf("Could not guess format.\n");
    return -1;
}
/* allocate the output media context */
oc = avformat_alloc_context();
if (oc == NULL) {
    printf("could not allocate context.\n");
    return -1;
}
oc->oformat = fmt;
snprintf(oc->filename, sizeof(oc->filename), "%s", filename);

video_st = NULL;
if (fmt->video_codec != AV_CODEC_ID_NONE) {
    video_st = add_stream(oc, &video_codec, fmt->video_codec);
}

// Let's see some information about our format
av_dump_format(oc, 0, filename, 1);

/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE)) {
    ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
    if (ret < 0) {
        fprintf(stderr, "Could not open '%s': %s\n", filename, av_err2str(ret));
        return 1;
    }
    }
/* Write the stream header, if any. */
ret = avformat_write_header(oc, NULL);
if (ret < 0) {
    fprintf(stderr, "Error occurred when opening output file: %s\n", av_err2str(ret));
    return 1;
}

// Setup x264 params
x264_param_t param;
x264_param_default_preset(&param, "veryfast", "zerolatency");
param.i_threads = 1;
param.i_width = video_st->codec->width;
param.i_height = video_st->codec->height;
param.i_fps_num = STREAM_FRAME_RATE; // 30 fps, same as video
param.i_fps_den = 1;
// Intra refres:
param.i_keyint_max = STREAM_FRAME_RATE;
param.b_intra_refresh = 1;
// Rate control:
param.rc.i_rc_method = X264_RC_CRF;
param.rc.f_rf_constant = 25;
param.rc.f_rf_constant_max = 35;
// For streaming:
param.b_repeat_headers = 1;
param.b_annexb = 1;
x264_param_apply_profile(&param, "baseline");

x264_t* encoder = x264_encoder_open(&param);
x264_picture_t pic_in, pic_out;
x264_picture_alloc(&pic_in, X264_CSP_I420, video_st->codec->width, video_st->codec->height);

x264_nal_t* nals;
int i_nals;

// The loop:
// 1. Read frames
// 2. Decode the frame
// 3. Attempt to re-encode using x264
// 4. Write the x264 encoded frame using av_interleaved_write_frame
while (av_read_frame(pFormatCtx, &packet) >= 0) {
    // Is this a packet from the video stream?
    if (packet.stream_index == videoStream) {
        // Decode video frame
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

        // Did we get a video frame?
        if (frameFinished) {
            sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pic_in.img.plane, pic_in.img.i_stride);
            int frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);

            if (frame_size >= 0) {
                if (i_nals < 0)
                    printf("invalid frame size: %d\n", i_nals);
                // write out NALs
                for (i = 0; i < i_nals; i++) {
                    // initalize a packet
                    AVPacket p;
                    av_init_packet(&p);
                    p.data = nals[i].p_payload;
                    p.size = nals[i].i_payload;
                    p.stream_index = video_st->index;
                    p.flags = AV_PKT_FLAG_KEY;
                    p.pts = AV_NOPTS_VALUE;
                    p.dts = AV_NOPTS_VALUE;
                    ret = av_interleaved_write_frame(oc, &p);
                }
            }
            printf("encoded frame #%d\n", frame_count);
            frame_count++;
        }
    }

    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
}

// Now we free up resources used/close codecs, and finally close our program.


编码完成后,我检查输出文件output\u file.flv。我注意到它的大小非常大:101MB,无法播放。如果我使用ffmpeg对输入文件进行解码/编码,那么我会得到一个大小约为83MB的输出文件(与用作输入的原始.mp4文件大小大致相同)。此外,仅使用ffmpeg C api(与使用x264进行编码步骤相反)产生的83MB输出效果良好。有人知道我哪里出错了吗?我已经尝试研究了几天,但没有成功:(。我觉得我很快就能让它工作了,但是,我就是不知道我做错了什么。谢谢!

要生成正确的AVPacket,你应该将所有NAL写入同一个包中,就像在(请参见
encode\u nals
X264\u frame
函数)

要生成正确的AV数据包,应将所有NAL写入同一数据包,就像在中所做的那样(请参见
encode\u nals
X264\u frame
函数)

为什么不使用ffmpeg中内置的libx264编解码器?在编码和解码结果文件期间写入ffmpeg输出。当我使用ffmpeg中内置的libx264时,我注意到比特率、最小/最大速率和bufsize不受尊重。我在尝试修复时尝试了:但没有成功。由于某些原因,比特率仍然不受尊重。因此我遇到了一个post有些地方指出我应该尝试直接使用x264。为什么不使用ffmpeg中内置的libx264编解码器?在编码和解码结果文件期间写入ffmpeg输出。当我使用ffmpeg中内置的libx264时,我注意到比特率、最小/最大速率和bufsize不受尊重。我在以下位置尝试了修复:但没有成功。比特率由于某些原因,我仍然不被认可。因此,我偶然看到一篇文章,其中指出我应该尝试直接使用x264。我今天将尝试使用此方法,并将结果反馈给您。谢谢!在尝试您的建议之前,我决定再次尝试使用ffmpeg中内置的libx264对视频进行编码。我注意到,只有当我输出到mp4容器。但是,如果我将文件输出到flv,那么比特率将不再受尊重。你知道为什么会这样吗?嗯,我注意到,对于任何不是mp4、f4v、mov的容器,比特率都不受尊重。Wmv、flv等格式出于某种原因不受比特率的尊重。奇怪的是,比特率ate取决于容器。编码器完全独立运行。我设法解决了一些问题。编码过程没有任何错误。但是,当我运行输出视频时,它没有显示任何内容,只是在随机位置显示了一堆线条/奇怪的颜色。我将在今晚或明天晚些时候发布我的实现。谢谢!我将尝试在尝试您的建议之前,我决定再次尝试使用ffmpeg中内置的libx264对视频进行编码。我注意到,只有当我将文件输出到mp4容器时,才会使用比特率。但是,如果我将文件输出到flv中,则不再使用比特率。您是否碰巧e知道为什么会这样吗?嗯,我注意到任何不是mp4、f4v、mov的容器都不遵守比特率。Wmv、Flv等格式出于某种原因不遵守比特率。奇怪的是,比特率取决于容器。编码器完全独立运行。我设法解决了一些问题。编码继续进行虽然没有任何错误。但是,当我运行输出视频时,它没有显示任何内容,只是在随机的地方显示了一堆线条/奇怪的颜色。我将在今晚晚些时候或明天发布我的实现。谢谢!
/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id) {
    AVCodecContext *c;
    AVStream *st;
    int r;
    /* find the encoder */
    *codec = avcodec_find_encoder(codec_id);
    if (!(*codec)) {
        fprintf(stderr, "Could not find encoder for '%s'\n",
                avcodec_get_name(codec_id));
        exit(1);
    }
    st = avformat_new_stream(oc, *codec);
    if (!st) {
        fprintf(stderr, "Could not allocate stream\n");
        exit(1);
    }
    st->id = oc->nb_streams - 1;
    c = st->codec;
    switch ((*codec)->type) {
    case AVMEDIA_TYPE_AUDIO:
        st->id = 1;
        c->sample_fmt = AV_SAMPLE_FMT_FLTP;
        c->bit_rate = 64000;
        c->sample_rate = 44100;
        c->channels = 2;
        break;
    case AVMEDIA_TYPE_VIDEO:
        avcodec_get_context_defaults3(c, *codec);
        c->codec_id = codec_id;
        c->bit_rate = 500*1000;
        //c->rc_min_rate = 500*1000;
        //c->rc_max_rate = 500*1000;
        //c->rc_buffer_size = 500*1000;
        /* Resolution must be a multiple of two. */
        c->width = 1280;
        c->height = 720;
        /* timebase: This is the fundamental unit of time (in seconds) in terms
         * of which frame timestamps are represented. For fixed-fps content,
         * timebase should be 1/framerate and timestamp increments should be
         * identical to 1. */
        c->time_base.den = STREAM_FRAME_RATE;
        c->time_base.num = 1;
        c->gop_size = 12; /* emit one intra frame every twelve frames at most */
        c->pix_fmt = STREAM_PIX_FMT;
        if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
            /* just for testing, we also add B frames */
            c->max_b_frames = 2;
        }
        if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
            /* Needed to avoid using macroblocks in which some coeffs overflow.
             * This does not happen with normal video, it just happens here as
             * the motion of the chroma plane does not match the luma plane. */
            c->mb_decision = 2;
        }
        break;
    default:
        break;
    }
    /* Some formats want stream headers to be separate. */
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        c->flags |= CODEC_FLAG_GLOBAL_HEADER;
    return st;
}