文档章节

ffmpeg 如何探测网络流格式/如何从内存中获取数据,ffmpeg探测

j
 jane_linux
发布于 2017/04/11 08:59
字数 970
阅读 11
收藏 0
点赞 0
评论 0

ffmpeg 如何探测网络流格式/如何从内存中获取数据,ffmpeg探测

 

一般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;
}

 

© 著作权归作者所有

共有 人打赏支持
j
粉丝 0
博文 10
码字总数 970
作品 0
ONVIF协议网络摄像机(IPC)客户端程序开发(12):读取音视频流

1 专栏导读 本专栏第一篇文章「专栏开篇」列出了专栏的完整目录,按目录顺序阅读,有助于你的理解,专栏前面文章讲过的知识点(或代码段),后面文章不会赘述。为了节省篇幅,突出重点,在文...

benkaoya
2017/05/19
0
0
利用FFmpeg和管道(pipe),解决非URL和非文件的输入形式

利用FFmpeg和管道(pipe),解决非URL和非文件的输入形式 问题描述:利用FFmpeg来解码,但是输入方式不是URL,也不是文件系统中的文件,而是内存中的buffer。 解决此问题有两个思路,首先明确...

Michael_Yuan
2012/07/10
0
1
FFmpeg深入分析之零-基础

FFmpeg是相当强大的多媒体编解码框架,在深入分析其源代码之前必须要有基本的多媒 体基础知识,否则其源代码会非常晦涩难懂。本文将从介绍一些基本的多媒体只是,主要是为研读ffmpeg源代码做...

李荣刚
2015/03/16
0
0
如何在Windows上安装FFmpeg程序

如何在Windows上安装FFmpeg程序 由 Yutao 编辑 2 方法:下载FFmpeg在命令行中开启FFmpeg FFmpeg程序进行各种媒体格式的转换,从而它们可以在不同设备上播放。该程序只有命令行模式,因此将它安...

james_laughing
2014/12/09
0
0
PHP中利用Ffmpeg获得flv视频缩略图和播放时间

这里简单说一下:FFmpeg是用于录制、转换和流化音频和视频的完整解决方案,一套领先的音/视频编解码类库。官方正式版ffmpeg不支持rmvb和rm格式. 不过有很多解决方法 FFmpeg的官方网址是 http...

5D同学
2012/04/16
0
0
FFmpeg Maintainer赵军:FFmpeg关键组件与硬件加速

本文来自FFmpeg Maintainer赵军在LiveVideoStackCon 2018热身分享,并由LiveVideoStack整理而成。在分享中,赵军介绍了FFmpeg的历史、关键组件,并介绍了英特尔平台上的多种FFmpeg硬件加速方...

LiveVideoStack
昨天
0
0
FFmpeg深入分析之零-基础

FFmpeg是相当强大的多媒体编解码框架,在深入分析其源代码之前必须要有基本的多媒体基础知识,否则其源代码会非常晦涩难懂。本文将从介绍一些基本的多媒体只是,主要是为研读ffmpeg源代码做准...

天下杰论
2015/04/22
0
0
windows 下 hls 的点播和直播

Apple的动态码率自适应技术。主要用于PC和Apple终端的音视频服务。包括一个m3u(8)的索引文件,TS媒体分片文件和key加密串文件(可选)。 常用的流媒体协议主要有 HTTP 渐进下载和基于 RTSP/R...

mlianghua
2015/06/05
0
0
用SRS和FFMPEG进行直播流转码

WIKI:https://github.com/simple-rtmp-server/srs/wiki/v1CNFFMPEG 一、直播流转码配置及说明 listen 1935; maxconnections 1000; #定义一个默认的vhost vhost defaultVhost { } #定义一个名......

Johnny_feng
2015/05/13
0
16
学习FFmpeg API – 解码视频

ffmpeg是编解码的利器,用了很久,以前看过dranger 的教程,非常精彩,受益颇多,是学习ffmpeg api很好的材料。可惜的是其针对的ffmpeg版本已经比较老了,而ffmpeg的更新又很快,有些API已经...

霄霄月月
2012/05/08
0
32

没有更多内容

加载失败,请刷新页面

加载更多

下一页

about git flow

  昨天元芳做了git分支管理规范的分享,为了拓展大家关于git分支的认知,这里我特意再分享这两个关于git flow的链接,大家可以看一下。 Git 工作流程 Git分支管理策略   git flow本质上是...

qwfys
今天
2
0
Linux系统日志文件

/var/log/messages linux系统总日志 /etc/logrotate.conf 日志切割配置文件 参考https://my.oschina.net/u/2000675/blog/908189 dmesg命令 dmesg’命令显示linux内核的环形缓冲区信息,我们可...

chencheng-linux
今天
1
0
MacOS下给树莓派安装Raspbian系统

下载镜像 前往 树莓派官网 下载镜像。 点击 最新版Raspbian 下载最新版镜像。 下载后请,通过 访达 双击解压,或通过 unzip 命令解压。 检查下载的文件 ls -lh -rw-r--r-- 1 dingdayu s...

dingdayu
今天
1
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
今天
2
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
今天
1
0
Java工具类—随机数

Java中常用的生成随机数有Math.random()方法及java.util.Random类.但他们生成的随机数都是伪随机的. Math.radom()方法 在jdk1.8的Math类中可以看到,Math.random()方法实际上就是调用Random类...

PrivateO2
今天
2
0
关于java内存模型、并发编程的好文

Java并发编程:volatile关键字解析    volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在...

DannyCoder
昨天
1
0
dubbo @Reference retries 重试次数 一个坑

在代码一中设置 成retries=0,也就是调用超时不用重试,结果DEBUG的时候总是重试,不是0吗,0就不用重试啊。为什么还是调用了多次呢? 结果在网上看到 这篇文章才明白 https://www.cnblogs....

奋斗的小牛
昨天
2
0
数据结构与算法3

要抓紧喽~~~~~~~放羊的孩纸回来喽 LowArray类和LowArrayApp类 程序将一个普通的Java数组封装在LowArray类中。类中的数组隐藏了起来,它是私有的,所以只有类自己的方法才能访问他。 LowArray...

沉迷于编程的小菜菜
昨天
1
0
spring boot应用测试框架介绍

一、spring boot应用测试存在的问题 官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能(junit、spring test、assertj、hamcrest、mockito、jsonassert、jsonpath),但是在数...

yangjianzhou
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部