• FFmpeg源代码简单分析-编码-avcodec_encode_video()已被send_frame 和 receive_packet替代


    参考链接

    avcodec_encode_video()

    send_frame 和 receive_packet 例子

    1. static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
    2. FILE *outfile)
    3. {
    4. int ret;
    5. /* send the frame to the encoder */
    6. if (frame)
    7. printf("Send frame %3"PRId64"\n", frame->pts);
    8. ret = avcodec_send_frame(enc_ctx, frame);
    9. if (ret < 0) {
    10. fprintf(stderr, "Error sending a frame for encoding\n");
    11. exit(1);
    12. }
    13. while (ret >= 0) {
    14. ret = avcodec_receive_packet(enc_ctx, pkt);
    15. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
    16. return;
    17. else if (ret < 0) {
    18. fprintf(stderr, "Error during encoding\n");
    19. exit(1);
    20. }
    21. printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
    22. fwrite(pkt->data, 1, pkt->size, outfile);
    23. av_packet_unref(pkt);
    24. }
    25. }
    • avcodec_encode_video一个函数即可完成编码操作,编码成功后可直接使用压缩后的数据。新版 API 需要两个函数一起使用,一个 send,一个 receive,分别用于发送原始视频数据、获取编码后的数据;具体在哪里完成了编码动作,暂时未知。
    • avcodec_encode_video 一次编码动作对应 0 个或 1 个 AVFrame 和 0 个或 1 个 AVPacket。新本 API 一次编码动作对应 0 个或 1 个 AVFrame 和 0 个或多个 AVPacket。 

    avcodec_send_frame

    • avcodec_send_frame 的声明如下:
    1. /**
    2. * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet()
    3. * to retrieve buffered output packets.
    4. *
    5. * @param avctx codec context
    6. * @param[in] frame AVFrame containing the raw audio or video frame to be encoded.
    7. * Ownership of the frame remains with the caller, and the
    8. * encoder will not write to the frame. The encoder may create
    9. * a reference to the frame data (or copy it if the frame is
    10. * not reference-counted).
    11. * It can be NULL, in which case it is considered a flush
    12. * packet. This signals the end of the stream. If the encoder
    13. * still has packets buffered, it will return them after this
    14. * call. Once flushing mode has been entered, additional flush
    15. * packets are ignored, and sending frames will return
    16. * AVERROR_EOF.
    17. *
    18. * For audio:
    19. * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame
    20. * can have any number of samples.
    21. * If it is not set, frame->nb_samples must be equal to
    22. * avctx->frame_size for all frames except the last.
    23. * The final frame may be smaller than avctx->frame_size.
    24. * @return 0 on success, otherwise negative error code:
    25. * AVERROR(EAGAIN): input is not accepted in the current state - user
    26. * must read output with avcodec_receive_packet() (once
    27. * all output is read, the packet should be resent, and
    28. * the call will not fail with EAGAIN).
    29. * AVERROR_EOF: the encoder has been flushed, and no new frames can
    30. * be sent to it
    31. * AVERROR(EINVAL): codec not opened, it is a decoder, or requires flush
    32. * AVERROR(ENOMEM): failed to add packet to internal queue, or similar
    33. * other errors: legitimate encoding errors
    34. */
    35. int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
    • 从注释中可以看出,这个函数用于发送原始的视频/音频数据给编码器编码,参数 AVFrame 同样可以为 NULL 以刷新编码器。

    1. int attribute_align_arg avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
    2. {
    3. AVCodecInternal *avci = avctx->internal;
    4. int ret;
    5. if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
    6. return AVERROR(EINVAL);
    7. if (avci->draining)
    8. return AVERROR_EOF;
    9. if (avci->buffer_frame->buf[0])
    10. return AVERROR(EAGAIN);
    11. if (!frame) {
    12. avci->draining = 1;
    13. } else {
    14. ret = encode_send_frame_internal(avctx, frame);
    15. if (ret < 0)
    16. return ret;
    17. }
    18. if (!avci->buffer_pkt->data && !avci->buffer_pkt->side_data) {
    19. ret = encode_receive_packet_internal(avctx, avci->buffer_pkt);
    20. if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
    21. return ret;
    22. }
    23. avctx->frame_number++;
    24. return 0;
    25. }

    avcodec_receive_packet

    • avcodec_receive_packet 则用于获取编码后的视频/音频数据。它的声明如下:
    1. /**
    2. * Read encoded data from the encoder.
    3. *
    4. * @param avctx codec context
    5. * @param avpkt This will be set to a reference-counted packet allocated by the
    6. * encoder. Note that the function will always call
    7. * av_packet_unref(avpkt) before doing anything else.
    8. * @return 0 on success, otherwise negative error code:
    9. * AVERROR(EAGAIN): output is not available in the current state - user
    10. * must try to send input
    11. * AVERROR_EOF: the encoder has been fully flushed, and there will be
    12. * no more output packets
    13. * AVERROR(EINVAL): codec not opened, or it is a decoder
    14. * other errors: legitimate encoding errors
    15. */
    16. int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
    1. int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
    2. {
    3. AVCodecInternal *avci = avctx->internal;
    4. int ret;
    5. av_packet_unref(avpkt);
    6. if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
    7. return AVERROR(EINVAL);
    8. if (avci->buffer_pkt->data || avci->buffer_pkt->side_data) {
    9. av_packet_move_ref(avpkt, avci->buffer_pkt);
    10. } else {
    11. ret = encode_receive_packet_internal(avctx, avpkt);
    12. if (ret < 0)
    13. return ret;
    14. }
    15. return 0;
    16. }

     注意事项

    • 旧版本视频编码使用 avcodec_encode_video2,音频编码使用 avcodec_encode_audio2;新版本音视频编码统一使用 avcodec_send_frame 和 avcodec_receive_packet
    • 旧版本 API 内部直接调用了 AVCodec 的函数指针 encode2;新版本 API 首先会判断编码器是否实现了函数指针 send_frame 和 receive_packet,如果实现了,优先使用send_frame 和 receive_packet,否则使用旧版本的 encode2    未找到代码证明,每个版本之间差异较大
    • 目前仅发现编码器 ff_hevc_nvenc_encoder 实现了新版本的 API(send_frame 和 receive_packet),libx264、AAC 等编码器依然使用了旧版本的 API(encode2)
    请使用手机"扫一扫"x
  • 相关阅读:
    Shell 未知汇总1
    (五)进程管理:进程的状态与控制
    Ubuntu 22.04配置/etc/rc.local开机自启文件
    python django在线考试系统796p5
    Qt基础开发之QString与QByteArray详细用法与区别及QString QByteArray互转
    第七章《Java的异常处理》第4节:throw与throws关键字
    文件防泄密系统如何保障企业文档的安全性?
    数据结构与算法(C语言版)P4---顺序表、链表总结
    python毕业设计作品基于django框架 电影院购票选座系统毕设成品(5)任务书
    我经历过的职场故事
  • 原文地址:https://blog.csdn.net/CHYabc123456hh/article/details/125409426