文章转自:http://blog.csdn.net/rootusers/article/details/42551935

一般ffmpeg都是直接从文件中读取或者从网络流中读取,比如rtp://xx.xx.xx.xx:xxxx。

事实上也支持从内存中获取。

函数avio_alloc_context()实现该功能。

  1. AVIOContext *avio_alloc_context(
  2. unsigned char *buffer,
  3. int buffer_size,
  4. int write_flag,
  5. void *opaque,
  6. int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),//重写该函数,指定从内存中读取的方法,将buf_size字节大小的数据保存到buf
  7. int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),//对应的这是写内存的函数
  8. int64_t (*seek)(void *opaque, int64_t offset, int whence));

对于探测网络媒体流个格式,也可以用此种方法,先接收数据,然后探测。

下面贴出代码:

  1. /*
  2. *author tongli
  3. */
  4. extern "C"{
  5. #include "libavformat/avformat.h"
  6. #include "libavcodec/avcodec.h"
  7. #include "libavutil/avutil.h"
  8. }
  9. #define BUF_SIZE 4096*500
  10. FILE* file;
  11. //实现read_packet函数,从文件中读取模拟的是从内存中获取,同样可以实现为接收网络流
  12. int read_packet(void *opaque, uint8_t *buf, int buf_size)
  13. {
  14. int n = 0;
  15. if (!feof(file)){
  16. n = fread(buf, 1, buf_size, file);
  17. return n;
  18. }else
  19. return -1;
  20. }
  21. int main(int argc, char** argv)
  22. {
  23. file = fopen("2.mp4", "rb");
  24. if (file == NULL)
  25. return -1;
  26. av_register_all();
  27. AVIOContext* pb = NULL;
  28. AVInputFormat* piFmt = NULL;
  29. AVInputFormat* pFmt = NULL;
  30. uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t)* BUF_SIZE);
  31. pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_packet, NULL, NULL);
  32. if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)//探测从内存中获取到的媒体流的格式
  33. {
  34. fprintf(stderr, "probe format failed\n");
  35. return -1;
  36. }
  37. else{
  38. fprintf(stdout, "format:%s[%s]\n", piFmt->name, piFmt->long_name);
  39. }
  40. return 0;
  41. }


下面实现一个简单的例子,从内存中读取,然后播放。

    1. <pre name="code" class="cpp">/*
    2. *author tongli
    3. */
    4. #include <stdio.h>
    5. #include <direct.h>
    6. #include <io.h>
    7. extern "C"{
    8. #include "libavformat/avformat.h"
    9. #include "libavcodec/avcodec.h"
    10. #include "libavutil/avutil.h"
    11. #include "libswscale/swscale.h"
    12. #include "libavformat/avio.h"
    13. #include "sdl/SDL.h"
    14. }
    15. #define BUF_SIZE 4096 * 500
    16. FILE* file;
    17. int read_data(void *opaque, uint8_t *buf, int buf_size)
    18. {
    19. int n = 0;
    20. if (!feof(file)){
    21. n = fread(buf, 1, buf_size, file);
    22. return n;
    23. }
    24. else
    25. return -1;
    26. }
    27. int main(int argc, char* argv[])
    28. {
    29. av_register_all();
    30. //file = fopen("h2.dat", "rb");
    31. file = fopen("3.mp4", "rb+");
    32. if (file == NULL)
    33. return -1;
    34. AVFormatContext *pFormatCtx;
    35. int             i, videoindex;
    36. AVCodecContext  *pCodecCtx;
    37. AVCodec         *pCodec;
    38. AVIOContext* pb = NULL;
    39. AVInputFormat* piFmt = NULL;
    40. uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t)* BUF_SIZE);
    41. pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_data, NULL, NULL);
    42. if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)
    43. {
    44. fprintf(stderr, "probe format failed\n");
    45. return -1;
    46. }
    47. else{
    48. fprintf(stdout, "format:%s[%s]\n", piFmt->name, piFmt->long_name);
    49. }
    50. pFormatCtx = avformat_alloc_context();
    51. pFormatCtx->pb = pb;
    52. if (avformat_open_input(&pFormatCtx, "", piFmt, NULL) != 0){//iformat,priv_data赋值,pb, nbstreams,streams为null
    53. printf("Couldn't open input stream.(无法打开输入流)\n");
    54. return -1;
    55. }
    56. if (avformat_find_stream_info(pFormatCtx, NULL)<0)//nbstreams,streams赋值, pb还是为null
    57. {
    58. printf("Couldn't find stream information.(无法获取流信息)\n");
    59. return -1;
    60. }
    61. videoindex = -1;
    62. for (i = 0; i<pFormatCtx->nb_streams; i++) //一般情况下,一个媒体只有两个流,视频和音频流即streams[0],stream[1]
    63. if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
    64. {//找到视频流
    65. videoindex = i;//在nb_streams视频流的索引
    66. break;
    67. }
    68. if (videoindex == -1)
    69. {
    70. printf("Didn't find a video stream.(没有找到视频流)\n");
    71. return -1;
    72. }
    73. pCodecCtx = pFormatCtx->streams[videoindex]->codec;
    74. pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    75. if (pCodec == NULL)
    76. {
    77. printf("Codec not found.(没有找到解码器)\n");
    78. return -1;
    79. }
    80. if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    81. {
    82. printf("Could not open codec.(无法打开解码器)\n");
    83. return -1;
    84. }
    85. AVFrame *pFrame, *pFrameYUV;
    86. pFrame = av_frame_alloc();
    87. pFrameYUV = av_frame_alloc();
    88. uint8_t *out_buffer;
    89. out_buffer = new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];
    90. avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
    91. //------------SDL----------------
    92. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    93. printf("Could not initialize SDL - %s\n", SDL_GetError());
    94. return -1;
    95. }
    96. SDL_Surface *screen;
    97. screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
    98. if (!screen) {
    99. printf("SDL: could not set video mode - exiting\n");
    100. return -1;
    101. }
    102. SDL_Overlay *bmp;
    103. bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);
    104. SDL_Rect rect;
    105. //---------------
    106. int ret, got_picture;
    107. int y_size = pCodecCtx->width * pCodecCtx->height;
    108. AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    109. av_new_packet(packet, y_size);
    110. struct SwsContext *img_convert_ctx;
    111. img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
    112. AV_PIX_FMT_YUVJ420P/*pCodecCtx->pix_fmt*/, pCodecCtx->width, pCodecCtx->height,
    113. PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
    114. //------------------------------
    115. while (av_read_frame(pFormatCtx, packet) >= 0)
    116. {
    117. if (packet->stream_index == videoindex)
    118. {
    119. ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
    120. if (ret < 0)
    121. {
    122. printf("Decode Error.(解码错误)\n");
    123. return -1;
    124. }
    125. if (got_picture)
    126. {
    127. sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
    128. SDL_LockYUVOverlay(bmp);
    129. bmp->pixels[0] = pFrameYUV->data[0];
    130. bmp->pixels[2] = pFrameYUV->data[1];
    131. bmp->pixels[1] = pFrameYUV->data[2];
    132. bmp->pitches[0] = pFrameYUV->linesize[0];
    133. bmp->pitches[2] = pFrameYUV->linesize[1];
    134. bmp->pitches[1] = pFrameYUV->linesize[2];
    135. SDL_UnlockYUVOverlay(bmp);
    136. rect.x = 0;
    137. rect.y = 0;
    138. rect.w = pCodecCtx->width;
    139. rect.h = pCodecCtx->height;
    140. SDL_DisplayYUVOverlay(bmp, &rect);
    141. //延时40ms
    142. SDL_Delay(40);
    143. }
    144. }
    145. av_free_packet(packet);
    146. }
    147. sws_freeContext(img_convert_ctx);
    148. delete[] out_buffer;
    149. av_free(pFrameYUV);
    150. avcodec_close(pCodecCtx);
    151. avformat_close_input(&pFormatCtx);
    152. return 0;
    153. }

FFmpeg 如何探测网络流格式/如何从内存中获取数据的更多相关文章

  1. ffmpeg 从内存中读取数据(或将数据输出到内存)

    更新记录(2014.7.24): 1.为了使本文更通俗易懂,更新了部分内容,将例子改为从内存中打开. 2.增加了将数据输出到内存的方法. 从内存中读取数据 ffmpeg一般情况下支持打开一个本地文件, ...

  2. ffmpeg 从内存中读取数据(或将数据输出到内存)(转)

    更新记录(2014.7.24): 1.为了使本文更通俗易懂,更新了部分内容,将例子改为从内存中打开. 2.增加了将数据输出到内存的方法. 从内存中读取数据 ffmpeg一般情况下支持打开一个本地文件, ...

  3. ffmpeg 从内存中读取数据 .

    http://blog.csdn.net/leixiaohua1020/article/details/12980423 ——————————————————————————————————————— ...

  4. EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载

    之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...

  5. 【EF学习笔记05】----------操作内存中的数据

    SingleOrDefault实验 //SingleOrDefault实验 using (var db = new Entities()) { var classes = new Classes() ...

  6. EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载

    EF如何操作内存中的数据和加载外键数据:延迟加载.贪婪加载.显示加载 之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需 ...

  7. 使用spark将内存中的数据写入到hive表中

    使用spark将内存中的数据写入到hive表中 hive-site.xml <?xml version="1.0" encoding="UTF-8" st ...

  8. Xcode如何查看内存中的数据

    在  debug 模式下如何在断点处,查看字符指针变量内存中的值,像vs2008的调试工具一样的内存查看器,现在只能查看第一个内存中的值可以在输出窗口采用gdb命令:x /nfu <addr&g ...

  9. cocos2dx中加载图片资源的方法,和从内存中获取已经加载的图片资源的方法

    游戏中通常需要将常用的资源如:声音,图片,plist文件,提前加载进内存,以加快游戏的流畅度 1.预加载声音: SimpleAudioEngine::getInstance()->preload ...

随机推荐

  1. mui 页面滚动解决方案

    默认情况下mui 页面不能滚动,以下为解决方案: 1. mui('.mui-scroll-wrapper').scroll({  deceleration: 0.0005 //flick 减速系数,系 ...

  2. HDU 4669 Mutiples on a circle (2013多校7 1004题)

    Mutiples on a circle Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Oth ...

  3. 小程序setData工作原理理解图

    优化建议:1.频繁的去setData--我曾经用这个弄过动画效果,当然后来发现JS动画不适合小程序,CSS3动画才是王道2.每次setData都传递大量新数据--这个大量还真不好理解,暂时定为排行榜类 ...

  4. 软件版本GA,RC,alpha,beta,Build 含义

    (1)RC:(Release Candidate) Candidate是候选人的意思,用在软件上就是候选版本.Release.Candidate.就是发行候选版本.和Beta版最大的差别在于Beta阶 ...

  5. Windows下Linux 环境 Cygwin安装及配置 基本工具使用

    用久了Ubuntu开发环境,切换到windows多少有些不爽,想在windows下享用linux便捷的工具可以安装强大的Cygwin,本人也是初次使用中学习.本文主要目的让你可以通过cygwin使用基 ...

  6. Java垃圾回收精粹 — Part2

    Java垃圾回收精粹分4个部分,本篇是第2部分.在第2部分里介绍了Hotspot中的堆结构.对象分配以及次要回收. Hotspot中的堆结构 理解不同的收集器的工作方式,是探讨Java堆结构如何支持分 ...

  7. spm教程

    1.spm初学者教程:http://www.ernohermans.com/wp-content/uploads/2011/11/spm8_startersguide.pdf 2.spm官方mannu ...

  8. 描述 Machine.Config 和 Web.Config(转载)

    NET Framework 提供的配置管理包括范围广泛的设置,允许管理员管理 Web 应用程序及其环境.这些设置存储在 XML 配置文件中,其中一些控制计算机范围的设置,另一些控制应用程序特定的配置. ...

  9. TYVJ-P1864 守卫者的挑战 题解

    P1864 [Poetize I]守卫者的挑战 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜 ...

  10. go语言基础之获取命令行参数

    1.获取命令行参数 示例: package main //必须 import "fmt" import "os" func main() { list := o ...