返回

FFmpeg之new_video_stream添加视频输出流

前端

FFmpeg简介

FFmpeg是一个开源的跨平台多媒体框架,可以处理各种各样的音频和视频格式。它可以用于视频编码、解码、转码、复用、解复用、流媒体等多种用途。FFmpeg支持多种协议,包括HTTP、FTP、RTSP、RTMP等。

new_video_stream()函数概述

new_video_stream()函数用于向一个输出媒体流添加一个新的视频流。该函数的流程相对来说比较简单,主要的逻辑如下:

  1. 调用new_output_stream()函数来创建OutputStream输出流。
  2. 调用avcodec_find_encoder()函数来查找一个合适的视频编码器。
  3. 调用avcodec_alloc_context3()函数来分配一个AVCodecContext结构体。
  4. 调用avcodec_parameters_to_context()函数将AVCodecParameters结构体中的参数复制到AVCodecContext结构体中。
  5. 调用avcodec_open2()函数来打开视频编码器。
  6. 调用av_new_stream()函数来创建一个新的视频流。
  7. 将视频编码器和视频流关联起来。
  8. 返回视频流的索引。

new_video_stream()函数语法

AVStream *avformat_new_video_stream(AVFormatContext *s, AVCodec *codec)

new_video_stream()函数参数

参数 类型 说明
s AVFormatContext * 输出媒体流的上下文
codec AVCodec * 视频编码器

new_video_stream()函数返回值

如果成功,则返回视频流的索引;否则,返回NULL。

new_video_stream()函数示例

#include <libavformat/avformat.h>

int main() {
  AVFormatContext *fmt_ctx = NULL;
  AVStream *video_stream = NULL;
  AVCodec *video_codec = NULL;
  AVCodecContext *video_codec_ctx = NULL;

  // 打开输入媒体文件
  if (avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL) < 0) {
    fprintf(stderr, "Could not open input file.\n");
    return -1;
  }

  // 查找视频编码器
  video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
  if (!video_codec) {
    fprintf(stderr, "Could not find video encoder.\n");
    return -1;
  }

  // 分配AVCodecContext结构体
  video_codec_ctx = avcodec_alloc_context3(video_codec);
  if (!video_codec_ctx) {
    fprintf(stderr, "Could not allocate video codec context.\n");
    return -1;
  }

  // 将AVCodecParameters结构体中的参数复制到AVCodecContext结构体中
  if (avcodec_parameters_to_context(video_codec_ctx, fmt_ctx->streams[0]->codecpar) < 0) {
    fprintf(stderr, "Could not copy codec parameters.\n");
    return -1;
  }

  // 打开视频编码器
  if (avcodec_open2(video_codec_ctx, video_codec, NULL) < 0) {
    fprintf(stderr, "Could not open video encoder.\n");
    return -1;
  }

  // 创建一个新的视频流
  video_stream = avformat_new_video_stream(fmt_ctx, video_codec);
  if (!video_stream) {
    fprintf(stderr, "Could not create video stream.\n");
    return -1;
  }

  // 将视频编码器和视频流关联起来
  video_stream->codec = video_codec_ctx;

  // 写入输出媒体文件
  if (avformat_write_header(fmt_ctx, NULL) < 0) {
    fprintf(stderr, "Could not write header.\n");
    return -1;
  }

  // 写入视频数据
  while (1) {
    AVPacket pkt;

    // 从输入媒体文件中读取一帧视频数据
    if (av_read_frame(fmt_ctx, &pkt) < 0) {
      break;
    }

    // 将视频数据编码成H.264格式
    if (pkt.stream_index == 0) {
      if (avcodec_send_frame(video_codec_ctx, &pkt) < 0) {
        fprintf(stderr, "Could not send frame to encoder.\n");
        return -1;
      }

      while (1) {
        AVPacket enc_pkt;

        // 从编码器中获取编码后的视频数据
        if (avcodec_receive_packet(video_codec_ctx, &enc_pkt) < 0) {
          break;
        }

        // 将编码后的视频数据写入输出媒体文件中
        if (av_interleaved_write_frame(fmt_ctx, &enc_pkt) < 0) {
          fprintf(stderr, "Could not write frame.\n");
          return -1;
        }

        av_packet_unref(&enc_pkt);
      }
    }

    av_packet_unref(&pkt);
  }

  // 写入输出媒体文件的尾部
  if (av_write_trailer(fmt_ctx) < 0) {
    fprintf(stderr, "Could not write trailer.\n");
    return -1;
  }

  // 释放资源
  avcodec_close(video_codec_ctx);
  avformat_free_context(fmt_ctx);

  return 0;
}

new_video_stream()函数应用场景

new_video_stream()函数可以用于多种场景,包括:

  • 视频转码:将一种格式的视频转码成另一种格式的视频。
  • 视频复用:将多个视频流复用成一个视频文件。
  • 视频解复用:将一个视频文件解复用成多个视频流。
  • 视频流媒体:将视频流传输到客户端进行播放。