0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Tiny4412移植ffmpeg实现视频解码

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-09-29 15:31 次阅读

Tiny4412移植ffmpeg实现视频解码

 FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。

1.硬件平台

硬件平台:Tiny4412(Cortex-A9)
交叉编译器:arm-linux-gcc(Ver4.5.1)
开发板系统:linux3.5
ffmpeg版本:ffmpeg-4.2.5

2.ffmpeg源码编译

  安装ffmpeg库之前需要先安装x264库。

 2.1 x264编译安装

  x264下载地址:https://www.videolan.org/developers/x264.html

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

 安装x264

#解压
tar xvf /mnt/hgfs/ubuntu/software_pack/x264-master.tar.bz2
#配置信息,生成Makefile
./configure --prefix=$PWD/_install --enable-shared --disable-asm --host=arm-linux
#修改config.mak 
gedit config.mak 
watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

  编译 make

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

若编译出现报错:undefined reference to `clock_gettime’,则添加动态链接: -lrt
  重新编译 make

/*编译*/
make && make install
/*生成文件*/
[wbyq@wbyq x264-master]$ tree _install/
_install/
├── bin
│   └── x264
├── include
│   ├── x264_config.h
│   └── x264.h
└── lib
    ├── libx264.so -> libx264.so.164
    ├── libx264.so.164
    └── pkgconfig
        └── x264.pc

4 directories, 6 files

 2.2 ffmpeg编译安装

  下载地址:http://www.ffmpeg.org/download.html

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASVRf6Zi_5rC0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center

  编译安装ffmpeg

/*解压*/
tar xvf /mnt/hgfs/ubuntu/software_pack/ffmpeg-4.2.5.tar.bz2 
/*配置信息,生成makefile文件*/
./configure --enable-shared --enable-static --prefix=$PWD/_install --cross-prefix=arm-linux- --arch=arm --target-os=linux --enable-gpl --extra-cflags=-I/home/wbyq/tiny4412_pack/x264-master/_install/include --extra-ldflags=-L/home/wbyq/tiny4412_pack/x264-master/_install/lib --enable-ffmpeg --enable-libx264
/*编译源码*/
make && make install

3.视频解码

#include 
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 

#define FILE_NAME "1.mp4"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
extern const unsigned char ascii_32_16[][32*16/8];
static  struct fb_var_screeninfo vinfo;/*lcd可变形参结构体*/
static struct fb_fix_screeninfo finfo;/*lcd固定参数结构体*/
static unsigned char *lcd_p;/*lcd缓冲区首地址*/

u32 lcd_widht;/*LCD屏宽度*/
u32 lcd_hight;/*LCD屏高度*/

static unsigned char *lcd_p2;/*图像数据*/
u32 map_w;
u32 map_h;
/*画点函数*/
void LCD_DrawPoint(int x,int y,int c)
{
	unsigned int *p=(unsigned int *)(y*finfo.line_length+x*vinfo.bits_per_pixel/8+lcd_p);
	*p=c;
}
/*画点函数*/
void LCD_DrawPoint2(int x,int y,int c)
{
	unsigned int *p=(unsigned int *)(y*map_w*3+x*3+lcd_p2);
	*p=c;
}
/*显示数据*/
void LCD_DisplayData(int x,int y,int w,int h,const unsigned char *data)
{
	int i,j;
	int x0=x;
	unsigned char temp;
	for(i=0;i0x80)
    {
		str+=2;
    }
    else
    {
      LCD_DisplayData(x,y,size/2,size,ascii_32_16[*str-' ']);
      str++;
      x+=size/2;
    }
  }
}
/*显示图片函数(居中显示)*/
void LCD_Image(int map_w,int map_h,u8 *map_rgb)
{
    u32 w=map_w;//图片宽度
    u32 h=map_h;//图片高度
    //printf("w=%d,h=%dn",w,h);
   // u16 x=(lcd_widht-w)/2;
  //  u16 y=(lcd_hight-h)/2;
	u16 x=0;
	u16 y=0;
    int i,j;
    int cnt=0;
    u32 rgb=0xff0000;
    u8 *image_rgb=map_rgb;
    u32 *p=(unsigned int *)(y*finfo.line_length+x*vinfo.bits_per_pixel/8+lcd_p);//获取到坐标地址
    for(i=0;istreams[videostream];
	AVCodec *vcodec=avcodec_find_decoder(stream->codecpar->codec_id);
	if(!vcodec)
	{
		printf("未找到解码器n");
		return -1;
	}
	/*申请视频AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。*/
	res=avcodec_open2(stream->codec,vcodec,NULL);
	if(res)
	{
		printf("打开解码器失败n");
		return -1;
	}
	
	/*寻找音频解码器*/
	AVStream *audstream = ps->streams[audiostream];
	AVCodec *audcodec=avcodec_find_decoder(audstream->codecpar->codec_id);
	if(!audcodec)
	{
		printf("audcodec failedn");
		return -1;
	}
	/*申请音频AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。*/
	res=avcodec_open2(audstream->codec,audcodec,NULL);
	if(res)
	{
		printf("open audio failedn");
		return -1;
	}
	printf("sucessn");
	int sample_rate=audstream->codec->sample_rate;/*采样率*/
	int channel=audstream->codec->channels;/*通道数*/
	
	printf("sample_rate:%dn",sample_rate);
	printf("channel:%dn",channel);
	int sample_fmt;
	switch(audstream->codec->sample_fmt)
	{
		case AV_SAMPLE_FMT_U8:/*8位*/
			sample_fmt=AV_SAMPLE_FMT_U8;
			break;
		case AV_SAMPLE_FMT_FLTP:/*浮点型*/
			sample_fmt=AV_SAMPLE_FMT_FLTP;
			break;
	}
	int go_audio;
	AVPacket *packet=av_malloc(sizeof(AVPacket));/*分配包*/
	AVFrame *frame=av_frame_alloc();/*分配视频帧*/
	AVFrame *audioframe=av_frame_alloc();/*分配音频帧*/
	int audiosize=2*1024*2;
	char *out_buffer = (char*)av_malloc(audiosize);
	/*对解码数据进行重采样*/
	SwrContext *swrCtx = swr_alloc();
	enum AVSampleFormat in_sample_fmt=audstream->codec->sample_fmt;/*输入采样格式*/
	enum AVSampleFormat out_sample_fmt=AV_SAMPLE_FMT_S16;/*输出采样格式:16bit PCM*/
	int in_sample_rate=audstream->codec->sample_rate;/*输入采样率*/
	int out_sample_rate=44100;/*输出采样率*/
	
	uint64_t in_ch_layout=audstream->codecpar->channel_layout;//输入的声道布局
	uint64_t out_ch_layout=audstream->codecpar->channel_layout;/*立体声*/
	
	swr_alloc_set_opts(swrCtx,out_ch_layout,out_sample_fmt,out_sample_rate,/*输入音频格式*/
								in_ch_layout,in_sample_fmt,in_sample_rate,/*输出音频格式*/
								0,NULL);
	
	swr_init(swrCtx);
	//视频解码
	AVFrame *frameRGB=av_frame_alloc();/*申请yuv空间*/
	/*分配空间,进行图像转换*/
	int width=ps->streams[videostream]->codecpar->width;
	int height=ps->streams[videostream]->codecpar->height;
	int fmt=ps->streams[videostream]->codecpar->format;/*流格式*/
	map_w=800;
	map_h=480;
	int size=avpicture_get_size(AV_PIX_FMT_BGR24, map_w,map_h);
	unsigned char *buff=NULL;
	printf("w=%d,h=%d,size=%dn",width,height,size);
	buff=av_malloc(size);
	/*计算一帧空间大小*/
	avpicture_fill((AVPicture *)frameRGB,buff,AV_PIX_FMT_BGR24,map_w,map_h);
	/*转换上下文*/
	struct SwsContext *swsctx=sws_getContext(width,height, fmt,map_w,map_h, AV_PIX_FMT_BGR24,SWS_BICUBIC,NULL,NULL,NULL);

	/*读帧*/
	int go=0;
	int Framecount=0;
	printf("read fream buffn");
	int audio_count=0;
	time_t sec=0,sec2=0;
	char buff_time[200]={0};
	struct tm result;
	while((av_read_frame(ps,packet)>=0))
	{
		sec=time(NULL);
		if(sec!=sec2)
		{
			sec2=sec;
			localtime_r(&sec2,&result);//将秒单位时间转换为时间结构体
			strftime(buff_time,sizeof(buff_time),"%H:%M:%S",&result);//时间格式化打印	
		}

		if(packet->stream_index == AVMEDIA_TYPE_VIDEO)/*判断是否为视频*/
		{
			res=avcodec_decode_video2(ps->streams[videostream]->codec,frame,&go,packet);
			if(res<0)
			{
				printf("avcodec_decode_video2 failedn");
				return -1;
			}
			if(go)
			{
				sws_scale(swsctx,(const uint8_t **)frame->data,frame->linesize,0,map_h,(const uint8_t **)frameRGB->data,frameRGB->linesize);
				lcd_p2=buff;
				NT35310_DisplayStr(lcd_widht/2-strlen(buff_time)/2*16,50,32,buff_time);
				LCD_Image(map_w,map_h,buff);
				Framecount++;
				//printf("frame index:%dn",Framecount);
			}
		}
		else if(packet->stream_index==AVMEDIA_TYPE_AUDIO)/*音频流*/
		{
			res=avcodec_decode_audio4(audstream->codec,audioframe,&go_audio,packet);
			if(res<0)
			{
				printf("decode_audio4 failedn");
				return -1;
			}
			if(go_audio)//音频数据处理
			{
			}
		}
	}
	av_free_packet(packet);
	sws_freeContext(swsctx);
	av_frame_free(&frame);
	av_frame_free(&frameRGB);
	avformat_free_context(ps);
	return 0;
}

*3;j+=3)>*w>

  makefile文件

CFLAGS=-I/home/wbyq/tiny4412_pack/ffmpeg-4.2.5/_install/include -L/home/wbyq/tiny4412_pack/ffmpeg-4.2.5/_install/lib 
CFLAGS+=-I/home/wbyq/tiny4412_pack/x264-master/_install/include -L/home/wbyq/tiny4412_pack/x264-master/_install/lib
CFLAGS+= -lpthread -lm -ldl -lavcodec -lavfilter -lavutil -lswresample -lavdevice -lavformat -lpostproc -lswscale -lpthread -lstdc++ -lm -lasound -lx264
OBJ=main.c ascii.c
app:
	arm-linux-gcc -o app $(OBJ) $(CFLAGS)   

4.相关函数介绍

4.1 打开输入流并读取头数据avformat_open_input

int avformat_open_input(AVFormatContext **ps, const char *filename, ff_const59 AVInputFormat *fmt, AVDictionary **options);
函数功能:打开一个输入流并读取头部信息,但编解码器不会打开
   1.分配一个AVFormatContext的实例。
   2.调用init_input函数初始化输入流的信息。这里会初始化AVInputFormat。
   3.根据上一步初始化好的AVInputFormat的类型,调用它的read_header方法,读取文件头。
形 参: AVFormatContext **ps 媒体文件或媒体流的构成和基本信息
   filename 输入文件名
   AVInputFormat *fmt 输入文件格式,一般填NULL即可。
     如果fmt参数非空,也就是人为的指定了一个AVInputFormat的实例,那么这个函数就不会再检测输入文件的格式了;如果fmt为空,那么这个函数就会自动探测输入文件的格式等信息。
     AVDictionary **options 附加的一些选项,一般填NULL即可;
返回值: 成功返回0

4.2 查找流信息avformat_find_stream_info

int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
函数功能:查找流信息
形参: AVFormatContext *ic 输入的流信息
   AVDictionary **options 附加的一些选项,一般填NULL即可;
返回值: 成功返回0

4.3 查找输入流中的音视频信息av_find_best_stream

int av_find_best_stream(AVFormatContext *ic,
           enum AVMediaType type,
           int wanted_stream_nb,
            int related_stream,
            AVCodec **decoder_ret,
           int flags);
形参: AVFormatContext *ic 输入的流信息
    type 查找类型AVMEDIA_TYPE_VIDEO视频、AVMEDIA_TYPE_AUDIO音频
     wanted_stream_nb 用户请求的流编号,-1用于自动选择,
    related_stream 尝试查找与此相关的流(例如,在同一程序中),如果没有,则为-1
    decoder_ret 如果非空,则返回所选流的解码器,可以填NULL,
     flags 标志,当前未定义任何
返回值: 成功情况下的非负流编号

4.4 初始化音视频编解码器avcodec_open2

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
函数功能:该函数用于 初始化 一个视音频编解码器的AVCodecContext。
形参:avctx 编解码器上下文
   codec 要打开的编解码器
   options 一个包含AVcodeContext和编解码器专用选项的存储工具。
返回值: 成功返回0,失败返回负数

4.5 分配一个重采样swr_alloc_set_opts

struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
           int64_t out_ch_layout,
           enum AVSampleFormat out_sample_fmt,
           int out_sample_rate,
           int64_t in_ch_layout,
           enum AVSampleFormat in_sample_fmt,
           int in_sample_rate,
           int log_offset,
           void *log_ctx);
函数功能:分配一个重采样,设置/重置公共参数
形参: s 现有的Swr上下文(如果可用),或NULL(如果不可用)
    out_ch_layout 输出声道格式
    out_sample_fmt 输出采样频率
    in_ch_layout 输入的声道布局
    in_sample_fmt 输入采样格式
    log_offse、log_ctx 日志信息,填0和NULL即可
返回值: 错误时为NULL,否则为已分配上下文

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 开源
    +关注

    关注

    3

    文章

    2985

    浏览量

    41709
  • 视频解码
    +关注

    关注

    1

    文章

    47

    浏览量

    17990
  • ffmpeg
    +关注

    关注

    0

    文章

    45

    浏览量

    7290
收藏 人收藏

    评论

    相关推荐

    Linux下基于ffmpeg视频解码

    FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频
    的头像 发表于 09-29 14:28 2883次阅读
    Linux下基于<b class='flag-5'>ffmpeg</b>音<b class='flag-5'>视频</b><b class='flag-5'>解码</b>

    【OK210申请】基于OK210的WIFI无线视频监控小车的设计与实现

    申请理由:1.有着对ARM的渴求度,对LINUX有一定的掌握2.本着自己为毕业一年的硬件开发工程师,希望能够接触到软硬结合的ARM系统3.资金有限,只能获得免费申请4.手里有一块TINY4412板子
    发表于 08-04 16:34

    免费试用“Tiny4412开发板——友善之臂Cortex-A9”

    本帖最后由 L490351555 于 2015-8-19 08:38 编辑 大家好,这两天咱们的论坛搞了一个开发板投票试用活动。现在有一个投票项就是“Tiny4412开发板——友善之臂
    发表于 08-18 19:09

    请问在4412的USB驱动程序里该如何修改?

    tiny4412遇到一个问题,4412作为USB设备与作为主机的PC连接,物理连接是USB线,在4412上需要把USB上的特殊数据解析出来,当做并口数据处理。请问在4412的USB驱
    发表于 05-17 00:12

    Tiny4412-Uboot启动后无法加载uImage

    好吧。。在这里先祈求,有哪位大大,或者老师,能关注下。个人一度试图移植tiny4412的uboot和kernel还有根文件系统。。。。。然后顺带学习一下设备树的用法这个是uboot配置ls/dev
    发表于 08-30 05:45

    怎么实现ffmpeg解码器到龙芯3B的移植

    本文实现ffmpeg解码器到龙芯3B的移植,并针对龙芯3B实现了对向量扩展指令支持的特点,对ffmpe
    发表于 06-02 06:57

    TINY4412 UART程序设计得相关资料分享

    嵌入式实验: TINY4412 UART 程序设计一、实验目的熟悉UART通信相关的寄存器的功能和设置方法,设置引脚复用,选择UART接收和发送对应的引脚用于UART通信,数据流格式设置,设置
    发表于 11-09 06:11

    如何实现Tiny4412通过NRF24L01 2.4G无线模块发送数据呢

    Linux下SPI设备驱动该怎样去编写呢?如何实现Tiny4412通过NRF24L01 2.4G无线模块发送数据呢?
    发表于 12-17 06:36

    iny4412嵌入式Linux操作系统启动流程是怎样的

    本次介绍一下友善之臂tiny4412嵌入式Linux操作系统分析首先,可以从官方提供的用户手册中得到这样一张图,它简单表达了裸机烧写启动系统的流程,不过这张图中缺少对BL2的描述,所以我就自己手绘了
    发表于 12-20 07:50

    基于FFmpeg + SDL2实现视频播放功能资料分享

    1、使用FFmpeg+SDL2在ART-Pi Smart平台上实现视频播放功能简介X264 是由 VideoLAN 开发的一个免费开源软件库和命令行实用程序,用于将视频流编码为 H.2
    发表于 08-05 11:40

    ffmpeg支持的音视频格式有哪些

    FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频
    发表于 11-01 08:43 2.2w次阅读

    FFMPEG视频解码流程 H.264硬件编解码实现

    本文阐述了基于FFMpeg的 H.264视频 硬件编解码在 S3C6410 处理器上的实现方法,为数字娱乐、视频监控和
    发表于 04-03 11:28 1.9w次阅读
    <b class='flag-5'>FFMPEG</b><b class='flag-5'>视频</b>编<b class='flag-5'>解码</b>流程 H.264硬件编<b class='flag-5'>解码</b><b class='flag-5'>实现</b>

    友善之臂Tiny4412核心板介绍

    Tiny4412是一款高性能的四核Cortex-A9核心板,由广州友善之臂设计、生产和发行销售。
    的头像 发表于 11-05 17:40 1.1w次阅读
    友善之臂<b class='flag-5'>Tiny4412</b>核心板介绍

    嵌入式实验: TINY4412 UART 程序设计

    嵌入式实验: TINY4412 UART 程序设计一、实验目的熟悉UART通信相关的寄存器的功能和设置方法,设置引脚复用,选择UART接收和发送对应的引脚用于UART通信,数据流格式设置,设置
    发表于 11-03 20:06 13次下载
    嵌入式实验: <b class='flag-5'>TINY4412</b> UART 程序设计

    在QT上构建ffmpeg环境实现音频的解码

    在QT上构建ffmpeg环境,实现音频的解码
    发表于 06-09 09:05 903次阅读
    在QT上构建<b class='flag-5'>ffmpeg</b>环境<b class='flag-5'>实现</b>音频的<b class='flag-5'>解码</b>