FFmpeg 如何探测网络流格式/如何从内存中获取数据
文章转自:http://blog.csdn.net/rootusers/article/details/42551935
一般ffmpeg都是直接从文件中读取或者从网络流中读取,比如rtp://xx.xx.xx.xx:xxxx。
事实上也支持从内存中获取。
函数avio_alloc_context()实现该功能。
- AVIOContext *avio_alloc_context(
- unsigned char *buffer,
- int buffer_size,
- int write_flag,
- void *opaque,
- int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),//重写该函数,指定从内存中读取的方法,将buf_size字节大小的数据保存到buf
- int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),//对应的这是写内存的函数
- int64_t (*seek)(void *opaque, int64_t offset, int whence));
对于探测网络媒体流个格式,也可以用此种方法,先接收数据,然后探测。
下面贴出代码:
- /*
- *author tongli
- */
- extern "C"{
- #include "libavformat/avformat.h"
- #include "libavcodec/avcodec.h"
- #include "libavutil/avutil.h"
- }
- #define BUF_SIZE 4096*500
- FILE* file;
- //实现read_packet函数,从文件中读取模拟的是从内存中获取,同样可以实现为接收网络流
- int read_packet(void *opaque, uint8_t *buf, int buf_size)
- {
- int n = 0;
- if (!feof(file)){
- n = fread(buf, 1, buf_size, file);
- return n;
- }else
- return -1;
- }
- int main(int argc, char** argv)
- {
- file = fopen("2.mp4", "rb");
- if (file == NULL)
- return -1;
- av_register_all();
- AVIOContext* pb = NULL;
- AVInputFormat* piFmt = NULL;
- AVInputFormat* pFmt = NULL;
- uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t)* BUF_SIZE);
- pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_packet, NULL, NULL);
- if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)//探测从内存中获取到的媒体流的格式
- {
- fprintf(stderr, "probe format failed\n");
- return -1;
- }
- else{
- fprintf(stdout, "format:%s[%s]\n", piFmt->name, piFmt->long_name);
- }
- return 0;
- }
下面实现一个简单的例子,从内存中读取,然后播放。
- <pre name="code" class="cpp">/*
- *author tongli
- */
- #include <stdio.h>
- #include <direct.h>
- #include <io.h>
- extern "C"{
- #include "libavformat/avformat.h"
- #include "libavcodec/avcodec.h"
- #include "libavutil/avutil.h"
- #include "libswscale/swscale.h"
- #include "libavformat/avio.h"
- #include "sdl/SDL.h"
- }
- #define BUF_SIZE 4096 * 500
- FILE* file;
- int read_data(void *opaque, uint8_t *buf, int buf_size)
- {
- int n = 0;
- if (!feof(file)){
- n = fread(buf, 1, buf_size, file);
- return n;
- }
- else
- return -1;
- }
- int main(int argc, char* argv[])
- {
- av_register_all();
- //file = fopen("h2.dat", "rb");
- file = fopen("3.mp4", "rb+");
- if (file == NULL)
- return -1;
- AVFormatContext *pFormatCtx;
- int i, videoindex;
- AVCodecContext *pCodecCtx;
- AVCodec *pCodec;
- AVIOContext* pb = NULL;
- AVInputFormat* piFmt = NULL;
- uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t)* BUF_SIZE);
- pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_data, NULL, NULL);
- if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)
- {
- fprintf(stderr, "probe format failed\n");
- return -1;
- }
- else{
- fprintf(stdout, "format:%s[%s]\n", piFmt->name, piFmt->long_name);
- }
- pFormatCtx = avformat_alloc_context();
- pFormatCtx->pb = pb;
- if (avformat_open_input(&pFormatCtx, "", piFmt, NULL) != 0){//iformat,priv_data赋值,pb, nbstreams,streams为null
- printf("Couldn't open input stream.(无法打开输入流)\n");
- return -1;
- }
- if (avformat_find_stream_info(pFormatCtx, NULL)<0)//nbstreams,streams赋值, pb还是为null
- {
- printf("Couldn't find stream information.(无法获取流信息)\n");
- return -1;
- }
- videoindex = -1;
- for (i = 0; i<pFormatCtx->nb_streams; i++) //一般情况下,一个媒体只有两个流,视频和音频流即streams[0],stream[1]
- if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- {//找到视频流
- videoindex = i;//在nb_streams视频流的索引
- break;
- }
- if (videoindex == -1)
- {
- printf("Didn't find a video stream.(没有找到视频流)\n");
- return -1;
- }
- pCodecCtx = pFormatCtx->streams[videoindex]->codec;
- pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
- if (pCodec == NULL)
- {
- printf("Codec not found.(没有找到解码器)\n");
- return -1;
- }
- if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)
- {
- printf("Could not open codec.(无法打开解码器)\n");
- return -1;
- }
- AVFrame *pFrame, *pFrameYUV;
- pFrame = av_frame_alloc();
- pFrameYUV = av_frame_alloc();
- uint8_t *out_buffer;
- out_buffer = new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];
- avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
- //------------SDL----------------
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
- printf("Could not initialize SDL - %s\n", SDL_GetError());
- return -1;
- }
- SDL_Surface *screen;
- screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
- if (!screen) {
- printf("SDL: could not set video mode - exiting\n");
- return -1;
- }
- SDL_Overlay *bmp;
- bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);
- SDL_Rect rect;
- //---------------
- int ret, got_picture;
- int y_size = pCodecCtx->width * pCodecCtx->height;
- AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
- av_new_packet(packet, y_size);
- struct SwsContext *img_convert_ctx;
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
- AV_PIX_FMT_YUVJ420P/*pCodecCtx->pix_fmt*/, pCodecCtx->width, pCodecCtx->height,
- PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
- //------------------------------
- while (av_read_frame(pFormatCtx, packet) >= 0)
- {
- if (packet->stream_index == videoindex)
- {
- ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
- if (ret < 0)
- {
- printf("Decode Error.(解码错误)\n");
- return -1;
- }
- if (got_picture)
- {
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
- SDL_LockYUVOverlay(bmp);
- bmp->pixels[0] = pFrameYUV->data[0];
- bmp->pixels[2] = pFrameYUV->data[1];
- bmp->pixels[1] = pFrameYUV->data[2];
- bmp->pitches[0] = pFrameYUV->linesize[0];
- bmp->pitches[2] = pFrameYUV->linesize[1];
- bmp->pitches[1] = pFrameYUV->linesize[2];
- SDL_UnlockYUVOverlay(bmp);
- rect.x = 0;
- rect.y = 0;
- rect.w = pCodecCtx->width;
- rect.h = pCodecCtx->height;
- SDL_DisplayYUVOverlay(bmp, &rect);
- //延时40ms
- SDL_Delay(40);
- }
- }
- av_free_packet(packet);
- }
- sws_freeContext(img_convert_ctx);
- delete[] out_buffer;
- av_free(pFrameYUV);
- avcodec_close(pCodecCtx);
- avformat_close_input(&pFormatCtx);
- return 0;
- }
FFmpeg 如何探测网络流格式/如何从内存中获取数据的更多相关文章
- ffmpeg 从内存中读取数据(或将数据输出到内存)
更新记录(2014.7.24): 1.为了使本文更通俗易懂,更新了部分内容,将例子改为从内存中打开. 2.增加了将数据输出到内存的方法. 从内存中读取数据 ffmpeg一般情况下支持打开一个本地文件, ...
- ffmpeg 从内存中读取数据(或将数据输出到内存)(转)
更新记录(2014.7.24): 1.为了使本文更通俗易懂,更新了部分内容,将例子改为从内存中打开. 2.增加了将数据输出到内存的方法. 从内存中读取数据 ffmpeg一般情况下支持打开一个本地文件, ...
- ffmpeg 从内存中读取数据 .
http://blog.csdn.net/leixiaohua1020/article/details/12980423 ——————————————————————————————————————— ...
- EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载
之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...
- 【EF学习笔记05】----------操作内存中的数据
SingleOrDefault实验 //SingleOrDefault实验 using (var db = new Entities()) { var classes = new Classes() ...
- EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载
EF如何操作内存中的数据和加载外键数据:延迟加载.贪婪加载.显示加载 之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需 ...
- 使用spark将内存中的数据写入到hive表中
使用spark将内存中的数据写入到hive表中 hive-site.xml <?xml version="1.0" encoding="UTF-8" st ...
- Xcode如何查看内存中的数据
在 debug 模式下如何在断点处,查看字符指针变量内存中的值,像vs2008的调试工具一样的内存查看器,现在只能查看第一个内存中的值可以在输出窗口采用gdb命令:x /nfu <addr&g ...
- cocos2dx中加载图片资源的方法,和从内存中获取已经加载的图片资源的方法
游戏中通常需要将常用的资源如:声音,图片,plist文件,提前加载进内存,以加快游戏的流畅度 1.预加载声音: SimpleAudioEngine::getInstance()->preload ...
随机推荐
- 搭建MSSM框架(Maven+Spring+Spring MVC+MyBatis)
https://github.com/easonjim/ssm-framework 先欠着,后续再进行讲解: 一.Spring内核集成 二.Spring MVC集成 三.MyBatis集成 四.代码生 ...
- 蓝屏代码详解(更新WIN7蓝屏代码)
6位代码含意 0 0x0000 作业完成. 1 0x0001 不正确的函数. 2 0x0002 系统找不到指定的档案. 3 0x0003 系统找不到指定的路径. 4 0x0004 系统无法开启 ...
- Webharvest网络爬虫应用总结,web-harvest 编写脚本 读取 百度 博客 实例
Webharvest网络爬虫应用总结 Web-Harvest是一个Java开源Web数据抽取工具.它能够收集指定的Web页面并从这些页面中提取有用的数据.其实现原理是,根据预先定义的配置文件用ht ...
- FFmpeg的使用——PHP转换视频、截取视频以及JW Player播放器控制
转载:http://blog.csdn.net/zm2714/article/details/7916440 给朋友做的一个项目中,涉及到上传视频.转换视频.自动截取已上传视频内容中的一帧做为缩略图片 ...
- Informatica pmcmd命令
pmcmd startworkflow -sv 集成服务名称 -d 配置域名称 -u Administrator -p Administrator -f 文件夹名称 -wait 工作流名称例如: p ...
- hadoop中实现定制Writable类
Hadoop中有一套Writable实现可以满足大部分需求,但是在有些情况下,我们需要根据自己的需要构造一个新的实现,有了定制的Writable,我们就可以完全控制二进制表示和排序顺序. 为了演示如何 ...
- [Python爬虫] 之一 : Selenium+Phantomjs动态获取网站数据信息
本人刚才开始学习爬虫,从网上查询资料,写了一个利用Selenium+Phantomjs动态获取网站数据信息的例子,当然首先要安装Selenium+Phantomjs,具体的看 http://www.c ...
- JavaScript中的递归函数问题
学过其它编程语言的都应该会知道递归这个问题,递归函数是在一个函数通过名字调用自身的情况下后构成的. function fac(num){ if(num<=1){ return 1; }else{ ...
- .NET-使用NPOI组件将数据导出Excel-通用方法
一.Excel导入及导出问题产生: 从接触.net到现在一直在维护一个DataTable导出到Excel的类,时不时还会维护一个导入类.以下是时不时就会出现的问题:导出问题: 如果是asp.net,你 ...
- PHP的代理模式
php的代理模式的实现: 理解一种模式,可以融会贯通,和其它的模式进行对比.找出为什么要 代理模式呢?跟父类.接口的区别是什么? 为什么需要这种模式?存在的价值? 原文:https://www.cnb ...