- static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
- FILE *outfile)
- {
- int ret;
-
- /* send the frame to the encoder */
- if (frame)
- printf("Send frame %3"PRId64"\n", frame->pts);
-
- ret = avcodec_send_frame(enc_ctx, frame);
- if (ret < 0) {
- fprintf(stderr, "Error sending a frame for encoding\n");
- exit(1);
- }
-
- while (ret >= 0) {
- ret = avcodec_receive_packet(enc_ctx, pkt);
- if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
- return;
- else if (ret < 0) {
- fprintf(stderr, "Error during encoding\n");
- exit(1);
- }
-
- printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
- fwrite(pkt->data, 1, pkt->size, outfile);
- av_packet_unref(pkt);
- }
- }
- /**
- * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet()
- * to retrieve buffered output packets.
- *
- * @param avctx codec context
- * @param[in] frame AVFrame containing the raw audio or video frame to be encoded.
- * Ownership of the frame remains with the caller, and the
- * encoder will not write to the frame. The encoder may create
- * a reference to the frame data (or copy it if the frame is
- * not reference-counted).
- * It can be NULL, in which case it is considered a flush
- * packet. This signals the end of the stream. If the encoder
- * still has packets buffered, it will return them after this
- * call. Once flushing mode has been entered, additional flush
- * packets are ignored, and sending frames will return
- * AVERROR_EOF.
- *
- * For audio:
- * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame
- * can have any number of samples.
- * If it is not set, frame->nb_samples must be equal to
- * avctx->frame_size for all frames except the last.
- * The final frame may be smaller than avctx->frame_size.
- * @return 0 on success, otherwise negative error code:
- * AVERROR(EAGAIN): input is not accepted in the current state - user
- * must read output with avcodec_receive_packet() (once
- * all output is read, the packet should be resent, and
- * the call will not fail with EAGAIN).
- * AVERROR_EOF: the encoder has been flushed, and no new frames can
- * be sent to it
- * AVERROR(EINVAL): codec not opened, it is a decoder, or requires flush
- * AVERROR(ENOMEM): failed to add packet to internal queue, or similar
- * other errors: legitimate encoding errors
- */
- int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
从注释中可以看出,这个函数用于发送原始的视频/音频数据给编码器编码,参数 AVFrame 同样可以为 NULL 以刷新编码器。
- int attribute_align_arg avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
- {
- AVCodecInternal *avci = avctx->internal;
- int ret;
-
- if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
- return AVERROR(EINVAL);
-
- if (avci->draining)
- return AVERROR_EOF;
-
- if (avci->buffer_frame->buf[0])
- return AVERROR(EAGAIN);
-
- if (!frame) {
- avci->draining = 1;
- } else {
- ret = encode_send_frame_internal(avctx, frame);
- if (ret < 0)
- return ret;
- }
-
- if (!avci->buffer_pkt->data && !avci->buffer_pkt->side_data) {
- ret = encode_receive_packet_internal(avctx, avci->buffer_pkt);
- if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
- return ret;
- }
-
- avctx->frame_number++;
-
- return 0;
- }
- /**
- * Read encoded data from the encoder.
- *
- * @param avctx codec context
- * @param avpkt This will be set to a reference-counted packet allocated by the
- * encoder. Note that the function will always call
- * av_packet_unref(avpkt) before doing anything else.
- * @return 0 on success, otherwise negative error code:
- * AVERROR(EAGAIN): output is not available in the current state - user
- * must try to send input
- * AVERROR_EOF: the encoder has been fully flushed, and there will be
- * no more output packets
- * AVERROR(EINVAL): codec not opened, or it is a decoder
- * other errors: legitimate encoding errors
- */
- int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
- int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
- {
- AVCodecInternal *avci = avctx->internal;
- int ret;
-
- av_packet_unref(avpkt);
-
- if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec))
- return AVERROR(EINVAL);
-
- if (avci->buffer_pkt->data || avci->buffer_pkt->side_data) {
- av_packet_move_ref(avpkt, avci->buffer_pkt);
- } else {
- ret = encode_receive_packet_internal(avctx, avpkt);
- if (ret < 0)
- return ret;
- }
-
- return 0;
- }