当前位置:   article > 正文

C++ 使用ffmpeg播放音视频文件_c++ ffmpeg 播放视频

c++ ffmpeg 播放视频

 1、包含必须的头文件

  1. #include <iostream>
  2. extern "C" {
  3. #include <libavformat/avformat.h>
  4. #include <libswresample/swresample.h>
  5. #include <libavutil/opt.h>
  6. #include <libavutil/audio_fifo.h>
  7. #include <libavutil/frame.h>
  8. }
  9. // SDL相关头文件
  10. #include <SDL2/SDL.h>
  11. #include <SDL2/SDL_audio.h>

2、示例。

  1. #define AUDIO_BUFFER_SIZE 4096
  2. typedef struct {
  3. uint8_t* buffer;
  4. int size;
  5. int pos;
  6. } AudioParams;
  7. void audio_callback(void* userdata, Uint8* stream, int len) {
  8. AudioParams* audioParams = (AudioParams*)userdata;
  9. if (audioParams->pos >= audioParams->size) {
  10. return;
  11. }
  12. int remaining = audioParams->size - audioParams->pos;
  13. len = (len > remaining) ? remaining : len;
  14. memcpy(stream, audioParams->buffer + audioParams->pos, len);
  15. audioParams->pos += len;
  16. }
  17. int main() {
  18. AVFormatContext* formatContext = avformat_alloc_context();
  19. // 打开输入文件
  20. if (avformat_open_input(&formatContext, "input.mp4", NULL, NULL) != 0) {
  21. std::cerr << "无法打开输入文件" << std::endl;
  22. return -1;
  23. }
  24. // 检索流信息
  25. if (avformat_find_stream_info(formatContext, NULL) < 0) {
  26. std::cerr << "无法检索流信息" << std::endl;
  27. return -1;
  28. }
  29. // 寻找音频流和视频流
  30. int audioStreamIndex = -1;
  31. int videoStreamIndex = -1;
  32. for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
  33. if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
  34. audioStreamIndex = i;
  35. }
  36. else if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  37. videoStreamIndex = i;
  38. }
  39. }
  40. // 检查是否找到音频流和视频流
  41. if (audioStreamIndex == -1 || videoStreamIndex == -1) {
  42. std::cerr << "无法找到音频流或视频流" << std::endl;
  43. return -1;
  44. }
  45. // 获取音频解码器和视频解码器
  46. AVCodecParameters* audioCodecParameters = formatContext->streams[audioStreamIndex]->codecpar;
  47. AVCodecParameters* videoCodecParameters = formatContext->streams[videoStreamIndex]->codecpar;
  48. AVCodec* audioCodec = avcodec_find_decoder(audioCodecParameters->codec_id);
  49. AVCodec* videoCodec = avcodec_find_decoder(videoCodecParameters->codec_id);
  50. // 打开音频解码器和视频解码器
  51. AVCodecContext* audioCodecContext = avcodec_alloc_context3(audioCodec);
  52. AVCodecContext* videoCodecContext = avcodec_alloc_context3(videoCodec);
  53. if (!audioCodecContext || !videoCodecContext) {
  54. std::cerr << "无法分配解码器上下文" << std::endl;
  55. return -1;
  56. }
  57. if (avcodec_parameters_to_context(audioCodecContext, audioCodecParameters) < 0 ||
  58. avcodec_parameters_to_context(videoCodecContext, videoCodecParameters) < 0) {
  59. std::cerr << "无法填充解码器上下文" << std::endl;
  60. return -1;
  61. }
  62. if (avcodec_open2(audioCodecContext, audioCodec, NULL) < 0 ||
  63. avcodec_open2(videoCodecContext, videoCodec, NULL) < 0) {
  64. std::cerr << "无法打开解码器" << std::endl;
  65. return -1;
  66. }
  67. // 初始化SDL
  68. if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) {
  69. std::cerr << "无法初始化SDL" << std::endl;
  70. return -1;
  71. }
  72. // 创建窗口和渲染器
  73. SDL_Window* window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
  74. videoCodecParameters->width, videoCodecParameters->height, SDL_WINDOW_SHOWN);
  75. SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
  76. SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,
  77. videoCodecParameters->width, videoCodecParameters->height);
  78. // 音频参数设置
  79. AudioParams audioParams;
  80. audioParams.buffer = new uint8_t[AUDIO_BUFFER_SIZE];
  81. audioParams.size = AUDIO_BUFFER_SIZE;
  82. audioParams.pos = 0;
  83. // 初始化音频重采样上下文
  84. SwrContext* swrContext = swr_alloc_set_opts(NULL,
  85. av_get_default_channel_layout(audioCodecContext->channels),
  86. AV_SAMPLE_FMT_S16,
  87. audioCodecContext->sample_rate,
  88. av_get_default_channel_layout(audioCodecContext->channels),
  89. audioCodecContext->sample_fmt,
  90. audioCodecContext->sample_rate,
  91. 0, NULL);
  92. if (!swrContext) {
  93. std::cerr << "无法分配音频重采样上下文" << std::endl;
  94. return -1;
  95. }
  96. if (swr_init(swrContext) < 0) {
  97. std::cerr << "无法初始化音频重采样上下文" << std::endl;
  98. return -1;
  99. }
  100. // 打开音频设备
  101. SDL_AudioSpec desiredSpec, obtainedSpec;
  102. desiredSpec.freq = audioCodecContext->sample_rate;
  103. desiredSpec.format = AUDIO_S16SYS;
  104. desiredSpec.channels = audioCodecContext->channels;
  105. desiredSpec.silence = 0;
  106. desiredSpec.samples = 1024;
  107. desiredSpec.callback = audio_callback;
  108. desiredSpec.userdata = &audioParams;
  109. if (SDL_OpenAudio(&desiredSpec, &obtainedSpec) < 0) {
  110. std::cerr << "无法打开音频设备" << std::endl;
  111. return -1;
  112. }
  113. // 开始播放音频
  114. SDL_PauseAudio(0);
  115. // 循环读取帧数据并播放
  116. AVPacket packet;
  117. AVFrame* frame = av_frame_alloc();
  118. AVFrame* convertedFrame = av_frame_alloc();
  119. while (av_read_frame(formatContext, &packet) >= 0) {
  120. if (packet.stream_index == audioStreamIndex) {
  121. // 解码音频帧
  122. int ret = avcodec_send_packet(audioCodecContext, &packet);
  123. if (ret < 0) {
  124. std::cerr << "无法发送音频数据包" << std::endl;
  125. break;
  126. }
  127. while (ret >= 0) {
  128. ret = avcodec_receive_frame(audioCodecContext, frame);
  129. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  130. break;
  131. }
  132. else if (ret < 0) {
  133. std::cerr << "无法解码音频帧" << std::endl;
  134. break;
  135. }
  136. // 音频重采样
  137. int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrContext, frame->sample_rate) +
  138. frame->nb_samples,
  139. audioCodecContext->sample_rate,
  140. frame->sample_rate,
  141. AV_ROUND_UP);
  142. av_frame_make_writable(convertedFrame);
  143. convertedFrame->format = AV_SAMPLE_FMT_S16;
  144. convertedFrame->channel_layout = audioCodecContext->channel_layout;
  145. convertedFrame->sample_rate = audioCodecContext->sample_rate;
  146. convertedFrame->channels = audioCodecContext->channels;
  147. av_samples_alloc(convertedFrame->data, convertedFrame->linesize, audioCodecContext->channels,
  148. dst_nb_samples, AV_SAMPLE_FMT_S16, 0);
  149. swr_convert(swrContext, convertedFrame->data, dst_nb_samples,
  150. (const uint8_t**)frame->data, frame->nb_samples);
  151. // 播放音频
  152. int dataSize = av_get_bytes_per_sample((AVSampleFormat)convertedFrame->format) *
  153. convertedFrame->nb_samples * convertedFrame->channels;
  154. if (audioParams.pos + dataSize <= audioParams.size) {
  155. memcpy(audioParams.buffer + audioParams.pos, convertedFrame->data[0], dataSize);
  156. audioParams.pos += dataSize;
  157. }
  158. av_freep(&convertedFrame->data[0]);
  159. }
  160. }
  161. else if (packet.stream_index == videoStreamIndex) {
  162. // 解码视频帧
  163. int ret = avcodec_send_packet(videoCodecContext, &packet);
  164. if (ret < 0) {
  165. std::cerr << "无法发送视频数据包" << std::endl;
  166. // 音频参数设置
  167. AudioParams audioParams;
  168. audioParams.buffer = new uint8_t[AUDIO_BUFFER_SIZE];
  169. audioParams.size = AUDIO_BUFFER_SIZE;
  170. audioParams.pos = 0;
  171. // 初始化音频重采样上下文
  172. SwrContext* swrContext = swr_alloc_set_opts(NULL,
  173. av_get_default_channel_layout(audioCodecContext->channels),
  174. AV_SAMPLE_FMT_S16,
  175. audioCodecContext->sample_rate,
  176. av_get_default_channel_layout(audioCodecContext->channels),
  177. audioCodecContext->sample_fmt,
  178. audioCodecContext->sample_rate,
  179. 0, NULL);
  180. if (!swrContext) {
  181. std::cerr << "无法分配音频重采样上下文" << std::endl;
  182. return -1;
  183. }
  184. if (swr_init(swrContext) < 0) {
  185. std::cerr << "无法初始化音频重采样上下文" << std::endl;
  186. return -1;
  187. }
  188. // 打开音频设备
  189. SDL_AudioSpec desiredSpec, obtainedSpec;
  190. desiredSpec.freq = audioCodecContext->sample_rate;
  191. desiredSpec.format = AUDIO_S16SYS;
  192. desiredSpec.channels = audioCodecContext->channels;
  193. desiredSpec.silence = 0;
  194. desiredSpec.samples = 1024;
  195. desiredSpec.callback = audio_callback;
  196. desiredSpec.userdata = &audioParams;
  197. if (SDL_OpenAudio(&desiredSpec, &obtainedSpec) < 0) {
  198. std::cerr << "无法打开音频设备" << std::endl;
  199. return -1;
  200. }
  201. // 开始播放音频
  202. SDL_PauseAudio(0);
  203. // 循环读取帧数据并播放
  204. AVPacket packet;
  205. AVFrame* frame = av_frame_alloc();
  206. AVFrame* convertedFrame = av_frame_alloc();
  207. while (av_read_frame(formatContext, &packet) >= 0) {
  208. if (packet.stream_index == audioStreamIndex) {
  209. // 解码音频帧
  210. int ret = avcodec_send_packet(audioCodecContext, &packet);
  211. if (ret < 0) {
  212. std::cerr << "无法发送音频数据包" << std::endl;
  213. break;
  214. }
  215. while (ret >= 0) {
  216. ret = avcodec_receive_frame(audioCodecContext, frame);
  217. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  218. break;
  219. }
  220. else if (ret < 0) {
  221. std::cerr << "无法解码音频帧" << std::endl;
  222. break;
  223. }
  224. // 音频重采样
  225. int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrContext, frame->sample_rate) +
  226. frame->nb_samples,
  227. audioCodecContext->sample_rate,
  228. frame->sample_rate,
  229. AV_ROUND_UP);
  230. av_frame_make_writable(convertedFrame);
  231. convertedFrame->format = AV_SAMPLE_FMT_S16;
  232. convertedFrame->channel_layout = audioCodecContext->channel_layout;
  233. convertedFrame->sample_rate = audioCodecContext->sample_rate;
  234. convertedFrame->channels = audioCodecContext->channels;
  235. av_samples_alloc(convertedFrame->data, convertedFrame->linesize, audioCodecContext->channels,
  236. dst_nb_samples, AV_SAMPLE_FMT_S16, 0);
  237. swr_convert(swrContext, convertedFrame->data, dst_nb_samples,
  238. (const uint8_t**)frame->data, frame->nb_samples);
  239. // 播放音频
  240. int dataSize = av_get_bytes_per_sample((AVSampleFormat)convertedFrame->format) *
  241. convertedFrame->nb_samples * convertedFrame->channels;
  242. if (audioParams.pos + dataSize <= audioParams.size) {
  243. memcpy(audioParams.buffer + audioParams.pos, convertedFrame->data[0], dataSize);
  244. audioParams.pos += dataSize;
  245. }
  246. av_freep(&convertedFrame->data[0]);
  247. }
  248. }
  249. else if (packet.stream_index == videoStreamIndex) {
  250. // 解码视频帧
  251. int ret = avcodec_send_packet(videoCodecContext, &packet);
  252. if (ret < 0) {
  253. std::cerr << "无法发送视频数据包" << std::endl;
  254. break;
  255. }
  256. while (ret >= 0) {
  257. ret = avcodec_receive_frame(videoCodecContext, frame);
  258. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
  259. break;
  260. }
  261. else if (ret < 0) {
  262. std::cerr << "无法解码视频帧" << std::endl;
  263. break;
  264. }
  265. // 渲染视频
  266. SDL_UpdateTexture(texture, NULL, frame->data[0], frame->linesize[0]);
  267. SDL_RenderClear(renderer);
  268. SDL_RenderCopy(renderer, texture, NULL, NULL);
  269. SDL_RenderPresent(renderer);
  270. }
  271. }
  272. av_packet_unref(&packet);
  273. }
  274. // 释放资源
  275. av_frame_free(&frame);
  276. av_frame_free(&convertedFrame);
  277. avcodec_close(audioCodecContext);
  278. avcodec_close(videoCodecContext);
  279. avformat_close_input(&formatContext);
  280. avformat_free_context(formatContext);
  281. swr_free(&swrContext);
  282. SDL_CloseAudio();
  283. SDL_Quit();
  284. return 0;
  285. }
  286. }
  287. }
  288. }

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号