[FFmpeg学习]初级的SDL播放mp4测试

2024-06-11 04:52

本文主要是介绍[FFmpeg学习]初级的SDL播放mp4测试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在之前的学习中,通过AVFrame来保存为图片来认识了AVFrame,

[FFmpeg学习]从视频中获取图片_ffmpeg 获取图片-CSDN博客

在获取到AVFrame时,还可以调用SDL方法来进行展现,实现播放效果。

参考资料

SDL,ffmpeg实现简单视频播放器_ffmpeg sdl 播放器-CSDN博客

SDL2 简单介绍以及Windows开发环境搭建-CSDN博客

这里只显示了视频,没有处理声音,

// ffmpegTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>/*
int main()
{std::cout << "Hello World!\n";
}*/extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include <libavutil/log.h>
#include <libavformat/avformat.h>
}using namespace std;//要使用FFmpeg库从MP4文件中提取一张图片,你需要使用FFmpeg的解码器来读取视频帧,并将其保存为图片。以下是一个简单的示例程序,演示如何使用FFmpeg库从MP4文件中提取一张图片:
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  #include "SDL.h"int savePicture(AVFrame* pFrame, char* out_name) {//编码保存图片int width = pFrame->width;int height = pFrame->height;AVCodecContext* pCodeCtx = NULL;AVFormatContext* pFormatCtx = avformat_alloc_context();// 设置输出文件格式pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);// 创建并初始化输出AVIOContextif (avio_open(&pFormatCtx->pb, out_name, AVIO_FLAG_READ_WRITE) < 0) {printf("Couldn't open output file.");return -1;}// 构建一个新streamAVStream* pAVStream = avformat_new_stream(pFormatCtx, 0);if (pAVStream == NULL) {return -1;}AVCodecParameters* parameters = pAVStream->codecpar;parameters->codec_id = pFormatCtx->oformat->video_codec;parameters->codec_type = AVMEDIA_TYPE_VIDEO;parameters->format = AV_PIX_FMT_YUVJ420P;parameters->width = pFrame->width;parameters->height = pFrame->height;const AVCodec* pCodec = avcodec_find_encoder(pAVStream->codecpar->codec_id);  //查找编码器if (!pCodec) {printf("Could not find encoder\n");return -1;}pCodeCtx = avcodec_alloc_context3(pCodec);   //为AVCodecContext分配内存if (!pCodeCtx) {fprintf(stderr, "Could not allocate video codec context\n");exit(1);}if ((avcodec_parameters_to_context(pCodeCtx, pAVStream->codecpar)) < 0) {fprintf(stderr, "Failed to copy %s codec parameters to decoder context\n",av_get_media_type_string(AVMEDIA_TYPE_VIDEO));return -1;}//  AVRational tmp = { 1, 25 };pCodeCtx->time_base = { 1, 25 };if (avcodec_open2(pCodeCtx, pCodec, NULL) < 0) {   //打开编码器printf("Could not open codec.");return -1;}int ret = avformat_write_header(pFormatCtx, NULL);if (ret < 0) {printf("write_header fail\n");return -1;}int y_size = width * height;//Encode// 给AVPacket分配足够大的空间AVPacket pkt;av_new_packet(&pkt, y_size * 3);// 编码数据ret = avcodec_send_frame(pCodeCtx, pFrame);if (ret < 0) {printf("Could not avcodec_send_frame.");return -1;}// 得到编码后数据ret = avcodec_receive_packet(pCodeCtx, &pkt);if (ret < 0) {printf("Could not avcodec_receive_packet");return -1;}ret = av_write_frame(pFormatCtx, &pkt);if (ret < 0) {printf("Could not av_write_frame");return -1;}av_packet_unref(&pkt);//Write Trailerav_write_trailer(pFormatCtx);avcodec_close(pCodeCtx);avio_close(pFormatCtx->pb);avformat_free_context(pFormatCtx);return 0;
}class SDLHandle
{
public:SDLHandle(int w, int h){m_rect.x = 0;m_rect.y = 0;m_rect.w = w;m_rect.h = h;SdlInit();}~SDLHandle(){if (m_pTexture){SDL_DestroyTexture(m_pTexture);}if (m_pRender){SDL_DestroyRenderer(m_pRender);}if (m_pWnd){SDL_DestroyWindow(m_pWnd);}SDL_Quit();}bool CreateSDLWindow(const char* title, Uint32 flag){m_pWnd = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_rect.w, m_rect.h, flag);if (!m_pWnd){printf("CreateWindows error:%s.\n", SDL_GetError());return false;}m_pRender = SDL_CreateRenderer(m_pWnd, -1, 0);if (!m_pRender){return false;}m_pTexture = SDL_CreateTexture(m_pRender, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, m_rect.w, m_rect.h);if (!m_pTexture){return false;}return true;}void UpdateTexture(AVFrame* pFrame){if (!pFrame){return;}//SDL_UpdateTexture(m_pTexture, &m_rect, pFrame->data[0], pFrame->linesize[0]);SDL_UpdateYUVTexture(m_pTexture, &m_rect, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1], pFrame->data[2], pFrame->linesize[2]);SDL_RenderClear(m_pRender);SDL_RenderCopy(m_pRender, m_pTexture, nullptr, &m_rect);SDL_RenderPresent(m_pRender);SDL_Delay(40);}
private:bool SdlInit(){if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0){printf("sdl_init error:%s\n", SDL_GetError());return false;}return true;}
private:SDL_Renderer* m_pRender = nullptr;SDL_Window* m_pWnd = nullptr;SDL_Texture* m_pTexture = nullptr;SDL_Rect m_rect;
};int getpic4() {std::string filename = "test.mp4";     // 输入MP4文件名std::string outputFilename = "output4.jpg";  // 输出图片文件名SDL_Window* pScreen = nullptr;      // 播放窗口SDL_Renderer* pRender = nullptr;    // 渲染器SDL_Texture* pSDLTexture = nullptr; // 纹理SDLHandle* m_pSDlHandle = nullptr;AVFormatContext* formatContext = nullptr;if (avformat_open_input(&formatContext, filename.c_str(), nullptr, nullptr) != 0) {std::cerr << "Error opening input file" << std::endl;return -1;}if (avformat_find_stream_info(formatContext, nullptr) < 0) {std::cerr << "Error finding stream information" << std::endl;avformat_close_input(&formatContext);return -1;}const AVCodec* codec = nullptr;int videoStreamIndex = -1;for (unsigned int i = 0; i < formatContext->nb_streams; i++) {if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStreamIndex = i;codec = avcodec_find_decoder(formatContext->streams[i]->codecpar->codec_id);break;}}if (videoStreamIndex == -1 || codec == nullptr) {std::cerr << "Error finding video stream or decoder" << std::endl;avformat_close_input(&formatContext);return -1;}AVCodecContext* codecContext = avcodec_alloc_context3(codec);if (codecContext == nullptr) {std::cerr << "Error allocating codec context" << std::endl;avformat_close_input(&formatContext);return -1;}if (avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar) < 0) {std::cerr << "Error setting codec parameters" << std::endl;avcodec_free_context(&codecContext);avformat_close_input(&formatContext);return -1;}if (avcodec_open2(codecContext, codec, nullptr) < 0) {std::cerr << "Error opening codec" << std::endl;avcodec_free_context(&codecContext);avformat_close_input(&formatContext);return -1;}m_pSDlHandle = new SDLHandle(codecContext->width, codecContext->height);if (!m_pSDlHandle->CreateSDLWindow("SDL_TEXT", SDL_WINDOW_OPENGL)){printf("CreateSDLWindow error:%s\n", SDL_GetError());return -1;}AVPacket packet;av_init_packet(&packet);// 查找目标时间戳所对应的帧AVFrame* frame = av_frame_alloc();bool foundTargetFrame = false;int count = 0;while (av_read_frame(formatContext, &packet) >= 0) {if (packet.stream_index == videoStreamIndex) {int response = avcodec_send_packet(codecContext, &packet);if (response < 0) {std::cerr << "Error sending packet to decoder" << std::endl;break;}count++;response = avcodec_receive_frame(codecContext, frame);if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {continue;}else if (response < 0) {std::cerr << "Error receiving frame from decoder" << std::endl;break;}m_pSDlHandle->UpdateTexture(frame);}av_packet_unref(&packet);}if (!foundTargetFrame) {std::cerr << "Target frame not found" << std::endl;av_frame_free(&frame);avcodec_free_context(&codecContext);avformat_close_input(&formatContext);return -1;}// 清理资源av_frame_free(&frame);av_packet_unref(&packet);avcodec_free_context(&codecContext);return 1;
}#undef main
int main(int argc, char* argv[]) {av_log(NULL, AV_LOG_INFO, "...Hello world\n");getpic4();return 0;
}

这篇关于[FFmpeg学习]初级的SDL播放mp4测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1050245

相关文章

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影