FFmpeg播放一个MP4文件 C/C++实现
时间: 2024-01-26 18:03:55 浏览: 25
你可以使用FFmpeg库中的AVFormatContext和AVCodecContext来打开和解码MP4文件,并使用SDL或其他音视频播放库来播放解码后的音视频帧。
以下是一个简单的C++示例代码,可以使用FFmpeg和SDL播放MP4文件:
```c++
#include <iostream>
#include <SDL2/SDL.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
}
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
return -1;
}
const char* filename = argv[1];
av_register_all();
avcodec_register_all();
AVFormatContext* format_ctx = nullptr;
if (avformat_open_input(&format_ctx, filename, nullptr, nullptr) < 0) {
std::cerr << "Failed to open input file: " << filename << std::endl;
return -1;
}
if (avformat_find_stream_info(format_ctx, nullptr) < 0) {
std::cerr << "Failed to find stream information" << std::endl;
return -1;
}
int video_stream_index = -1;
for (unsigned int i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
std::cerr << "Failed to find video stream" << std::endl;
return -1;
}
AVCodecParameters* codecpar = format_ctx->streams[video_stream_index]->codecpar;
AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
if (!codec) {
std::cerr << "Failed to find codec" << std::endl;
return -1;
}
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
std::cerr << "Failed to allocate codec context" << std::endl;
return -1;
}
if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
std::cerr << "Failed to copy codec parameters to context" << std::endl;
return -1;
}
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
std::cerr << "Failed to open codec" << std::endl;
return -1;
}
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window* window = SDL_CreateWindow("Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, codec_ctx->width, codec_ctx->height, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, codec_ctx->width, codec_ctx->height);
AVPacket packet;
av_init_packet(&packet);
packet.data = nullptr;
packet.size = 0;
AVFrame* frame = av_frame_alloc();
AVFrame* frame_rgb = av_frame_alloc();
uint8_t* buffer = nullptr;
int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
buffer = (uint8_t*)av_malloc(num_bytes * sizeof(uint8_t));
av_image_fill_arrays(frame_rgb->data, frame_rgb->linesize, buffer, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
struct SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);
int frame_finished;
while (av_read_frame(format_ctx, &packet) >= 0) {
if (packet.stream_index == video_stream_index) {
if (avcodec_send_packet(codec_ctx, &packet) < 0) {
std::cerr << "Failed to send packet to codec context" << std::endl;
return -1;
}
while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height, frame_rgb->data, frame_rgb->linesize);
SDL_UpdateTexture(texture, nullptr, frame_rgb->data[0], frame_rgb->linesize[0]);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_RenderPresent(renderer);
av_frame_unref(frame);
}
}
av_packet_unref(&packet);
}
av_free(buffer);
av_frame_free(&frame);
av_frame_free(&frame_rgb);
avcodec_close(codec_ctx);
avformat_close_input(&format_ctx);
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
```
注意:这只是一个简单的示例代码,实际生产环境中需要进行更多的错误检查和错误处理。