【ffmpeg】ffmpeg+SDL实现播放器
// 视频分辨率
int vWidth = s_vWidth;
int vHeight = s_vHeight;
// 窗口的分辨率
int sdlWidth = s_vWidth;
int sdlHeight = s_vHeight;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
cout << "initialize SDL failed" << endl;
return ret;
}
if (avformat_open_input(&pFormatCtx, file, 0, nullptr) != 0) {
cout << "open the video file failed!" << endl;
return 0;
}
videostream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1,
nullptr, 0);
if (videostream == -1) {
cout << "open a video stream failed!" << endl;
return 0;
}
pCodec = avcodec_find_decoder(
pFormatCtx->streams[videostream]->codecpar->codec_id);
if (pCodec == nullptr) {
cout << "find a codec failed!" << endl;
return 0;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_parameters_to_context(pCodecCtx,
pFormatCtx->streams[videostream]->codecpar) != 0) {
cout << "copy codec context failed!" << endl;
return 0;
}
if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0) {
cout << "open the decoder failed!" << endl;
return 0;
}
pFrame = av_frame_alloc();
// 获得显示的视频画面的长度与宽度
vWidth = pCodecCtx->width;
vHeight = pCodecCtx->height;
// 创建窗口
window = SDL_CreateWindow("SDL PLAYER",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
vWidth, vHeight,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!window) {
cout << "create window failed!" << endl;
return 0;
}
// 创建render
renderer = SDL_CreateRenderer(window, -1, 0);
if (!renderer) {
cout << "create renderer failed!" << endl;
return 0;
}
// 视频格式设置为SDL_PIXELFORMAT_IYUV
pixformat = SDL_PIXELFORMAT_IYUV;
// 创建纹理
texture = SDL_CreateTexture(renderer,
pixformat,
SDL_TEXTUREACCESS_STREAMING,
vWidth,
vHeight);
// 创建SDL线程
timer_thread = SDL_CreateThread(refresh_video_timer, nullptr, nullptr);
// 主循环
while (1) {
// 无限期等待下一个可用事件
SDL_WaitEvent(&event);
if (event.type == REFRESH_EVENT) {// 画面刷新事件
// 每次只需要读取一个packet
while (1) {
// 如果已经读取完所有的帧,则退出
if (av_read_frame(pFormatCtx, &packet) < 0) {
s_thread_exit = 1;
}
// 读取的是视频帧就退出
if (packet.stream_index == videostream) {
break;
}
}
// 将一个packet进行解码操作
avcodec_send_packet(pCodecCtx, &packet);
// 将frame进行读取
while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {
// 刷新纹理
SDL_UpdateYUVTexture(texture, NULL,
pFrame->data[0], pFrame->linesize[0],
pFrame->data[1], pFrame->linesize[1],
pFrame->data[2], pFrame->linesize[2]);
// 设置渲染目标的显示区域
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
// 清空渲染器内容
SDL_RenderClear(renderer);
// 将纹理复制到渲染器
SDL_RenderCopy(renderer, texture, NULL, &rect);
// 渲染
SDL_RenderPresent(renderer);
}
// 将packet内容清空
av_packet_unref(&packet);
} else if (event.type == SDL_WINDOWEVENT) { // 如果窗口出现了调整
SDL_GetWindowSize(window, &sdlWidth, &sdlHeight);
} else if (event.type == SDL_QUIT) { // 如果窗口被关闭
s_thread_exit = 1;// 退出画面刷新线程
} else if (event.type == QUIT_EVENT) { // 退出主线程循环
break;
}
}
// 释放所有内存
if (pFrame) {
av_frame_free(&pFrame);
pFrame = nullptr;
}
if (pCodecCtx) {
avcodec_close(pCodecCtx);
pCodecCtx = nullptr;
pCodec = nullptr;
}
if (pFormatCtx) {
avformat_close_input(&pFormatCtx);
pFormatCtx = nullptr;
}
if (pCodeParameters) {
avcodec_parameters_free(&pCodeParameters);
pCodeParameters = nullptr;
}
if (texture) {
SDL_DestroyTexture(texture);
texture = nullptr;
}
if (renderer) {
SDL_DestroyRenderer(renderer);
renderer = nullptr;
}
if (window) {
SDL_DestroyWindow(window);
window = nullptr;
}
SDL_Quit();
return ret;