/*
编译命令:arm-linux-gcc -o show2642 264showyuv2.c -I/usr/local/ffmpeg_arm/include/   -L/usr/local/ffmpeg_arm/lib/ -lswresample -lavformat -lavutil -lavcodec -lswscale -lx264   libSDL.a
*/
#include "stdio.h"
#include "stdlib.h"

#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/fifo.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avstring.h"
#include "libavutil/imgutils.h"
#include "libavutil/timestamp.h"
#include "libavutil/bprint.h"
#include "libavutil/time.h"
#include "libavutil/threadmessage.h"
#include "/usr/local/ffmpeg_arm/include/SDL/SDL.h"

#include "libavfilter/avcodec.h"
#include "libavcodec/avcodec.h"

#if HAVE_SYS_RESOURCE_H
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#elif HAVE_GETPROCESSTIMES
#include <windows.h>
#endif
#if HAVE_GETPROCESSMEMORYINFO
#include <windows.h>
#include <psapi.h>
#endif

#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

#if HAVE_TERMIOS_H
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif HAVE_KBHIT
#include <conio.h>
#endif

#if HAVE_PTHREADS
#include <pthread.h>
#endif

#include <time.h>

#include "libavutil/avassert.h"

#define MAX_LEN  1024 * 50

////此方法参考官网的例子
static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
                     FILE *f)
{
  //  FILE *f;
    int i;
   // f = fopen(filename,"w");
   // fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
    for (i = 0; i < ysize; i++)
        fwrite(buf + i * wrap, 1, xsize, f);
  //  fclose(f);
}

int main()
{
	//下面初始化h264解码库
	//avcodec_init();
        int w = 720;
        int h = 576,retu;
        SDL_Rect rect;
	av_register_all();

	AVFrame *pFrame_ = NULL;

	/* find the video encoder */
	AVCodec *videoCodec = avcodec_find_decoder(CODEC_ID_H264);//得到264的解码器类
	if(!videoCodec)
	{
		printf("avcodec_find_decoder error\n");
		return -1;
	}

	AVCodecParserContext *avParserContext = av_parser_init(CODEC_ID_H264);//得到解析帧类,主要用于后面的帧头查找
	if(!avParserContext)
	{
		printf("av_parser_init  error\n");
		return -1;
	}
	AVCodecContext *codec_ = avcodec_alloc_context3(videoCodec);//解码会话层
	if(!codec_)
	{
		printf("avcodec_alloc_context3  error\n");
		return -1;
	}

	//初始化参数,下面的参数应该由具体的业务决定
	codec_->time_base.num = 1;
	codec_->frame_number = 1; //每包一个视频帧
	codec_->codec_type = AVMEDIA_TYPE_VIDEO;
	codec_->bit_rate = 0;
	codec_->time_base.den = 25;//帧率
	codec_->width = 720;//视频宽
	codec_->height = 576;//视频高

	if(avcodec_open2(codec_, videoCodec, NULL) >= 0)//打开解码器
	{
		pFrame_ = avcodec_alloc_frame();// Allocate video frame    成功打开解码器后, 此时可以分配帧内存, 当然你也可以在后面每次都分配、释放, 在此我省功夫, 只在开始分配一次
		if (!pFrame_) {
			fprintf(stderr, "Could not allocate video frame\n");
			exit(1);
		}
	}
	else
	{
		printf("avcodec_open2 error\n");
		return -1;
	}

	AVPacket packet = {0};
	int dwBufsize = 10;
	int frameFinished = dwBufsize;//这个是随便填入数字,没什么作用

	av_init_packet(&packet);
	packet.data = NULL;//这里填入一个指向完整H264数据帧的指针
	packet.size = 0;//这个填入H264数据帧的大小

	FILE *myH264 = fopen("1.264", "rb");//解码的文件264
	if(myH264 == NULL)
	{
		perror("cant open 264 file\n");
		return -1;
	}

	FILE *yuvfile = fopen("my264.yuv", "wb");//成功解码后保存成的YUV文件, 可以用YUV工具打开浏览
	if(yuvfile == NULL)
	{
		perror("cant open YUV file\n");
		return -1;
	}

	int readFileLen = 1;
	char readBuf[MAX_LEN];
	unsigned char *parseBuf = malloc(20*MAX_LEN);//这个地方浪费了我一个下午时间, 当时我用的是栈内存,即unsigned char parseBuf[20*MAX_LEN], 结果运行程序一直报错, 此处需要用堆内存才能正常解码
	int  parseBufLen = 0;

	int frameCount = 0;
	printf("begin...\n");
	printf("readBuf address  is %x\n", readBuf);
/////////////////////////SDL init////////////////////////////////////////
    SDL_Surface* hello = NULL;
    SDL_Surface* screen = NULL;

    //Start SDL
   // SDL_Init( SDL_INIT_EVERYTHING );
      SDL_Init(SDL_INIT_VIDEO);

    //Set up screen
    screen = SDL_SetVideoMode( 1024, 768, 32, SDL_SWSURFACE );
    SDL_Overlay* overlay = SDL_CreateYUVOverlay(w, h, SDL_YV12_OVERLAY, screen);

    SDL_LockSurface(screen);
    SDL_LockYUVOverlay(overlay);
//////////////////////////////////////////////////////////////////////
	while(readFileLen > 0)//开始解码工作
	{
		//printf("begin...\n");
		readFileLen = fread(readBuf, 1, sizeof(readBuf), myH264);//首先从文件里读出数据
		if(readFileLen <= 0)
		{
			printf("read over\n");
			break;
		}
		else
		{
			int handleLen = 0;
			int handleFileLen = readFileLen;
			while(handleFileLen > 0)
			{
				int nLength = av_parser_parse2(avParserContext, codec_, &parseBuf, &parseBufLen, readBuf + handleLen, handleFileLen, 0, 0, 0);//查找264帧头

				handleFileLen -= nLength;
				handleLen += nLength;

				if(parseBufLen <= 0)//当parseBufLen大于0时,说明查找到了帧头
				{
					continue;
				}
				packet.size = parseBufLen;//将查找到的帧长度送入
				packet.data = parseBuf;//将查找到的帧内存送入
                                 if(frameCount>100)break;
				//printf("parseBuf address is %x\n", parseBuf);
				while(packet.size > 0)
				{//下面开始真正的解码
					int decodeLen = avcodec_decode_video2(codec_, pFrame_, &frameFinished, &packet);
					if(decodeLen < 0)
						break;
					packet.size -= decodeLen;
					packet.data += decodeLen;
					if(frameFinished > 0)//成功解码
					{
						int picSize = codec_->height * codec_->width;
						//int newSize = picSize * 1.5;

						//申请内存
						//unsigned char *buf = malloc(newSize);

						int height = pFrame_->height;
						int width = pFrame_->width;

						//printf("OK, get data\n");
						//printf("Frame height is %d\n", height);
						//printf("Frame width is %d\n", width);
						frameCount ++;
						printf("Frame count is %d\n", frameCount);

						pgm_save(pFrame_->data[0], pFrame_->linesize[0],//保存Y
                 codec_->width, codec_->height, yuvfile);
						pgm_save(pFrame_->data[1], pFrame_->linesize[1],//保存U
                 codec_->width/2, codec_->height/2, yuvfile);
						pgm_save(pFrame_->data[2], pFrame_->linesize[2],//保存V
                 codec_->width/2, codec_->height/2, yuvfile);

                        ///有了YUV数据, 后面可以用FFMPEG提供的转换方法,将其转成RGB数据,进行后续的显示或其它的图像处理工作
                                            ////sdl
                                                int i;
                                                for(i=0;i<576;i++)
                                                {//fwrite(buf + i * wrap, 1, xsize, f);
                                                     memcpy(overlay->pixels[0]+i*720, pFrame_->data[0]+i*pFrame_->linesize[0], 720);
                                                }
		                                for(i=0;i<288;i++)
                                                {
						     memcpy(overlay->pixels[2]+i*360, pFrame_->data[1]+i*pFrame_->linesize[1], 360);
						     memcpy(overlay->pixels[1]+i*360, pFrame_->data[2]+i*pFrame_->linesize[2], 360);                                                                      }

						SDL_UnlockYUVOverlay(overlay);
						SDL_UnlockSurface(screen);

						rect.w = w;
						rect.h = h;
						rect.x = rect.y = 0;
						SDL_DisplayYUVOverlay(overlay, &rect);
		                            //sdl
						//SDL_Delay(40);
					}
					else
						printf("failed to decodec\n");
				}
			}
		}
	}
    //////释放工作
	avcodec_close(codec_);
	av_free(codec_);
	av_free_packet(&packet);
	av_frame_free(&pFrame_);
    //SDL
        SDL_FreeYUVOverlay(overlay);
        SDL_FreeSurface(screen);
    //Quit SDL
        SDL_Quit();
	fclose(yuvfile);
	fclose(myH264);

}

嵌入式linux------ffmpeg移植 解码H264(am335x解码H264到yuv420并通过SDL显示)的更多相关文章

  1. 【课程分享】深入浅出嵌入式linux系统移植开发 (环境搭建、uboot的移植、嵌入式内核的配置与编译)

    深入浅出嵌入式linux系统移植开发 (环境搭建.uboot的移植.嵌入式内核的配置与编译) 亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的,能够加我的QQ2059055336和我联系 ...

  2. 嵌入式linux系统移植(一)

    内容:   交叉编译环境   bootloader功能子系统   内核核心子系统   文件系统子系统要点:  搭建交叉编译环境  bootloader的选择和移植  kernel的配置.编译.移植和调 ...

  3. 嵌入式Linux系统移植——uboot常用命令

    flash的一般分区: 其它数据 环境变量 可执行程序.如bootloader print(可缩写为:pri):打印查看uboot这个软件中集成的环境变量setenv.saveenv:设置.保存环境变 ...

  4. 嵌入式Linux系统移植(二)——交叉编译工具集

    常用工具:readelf.size.nm.strip.strings.objdump.objcopy.addr2line readelf:读可执行文件的elf头 ELF Header: Magic: ...

  5. 手把手带你基于嵌入式Linux移植samba服务

    摘要:Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成. 本文分享自华为云社区<嵌入式Linux下移植samba服务--<基于北斗和4G ca ...

  6. 嵌入式linux和嵌入式android系统有什么区别和联系?

    转自:http://bbs.eeworld.com.cn/thread-430437-1-1.html 这个问题很多人问,尤其是初入嵌入式的菜鸟.其实大家都认为android是java,已经不是lin ...

  7. [ffmpeg] h264并行解码

    ffmpeg中的并行解码分为两种: Frame-level Parallelism Slice-level Parallelism Frame-level Parallelism 帧间依赖 我们之前讨 ...

  8. ffmpeg H264 编解码配置

    ffmpeg H264编解码前面有文章介绍下,本文主要介绍一些参数配置. 编码: int InitEncoderCodec( int iWidth, int iHeight) { AVCodec * ...

  9. 利用ffmpeg将H264流 解码为RGB

    利用H264解码分为几个步骤: 注意一点在添加头文件的时候要添加extern "C",不然会出现错误 [cpp] view plaincopy extern "C&quo ...

随机推荐

  1. JAVA设计模式---命令模式

    1.定义: 将“请求”封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象,命令模式也支持可撤销的操作.命令可以用来实现日志和事务系统. 2.实例: 1)需求:设计一个家电遥控器的API,遥控 ...

  2. HTTP协议篇(一):多工、数据流

    管道机制.多工 管道机制(Pipelining) HTTP 1.1 引入了管道机制(Pipelining),即客户端可通过同一个TCP连接同时发送多个请求.如果客户端需要请求两个资源,以前的做法是在同 ...

  3. CentOS 6.3 SSH连接时很慢的解决方法

    SSH的配置文件,默认开启了DNS反向解析,这使得处于同一个局域网下的终端,在SSH到服务器的时候异常缓慢,如果从是外网SSH到服务器的话,速度则是正常的.我们只需要关闭DNS反向解析即可. 修改/e ...

  4. CodeChef Little Elephant and Mouses [DP]

    https://www.codechef.com/problems/LEMOUSE 题意: 有一个n *m的网格.有一头大象,初始时在(1,1),要移动到(n,m),每次只能向右或者向下走.有些格子中 ...

  5. java windows自动化-mail自动发邮件

    本文旨在让测试人员了解如何发邮件 发邮件的话,最简单的事是直接手动发邮件,但是在自动化测试中,应做到让机器或者代码来自动发送邮件,笔者大概了解以下几种方法,总有一款口味适合你:1java代码来做下面即 ...

  6. .vue文件在webstorm中es6语法报错解决方法

    1 语法支持es6设置 Preferences > Languages & Frameworks > JavaScript 把 Javascript Language versio ...

  7. 浏览器中显示PPT的展示效果

    发现了一个PPT的WEb展示的方法,在浏览器中载入PDF文件之后,可以实现基于WEB的页面展示,支持全屏与自动播放. https://sharedoc.onk.ninja/ 这不失为一种可行的方式,且 ...

  8. 页面刷新方式实时检测cookie是否失效

    在浏览器端每隔10秒钟刷新一次页面,可用于检查cookie值是否失效. 在study.php文件中存在这样一条语句: <meta http-equiv="refresh" c ...

  9. egametang框架服务端运行流程

    et框架的构建块主要由entity和componet组成,类似unity的组件.一个Entity可以挂载多个不同Component.Entity和Component的共同基类Disposer用于提供对 ...

  10. es6变量声明和解构赋值

    /*声明: * 本文内容多为学习借鉴性内容,大部分非原创 * 特别感谢阮一峰的 ECMAScript6 入门,推荐大家学习 */ 一.es5变量声明的不足 1.变量提升和函数声明提升 es5的代码加载 ...