21xrx.com
2024-07-20 18:17:42 Saturday
登录
文章检索 我的文章 写文章
使用FFmpeg实时播放本地文件
2024-05-19 15:55:38 深夜i     --     --
FFmpeg 实时播放 本地文件

FFmpeg是一种广泛使用的开源多媒体框架,它提供了许多强大的功能,包括音视频编解码、转换、流媒体传输等。其中,实时播放本地文件是FFmpeg的一个重要应用之一。在本文中,我们将介绍如何使用FFmpeg来实现这一功能。

首先,我们需要安装FFmpeg。你可以在FFmpeg的官方网站上下载并安装它。安装完成后,我们就可以开始写代码了。

在开始之前,我们先创建一个示例的本地视频文件。假设我们的视频文件名为"example.mp4"。请确保你的文件路径正确,并且已经下载并保存了相应的视频文件。

下面是一个使用FFmpeg实时播放本地文件的示例代码:


#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#define READ_SIZE 2048

int main(int argc, char** argv) {

  if (argc != 2) {

    printf("Usage: %s <input_file>\n", argv[0]);

    return 1;

  }

  char* input_file = argv[1];

  // 创建FFmpeg输入上下文

  AVFormatContext* format_context = avformat_alloc_context();

  if (!format_context) {

    printf("Failed to allocate AVFormatContext\n");

    return 1;

  }

  // 打开输入文件

  if (avformat_open_input(&format_context, input_file, NULL, NULL) != 0) {

    printf("Failed to open input file\n");

    return 1;

  }

  // 查找流信息

  if (avformat_find_stream_info(format_context, NULL) < 0) {

    printf("Failed to find stream info\n");

    return 1;

  }

  // 查找音视频流

  int video_stream_index = -1;

  int audio_stream_index = -1;

  for (int i = 0; i < format_context->nb_streams; i++) {

    if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_stream_index == -1)

      video_stream_index = i;

     else if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_stream_index == -1)

      audio_stream_index = i;

    

  }

  // 检查是否找到音视频流

  if (video_stream_index == -1 || audio_stream_index == -1) {

    printf("Failed to find video or audio stream\n");

    return 1;

  }

  // 创建解码器上下文

  AVCodecContext* video_codec_context = avcodec_alloc_context3(NULL);

  if (!video_codec_context) {

    printf("Failed to allocate AVCodecContext\n");

    return 1;

  }

  AVCodecContext* audio_codec_context = avcodec_alloc_context3(NULL);

  if (!audio_codec_context) {

    printf("Failed to allocate AVCodecContext\n");

    return 1;

  }

  // 复制流参数到解码器上下文

  if (avcodec_parameters_to_context(video_codec_context, format_context->streams[video_stream_index]->codecpar) < 0) {

    printf("Failed to copy video codec parameters\n");

    return 1;

  }

  

  if (avcodec_parameters_to_context(audio_codec_context, format_context->streams[audio_stream_index]->codecpar) < 0) {

    printf("Failed to copy audio codec parameters\n");

    return 1;

  }

  // 查找解码器

  AVCodec* video_codec = avcodec_find_decoder(video_codec_context->codec_id);

  if (!video_codec) {

    printf("Failed to find video codec\n");

    return 1;

  }

  AVCodec* audio_codec = avcodec_find_decoder(audio_codec_context->codec_id);

  if (!audio_codec) {

    printf("Failed to find audio codec\n");

    return 1;

  }

  // 打开解码器

  if (avcodec_open2(video_codec_context, video_codec, NULL) < 0) {

    printf("Failed to open video codec\n");

    return 1;

  }

  if (avcodec_open2(audio_codec_context, audio_codec, NULL) < 0) {

    printf("Failed to open audio codec\n");

    return 1;

  }

  // 创建帧对象

  AVFrame* video_frame = av_frame_alloc();

  if (!video_frame) {

    printf("Failed to allocate video frame\n");

    return 1;

  }

  AVFrame* audio_frame = av_frame_alloc();

  if (!audio_frame) {

    printf("Failed to allocate audio frame\n");

    return 1;

  }

  // 创建数据包对象

  AVPacket* packet = av_packet_alloc();

  if (!packet) {

    printf("Failed to allocate packet\n");

    return 1;

  }

  // 初始化转换器

  SwsContext* sws_context = sws_getContext(video_codec_context->width, video_codec_context->height, video_codec_context->pix_fmt,

                       video_codec_context->width, video_codec_context->height, AV_PIX_FMT_RGB24,

                       SWS_BILINEAR, NULL, NULL, NULL);

  if (!sws_context) {

    printf("Failed to initialize sws context\n");

    return 1;

  }

  // 初始化音频转换器

  SwrContext* swr_context = swr_alloc();

  if (!swr_context) {

    printf("Failed to allocate swr context\n");

    return 1;

  }

  // 设置音频转换器参数

  av_opt_set_int(swr_context, "in_channel_layout", audio_codec_context->channel_layout, 0);

  av_opt_set_int(swr_context, "in_sample_rate", audio_codec_context->sample_rate, 0);

  av_opt_set_sample_fmt(swr_context, "in_sample_fmt", audio_codec_context->sample_fmt, 0);

  av_opt_set_int(swr_context, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);

  av_opt_set_int(swr_context, "out_sample_rate", 44100, 0);

  av_opt_set_sample_fmt(swr_context, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);

  // 初始化音频转换器

  if (swr_init(swr_context) < 0) {

    printf("Failed to initialize swr context\n");

    return 1;

  }

  // 创建音频播放器

  SDL_Init(SDL_INIT_AUDIO);

  SDL_AudioSpec wanted_spec;

  SDL_AudioSpec obtained_spec;

  wanted_spec.freq = audio_codec_context->sample_rate;

  wanted_spec.format = AUDIO_S16SYS;

  wanted_spec.channels = audio_codec_context->channels;

  wanted_spec.silence = 0;

  wanted_spec.samples = 1024;

  wanted_spec.callback = audio_callback;

  wanted_spec.userdata = audio_codec_context;

  if (SDL_OpenAudio(&wanted_spec, &obtained_spec) < 0) {

    printf("Failed to open audio device\n");

    return 1;

  }

  SDL_PauseAudio(0);

  // 开始播放

  while (av_read_frame(format_context, packet) >= 0) {

    if (packet->stream_index == video_stream_index) {

      avcodec_send_packet(video_codec_context, packet);

      avcodec_receive_frame(video_codec_context, video_frame);

      // 处理视频帧

      // ...

    } else if (packet->stream_index == audio_stream_index) {

      avcodec_send_packet(audio_codec_context, packet);

      avcodec_receive_frame(audio_codec_context, audio_frame);

      // 处理音频帧

      // ...

    }

    av_packet_unref(packet);

  }

  // 清理资源

  av_frame_free(&video_frame);

  av_frame_free(&audio_frame);

  av_packet_free(&packet);

  avcodec_close(video_codec_context);

  avcodec_close(audio_codec_context);

  avformat_close_input(&format_context);

  return 0;

}

上面的代码是一个简单的FFmpeg实时播放本地文件的示例。在代码中,我们使用了FFmpeg的一些函数来读取视频文件、查找和打开音视频流、创建解码器和转换器等。在读取帧数据后,我们可以根据需要对音视频帧进行处理和显示。

需要注意的是,上面的代码仅仅是一个示例,你需要根据你自己的需求进行适当的修改和扩展。例如,你可能需要添加适当的错误处理、音视频帧的解码和显示,以及控制播放速度等功能。

总结起来,使用FFmpeg实时播放本地文件是一项非常有趣且有趣的任务。通过掌握FFmpeg的相关知识和使用相关函数,我们可以很容易地实现这一功能。希望本文能够帮助你了解如何使用FFmpeg来实现实时播放本地文件的功能。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复