【ffmpeg】ffmpeg+SDL实现播放器

时间:2025-03-09 09:33:17
// 视频分辨率 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;