精华内容
下载资源
问答
  • ffmpeg实现将H264裸流封装成.mp4或.avi文件
    千次阅读
    2020-07-17 14:22:00

     ffmpeg学习历程

    由于我是移植到arm-linux环境(海思HI3521A),H264裸流直接从海思的编码模块VENC获取。

    H264数据流序列:    SPS, PPS, SEI, I, P, P, ... P, P,  SPS, PPS, SEI, I, P, P, ... P, P, ...

    源码如下:

    #include <stdio.h>
    #include "mpi_venc.h"
    
    #ifndef __STDC_CONSTANT_MACROS
    #define __STDC_CONSTANT_MACROS
    #endif
    
    extern "C"
    {
    #include "libavformat/avformat.h"
    #include "libavcodec/avcodec.h"
    }
    
    class video_file
    {
    private:
    	AVFormatContext *m_fmtCtx;
    	bool m_bNeedGlobalHeader;
    	bool m_bHadFillGlobalHeader;
    	bool m_bFoundFirstIDR;
    	int m_frameNum;
    	int m_videoIndex;
    
    public:
    	video_file();	
    	~video_file();
    	int create_and_open_file(const char* fileName);
    	int close_file();
    	int write_packet(VENC_STREAM_S *vencStream);
    };
    
    
    #include <stdio.h>
    #include "video_file.h"
    
    video_file::video_file()
    {
    	m_fmtCtx = NULL;
    	m_bNeedGlobalHeader = false;
    	m_bHadFillGlobalHeader = false;
    	m_bFoundFirstIDR = false;
    	m_frameNum = 0;
    	m_videoIndex = 0;
    }
    
    video_file::~video_file()
    {
    	close_file();
    }
    
    int video_file::create_and_open_file(const char* fileName)
    {
    	int ret, i;
    	AVOutputFormat *ofmt = NULL;
    	AVCodec *codec = NULL;
    	AVStream *stream = NULL;
    	AVCodecContext *codecCtx = NULL;
    
    	if(m_fmtCtx != NULL)
    	{
    		printf("Another open video file is not closed\n");
    		return -1;
    	}
    	
    	av_register_all();
    	
    	ret = avformat_alloc_output_context2(&m_fmtCtx, NULL, NULL, fileName);
    	if(ret < 0)
    	{
    		printf("Failed to alloc output format context [fileName: %s]\n", fileName);
    		return -1;
    	}
    	
    	ofmt = m_fmtCtx->oformat;	
    	codec = avcodec_find_encoder(ofmt->video_codec);
    	if(codec == NULL)
    	{
    		printf("No encoder[%s] found\n", avcodec_get_name(ofmt->video_codec));
    		goto fail;
    	}
    	
    	stream = avformat_new_stream(m_fmtCtx, codec);
    	if(stream == NULL)
    	{
    	   printf("Failed to alloc stream\n");
    	   goto fail;
    	}
    
    	m_videoIndex = stream->index;
    	codecCtx = stream->codec;
    	//宽高,帧率,编码格式
    	codecCtx->codec_id = AV_CODEC_ID_H264;
    	codecCtx->width = 1920;
    	codecCtx->height = 1080;
    	codecCtx->time_base.den = 30;
    	codecCtx->time_base.num = 1;
    	//codecCtx->gop_size = 30;
    	//codecCtx->bit_rate = 0;
    	//codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    
    	//MP4格式需要全局头信息,AVI不需要	
    	m_bNeedGlobalHeader = (m_fmtCtx->oformat->flags & AVFMT_GLOBALHEADER);
    	if(m_bNeedGlobalHeader)
    	{
    		codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
    		//extradata空间大小只需能装下SPS,PPS,SEI等即可
    		codecCtx->extradata = (uint8_t*)av_malloc(1024);
    		codecCtx->extradata_size = 0;
    		m_bHadFillGlobalHeader = false;
    	}
    	
    	printf("==========Output Information==========\n");
    	av_dump_format(m_fmtCtx, 0, fileName, 1);
    
    	if(!(ofmt->flags & AVFMT_NOFILE))
    	{
    		ret = avio_open(&m_fmtCtx->pb, fileName, AVIO_FLAG_WRITE);
    		if (ret < 0)
    		{
    			printf("could not open %s\n", fileName);
    			goto fail;
    		}
    	}
    
    	ret = avformat_write_header(m_fmtCtx, NULL);
    	if (ret < 0)
    	{
    		printf("Error occurred when opening output file \n");
    		goto fail;
    	}
    
    	m_frameNum = 0;
    	m_bFoundFirstIDR = false;
    	return 0;
    
    fail:
    	if(stream && stream->codec->extradata)
    		av_free(stream->codec->extradata);
    	if (m_fmtCtx && !(m_fmtCtx->flags & AVFMT_NOFILE))
    		avio_close(m_fmtCtx->pb);		
    	avformat_free_context(m_fmtCtx);
    	m_fmtCtx = NULL;
    	return -1;
    }
    
    //分析源码可知, 释放AVFormatContext是,会自动释放旗下的若干AVStream, 而AVStream释放时也会自动释放旗下的extradata
    int video_file::close_file()
    {
    	if(m_fmtCtx != NULL)
    	{
    		av_write_trailer(m_fmtCtx);
    		if (m_fmtCtx && !(m_fmtCtx->flags & AVFMT_NOFILE))
    			avio_close(m_fmtCtx->pb);
    		/*AVStream *stream = m_fmtCtx->streams[m_videoIndex];
    		if(stream && stream->codec->extradata)
    		{
    			av_free(stream->codec->extradata);
    			stream->codec->extradata = NULL;
    		}*/
    		avformat_free_context(m_fmtCtx);
    		m_fmtCtx = NULL;
    	}
    	return 0;
    }
    
    /* 海思的VENC的裸流NAL序列如下:
    *	SPS, PPS, SEI, I, P, P, ..., P, P,   SPS, PPS, SEI, I, P, P, ..., P, P
    */
    int video_file::write_packet(VENC_STREAM_S *vencStream)
    {
    	int ret;
    	unsigned int i; 
    	AVStream *stream = NULL;
    	AVPacket pkt;
    	bool bIsIDR;
    
    	if(m_fmtCtx == NULL)
    	{
    		printf("Video file is not opened\n");
    		return -1;
    	}
    
    	if(vencStream == NULL)
    	{
    		printf("Input stream is NULL\n");
    		return -1;
    	}
    
    	stream = m_fmtCtx->streams[m_videoIndex];
    	bIsIDR = (vencStream->u32PackCount > 1);
    	//写入封装器的第一帧必须是IDR帧
    	if(!m_bFoundFirstIDR)
    	{
    		if(!bIsIDR)
    			return 0;
    		else
    			m_bFoundFirstIDR = true;
    	}
    
    	for(i = 0 ; i < vencStream->u32PackCount; i++)
    	{
    		//当需要global header时,将SPS, PPS, SEI填入CodecContext的extradata
    		if(bIsIDR && m_bNeedGlobalHeader && (i < 3))
    		{
    			if(!m_bHadFillGlobalHeader)
    			{
    				memcpy(stream->codec->extradata + stream->codec->extradata_size, vencStream->pstPack[i].pu8Addr + vencStream->pstPack[i].u32Offset, vencStream->pstPack[i].u32Len - vencStream->pstPack[i].u32Offset);
    				stream->codec->extradata_size += vencStream->pstPack[i].u32Len - vencStream->pstPack[i].u32Offset;
    				if(i == 2)
    					m_bHadFillGlobalHeader = true;
    			}
    			continue;
    		}
    
    		av_init_packet(&pkt);	
    		pkt.flags |= bIsIDR ? AV_PKT_FLAG_KEY : 0;
    		pkt.stream_index = stream->index;
    		pkt.data = (unsigned char*)(vencStream->pstPack[i].pu8Addr + vencStream->pstPack[i].u32Offset);
    		pkt.size = vencStream->pstPack[i].u32Len - vencStream->pstPack[i].u32Offset;		
    		pkt.pts = av_rescale_q(m_frameNum, stream->codec->time_base, stream->time_base);
    		pkt.dts = pkt.pts;
    		pkt.duration = 0;	//0 if unknown.
    		pkt.pos = -1;		//-1 if unknown
    						  
    		ret = av_interleaved_write_frame(m_fmtCtx, &pkt);
    		if(ret < 0)
    		{
    		 	 printf("av_interleaved_write_frame failed\n");
    		 	 return -1;
    		}
    		
    		m_frameNum++;
    	}
    		
    	return 0;
    }
    

    使用方法:

    video_file mp4File;
    mp4File.create_and_open_file("output.mp4");
    mp4File.write_packet(&vencStream);
    mp4File.close_file();

     

    更多相关内容
  • 使用ffmpeg封装h264裸流为MP4文件,亲测,可修改时间戳实现输出视频的速度控制,附使用说明。
  • 利用ffmpeg库,将H264裸流文件读到内存,然后封装为MP4文件并保存到本地。转换效果亲测,流畅,无卡顿。
  • 支持h264和h265视频流封装成mp4文件和推流到rtmp服务器,资源是一个完整的VS工程,VS版本为2015,可直接运行。主要代码文件为zhf_h264_to_mp4_file.h和zhf_pushstream_rtmp.h
  • 可以读取H264文件,并从中提取每一帧(是完整一帧,不是NAL)的数据,并能获得视频的分辨率。
  • 本人在学习海康威视开发时写的一个DEMO,用海康提供的回调接口获取标准的H264裸码,可实现标准H264裸码封装MP4文件+保存.h264文件+实时预览。参数可自行修改。我的下载资源里面也有一个H264文件封装MP4文件的DMEO,...
  • 本库文件包含了所有在使用逐飞科技TC264母版中用到的封装,已经经过实际使用检验可用,内只包含封装库,不包含其他
  • ffmpeg是一个开源库,实现了对h264视频文件的解压缩。 为了降低使用ffmpeg的复杂性,尽量隐藏实现细节,我写了一个封装库。c#也可以很方便的使用此库。解压后的数据可以为yuv格式,也可以为rgb格式。同时可以对rgb...
  • 用C++实现H264编码视频封装成avi/mp4文件
  • 本压缩包含 ①开关 按键封装库.PcbLib ②开关 按键原理图.SchLib 封装是3D封装,为本人长期整理积累,希望对大家有帮助!
  • Mp4v2 H264封装为MP4

    2018-05-09 17:27:39
    根据MP4文件协议直接将H264封装成MP4格式,通过Mp4v2可以很方便的将H264编码成MP4格式文件 参考博客文章:https://blog.csdn.net/davebobo/article/details/79648900
  • 使用ffmpeg经H264裸码流封装为MP4文件。 使用ffmpeg经H264裸码流封装为MP4文件
  • 最近再封装H264文件,本来想想用ffmpeg,可惜设备端没有足够的空间放ffmpeg的库了,无奈只好开始撸协议自己封装了~首先至少得了解以下知识点:一 AVC H264 的一些基本概念和知识二 FLV封装格式三 AMF协议...

        最近再封装H264文件,本来想想用ffmpeg,可惜设备端没有足够的空间放ffmpeg的库了,无奈只好开始撸协议自己封装了~

    首先至少得了解以下知识点:

    【音视频技术】AVC H264的一些基本概念和知识点

    【音视频技术】FLV封装格式

    【音视频技术】AMF实用协议解析说明

    好了,开撸。

    FLV的封装格式就不说了,这篇博客着重说一下 H264中的NALU如何封装成 FLV中的video tag ,关于FLVheader 及FLV其他结构有不清楚的可以上网查其他资料或者看我写的这篇【音视频技术】FLV封装格式博客。

    -------------------------------------------------------------------------------------------------------------

    H264 的NALU 封装成FLV有三种不同的形式: 

    (H264 NALU 不清楚的【音视频技术】AVC H264的一些基本概念和知识点

    (1)H264 NALU type SPS +PPS;

    (2)H264 NALU type SEI;

    (3)H264 NALU type Slice 也就是 type值为(1-5);

    --------------------------------------------------------------------------------------------------------------

    (1)H264 NALU type SPS +PPS 封装成 FLV video tag:

        在H264的码流中 SPS 和 PPS是成对出现的,先是SPS然后是PPS,SPS对于H264来说就是编码后的第一帧、PPS是编码后的第二帧这两针携带的数据主要是编码器的一些属性,比如宽高 profile level deblock滤波器等等。

        在封装FLV中这两帧数据被合并到一个video TAG中:


    FLV tag header                Bytes                    value

    1)Tag type                     // 0                        0x09

    2)Data Size                    // 1-3                     0x00 0x00 0x24

    3)TimeStamp                 // 4-6                     0x00 0x00 0x00     (First frame)

    4)TimeStampExtend       // 7                        0x00

    5)StreamID                    // 8-10                  0x00 0x00 0x00   (always zero)


    AVC Video tag header         

    1)FrameType | CodecID       //11                             0x17

    2)AVCPacketType                //12                             0x00

    3)Composition Time              //13-15                       0x00 0x00 0x00


                                     


    AVCDecoderConfigurationRecord

    1)Configuration VerSion                 //16                  0x01      

    2)AVC Profile SPS[1]                     //17                   0x42       

    3)profile_compatibility SPS[2]       //18                   0x00      

    4)AVC Level SPS[3]                       //19                   0x2A      

    5)lengthSizeMinusOne                    //20                   0xFF

    6)numOfSequenceParameterSets //21                  0xE1      

    SPS

    1)SPS0 Length                                //22-23            0x0010

    2)SPS0 Data

    3)SPS(n) length /btyes 如果存在多个循环存放最多31个SPS

    4)SPS(n) Data

                                         

    PPS

    PPS  count                                         //1byte             0x01

    PPS0 Length                                     //2bytes           0x00 0x04

    PPS0 Data

    PPS(n) Length

    PPS(n) Data

    +PreviousTag Size


    --------------------------------------------------------------------------------------------------------

    (2)H264 NALU type Sei 封装成 FLV video tag:

        SEI NALU 是没有图像数据的,它的主要作用是对图像数据或者视频流的补充,有些内容可能对解码有帮助。在封装FLV文件中含义SEI的videoTAG其中包含色SEI数据还有SEI帧后紧跟着的一个IDR数据,其编码结构如下;


    FLV tag header                Bytes                    value

    1)Tag type                     // 0                          0x09

    2)Data Size                    // 1-3                     0x00 0x00 0x24

    3)TimeStamp                 // 4-6                     0x00 0x00 0x00     (First frame)

    4)TimeStampExtend       // 7                       0x00

    5)StreamID                    // 8-10                   0x00 0x00 0x00   (always zero)


    AVC Video tag header         

    1)FrameType | CodecID       //11                             0x27

    2)AVCPacketType                //12                             0x01

    3)Composition Time              //13-15                       0x00 0x00 0x00

    SEI

    1)SEI length                   //16-19                        0x00  0x00 0x00 0x05

    2)SEI Data                       // 20-N                       0x06 E5 01 81 80

    3)IDR NALU Length    //4Bytes               0x00 0x00 0x1F 0xF4

    4)IDR NALU Data

    +PreviousTag Size


    ----------------------------------------------------------------------------------------------------

    (3)H264 NALU type Slice 封装成 FLV video tag:

        Slice Type NALU (1-5) 就是H264 中一片一片的数据了,在FLV video tag中封装 如下:


    FLV tag header                Bytes                    value

    1)Tag type                     // 0                          0x09

    2)Data Size                    // 1-3                     0x00 0x95 0xF6

    3)TimeStamp                 // 4-6                     0x00 0x00 0x00     (First frame)

    4)TimeStampExtend       // 7                       0x00

    5)StreamID                    // 8-10                   0x00 0x00 0x00   (always zero)


    AVC Video tag header         

    1)FrameType | CodecID       //11                             0x27 or 0x17

    2)AVCPacketType                //12                             0x01

    3)Composition Time              //13-15                       0x00 0x00 0x00


    NALU

    NALU Length                        //   4bytes                     0x00 0x00 0x95 0xED

    NALU data

    +PreviousTag Size

        OK,上述就是H264在封装成FLV文件时的3中video tag。再说点调试时的经验吧。封装FLV我总共花了3天,第一天了解FLV协议,AMF协议,结合着flv的媒体文件来对照协议,理解各个字段的意思。大家可以使用UEdit这个工具来看二进制文件,也可以使用这个flv解析工具来直接解析flv文件 (还算挺好用的吧)。封装过程中有些大端小端的一定要注意,还有扩展时间戳位(不知道搞协议的人怎么想的搞出这个东西来)。第二天,再网上搞了一套代码,看懂后改了改 ,可以封装H264了 但是 生产出来的flv文件播放有马赛克。后来用ffmpeg封装对比前后的文件慢慢找出的端倪。错在SEI type的nalu 我处理的不对又改了改,大功告成。源代码的话我就不放了,如果按照我这个按部就班的做应该没问题的,我就是这么搞出来的。

    整个工作过程这篇博客给我的帮助是最大的,内容也是最正确的,其他看了好多感觉都有写的不对的地方(感谢感谢):

    打包H264码流到FLV文件







    展开全文
  • Qt工程,ffmpeg库和h264测试文件。纯原创,仅供交流学习。
  • ffmpeg摄像头数据h264编码并封装avi http://blog.csdn.net/jklinux/article/details/72478004
  • h264和aac格式介绍及mp4文件封装

    千次阅读 2020-08-16 16:01:47
    mp4封装目录h264视频流格式介绍aac音频流格式介绍h264视频文件读取通过帧索引解析h264文件通过解析h264结构读取文件aac音频文件读取mp4封装初始化注意点 目录 h264视频流格式介绍 视频数据帧分为I帧,P帧,B帧,其中I...

    目录

    h264视频流格式介绍

    • 视频数据帧分为I帧,P帧,B帧,其中I帧为关键帧,所包含的图像信息最全,因而数据量最大,其他帧都有I帧通过计算而来

    • GOP
      在这里插入图片描述

    a) 所谓GOP就是1组图像Group of Picture,在这一组图像中有且只有1个I帧,多个P帧或B帧,两个I帧之间的帧数,就是一个GOP
    b) GOP一般设置为编码器每秒输出的帧数,即每秒帧率,一般为25或30,当然也可设置为其他值
    c) 在一个GOP中,P、B帧是由I帧预测得到的,当I帧的图像质量比较差时,会影响到一个GOP中后续P、B帧的图像质量,直到下一个GOP 开始才有可能得以恢复,所以GOP值也不宜设置过大
    d) 一般在播放时,为保证图像质量,第一帧应该播放I帧

    • H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位

    • H264 Annexb byte-stream格式
      在这里插入图片描述

    a) SODB:String of Data Bits,数据 bit 流,最原始的编码数据
    b) RBSP:Raw Byte Sequence Payload,原始字节序列载荷,在SODB的后面填加了结尾比特,RBSP trailing bits 一个bit“1”,若干比特“0”,以便字节对齐
    c) EBSP:Encapsulated Byte Sequence Payload,扩展字节序列载荷,在RBSP基础上填加了仿校验字节(0x03)。
    d) Start-code:在NALU加到Annexb即byte-stream格式时,需要在每组NALU之前添加开始码StartCode,如果该NALU对应的slice为1个GOP开始则用4位字节表示,0x00000001,否则用3位字节表示0x000001(也不一定)

    • H264网络传输的结构
      在这里插入图片描述
    • NALU头结构
      长度:1byte
      forbidden_bit(1bit) + nal_reference_bit(2bit) + nal_unit_type(5bit)
      在这里插入图片描述

    a) 位信息

    bitdesc
    F禁止位,0表示正常,1表示错误,一般都是0
    NRI重要级别,11表示非常重要,一般取值为11、10、01
    Typenal_unit_type(表示该NALU的类型是什么,类型的具体取值可见下表)

    b) nal_unit_type

    nal_unit_type012345678910111213-2324-31
    NAL类型未使用非IDR的片片数据A分区片数据B分区片数据C分区一个序列的第一个图像叫做IDR图像(立即刷新图像),IDR图像都是I帧补充增强信息单元(SEI)序列参数集(SPS)图像参数集(PPS)分界符序列结束码流结束填充保留未使用

    c) H264要求I帧为:帧分隔符+SPS+帧分隔符+PPS+帧分隔符+IDR

    帧分隔符SPS帧分隔符PPS帧分隔符IDR
    0x00 00 010x67…0x00 00 010x68…0x00 00 010x65…

    d) NALU start-code:0x00 00 00 01/0x00 00 01

    • H264 AVCC格式

    a) Annex-B:没有NALU长度字节,使用start code分隔NALU,start code为三字节或四字节,0x000001或0x00000001,一般是四字节;SPS和PPS按流的方式写在一组GOP之前。
    b) AVCC:使用NALU长度,固定字节,通常为4字节,分隔NALU;一般在每个NALU头部为4字节大端格式的长度字节,在一组GOP的头部包含extradata结构,用于存储sequence-header、SPS、PPS数据。
    c) 虽然AVCC格式不使用起始码,防竞争字节仍然存在
    d) SPS和PPS被存储在了非NALU包中(out of band带外),即独立于基本流数据
    e) mp4文件即是采用这种存储方式

    aac音频流格式介绍

    • aac有9中规格(LC/Main/SSR/LD…),LC为常用规格

    • aac文件格式有两种ADIF,ADTS

    a) ADIF:头信息只在文件首部,解码必须在首部开始,获取头信息后,剩余全是音频数据
    b) ADTS:每一帧都含有头信息,解码可以在任意位置
    在这里插入图片描述

    • ADTS的头信息为两部分组成,其一为固定头信息,紧接着是可变头信息

    a) adts固定头结构
    在这里插入图片描述
    b) adts可变头结构
    在这里插入图片描述

    • adts头字段含义

    a) syncword:同步字,一般为二进制"1111 1111 1111",用于找出帧头在比特流中的位置
    b) ID:MPEG 标示符
    c) layer:指示使用哪一层
    d) protection_absent:表示是否误码校验
    e) profile:表示使用哪个级别的AAC,如01:Low Complexity(LC)即为AACLC
    f) sampling_frequency_index:表示使用的采样率下标,如下图
    在这里插入图片描述
    g) channel_configuration:声道数

    0x000x010x020x030x040x050x060x070x08-0x0f
    单声道双声道三声道四声道五声道5.1声道7.1声道保留

    h) aac_frame_length:aac一帧数据大小,一个ADTS帧的长度包括ADTS头和raw data block
    i) adts_buffer_fullness:是否是码率可变码流(0x7FF:可变)
    j) number_of_raw_data_blocks_in_frame:表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧,
    所以说number_of_raw_data_blocks_in_frame == 0 表示说ADTS帧中有一个AAC数据块并不是说没有

    h264视频文件读取

    h264文件读取有两种方式:通过帧索引和通过解析h264结构

    通过帧索引解析h264文件

    所谓帧索引即是通过专门软件将h264文件中每一帧的信息做成索引存储在一个文件中,索引文件需要存储的信息有:

    • 每一帧的地址(在源文件中的位置)
      每次都从对应地址开始读取本帧数据
    • 每一帧的数据大小
    • 帧格式
      需要表明是否为I帧
    • 时间戳

    该方法比较简单,在此不做赘述

    通过解析h264结构读取文件

    h264文件每一帧都由分隔符隔开,分隔符或为0x00,0x00,0x00,0x01,或为0x00,0x00,0x01,解析时遇分隔符即为一帧起始,两个分隔符之间的即为一帧数据,紧跟分隔符的是该帧类型。
    在这里插入图片描述

    aac音频文件读取

    adts头部信息包含一帧音频数据的大小,该大小包含7字节的头部,因此实际数据需要跳过头部读取,相应大小也应减去7。
    aac帧大小信息计算

    mp4封装

    相关API用法网上很多,在此不做详解。

    初始化

    • 初始化包括创建生成的文件句柄,生成track信息,设置视频sps,pps信息,fps信息和图像width,height,以及设置音频specfice config信息,采样率等。
      伪代码如下:
    int mp4_init(const char *mp4_name)
    {
    	encoder->f_h = MP4Create(mp4_name, 0);
    	if (encoder->f_h == MP4_INVALID_FILE_HANDLE) {
    		printf("create mp4 file failed\n");
    		return -1;
    	}
    
    	MP4SetTimeScale(encoder->f_h, g_h264_timeScale);  //g_h264_timeScale一般设为90000
    
    	/* 创建video track */
    	encoder->h264_t = MP4AddH264VideoTrack(encoder->f_h, g_h264_timeScale,
    											g_h264_timeScale / g_h264_fps,
    											g_width, g_height, encoder->sps[4],
    											encoder->sps[5], encoder->sps[6], 3); //此处传入的sps信息要跳过分隔符和帧类型字段
    	if (encoder->h264_t == MP4_INVALID_TRACK_ID) {
    		 printf("add video track failed\n");
    		 return -1;
    	}
    	MP4SetVideoProfileLevel(encoder->f_h, 0x7f);
    	
    	/* 设置sps,pps信息 */
    	MP4AddH264SequenceParameterSet(encoder->f_h, encoder->h264_t,
    									encoder->sps + 3, encoder->sps_length - 3); //此处传入的sps信息要跳过分隔符
    	MP4AddH264PictureParameterSet(encoder->f_h, encoder->h264_t, encoder->pps + 3, encoder->pps_length);
    
    	/* 创建audio track */
    	encoder->aac_t = MP4AddAudioTrack(encoder->f_h, g_aac_timeScale, 1024, MP4_MPEG4_AUDIO_TYPE);
    	if (encoder->aac_t == MP4_INVALID_TRACK_ID) {
    		 printf("add audio track failed\n");
    		 return -1;
    	}
    	MP4SetAudioProfileLevel(encoder->f_h, 0x2);
    	
    	/* 设置acc specfice config信息 */
    	MP4SetTrackESConfiguration(encoder->f_h, encoder->aac_t, g_spec_cfg, 2);
    
    	return 0;
    }
    

    数据封装

    int mp4_packeted(unsigned char *h264_buffer,int h264_frame_len,
    					unsigned char *aac_buffer,int aac_frame_len,bool i_frame)
    {
    	if (video) {
    		if (!MP4WriteSample(encoder->f_h, encoder->h264_t, h264_buffer, h264_frame_len, MP4_INVALID_DURATION, 0, i_frame)) {  //最后一个参数代表是否为关键帧,是则为true
    			printf("video MP4WriteSample failed\n");
    		}
    	}
    	if (audio)) {
    		if (!MP4WriteSample(encoder->f_h, encoder->aac_t, aac_buffer, aac_frame_len, MP4_INVALID_DURATION, 0, 1)) {  //音频写入时最后参数置1即可
    			printf("audio MP4WriteSample failed\n");
    		}
    
    	}
    	return 0;
    }
    

    视频数据写入时帧前4字节替换为该帧大小,且为大端形式;音频数据写入时需要去掉adts头(某些不能去掉,具体原因暂未深入研究)。

    • 替换视频帧头
    int nal_size = h264_frame_len - 4;
    h264_frame[0] = (nal_size & 0xff000000) >> 24;
    h264_frame[1] = (nal_size & 0x00ff0000) >> 16;
    h264_frame[2] = (nal_size & 0x0000ff00) >> 8;
    h264_frame[3] =  nal_size & 0x000000ff;
    

    关闭mp4文件句柄

    MP4Close(encoder->f_h, MP4_CLOSE_DO_NOT_COMPUTE_BITRATE);
    

    在此需要注意分隔符为0x00,0x00,0x01的情况,此时读取视频帧时应将h264_frame[0]留出来,视频帧从h264_frame[1]开始存入,以便后续替换前4字节。

    注意点

    • mp4v2支持h264+aac封装为mp4,不支持h265
    • MP4AddH264VideoTrack()和MP4AddH264SequenceParameterSet(),MP4AddH264PictureParameterSet()需要传入sps,pps数据,该数据是去掉流分隔符的
    • MP4SetTrackESConfiguration()需要传入音频流的AAC object types
    • sps,pps信息不用写入数据区
    • 初始化时视频fps要设置正确否则会出现封装的mp4视频播放变慢问题。
    • 封装完毕需要调用MP4Close()关闭mp4句柄,否则封装的mp4文件无法播放,使用vlc播放报错解析moov等结构失败。
    • 视频帧前4字节必须为帧大小,若该处设置错误,使用vlc播放报错如下:
    [h264 @ 0x7f1dcccf7f60] AVC: nal size 20
    [h264 @ 0x7f1dcccf7f60] AVC: nal size 20
    [h264 @ 0x7f1dcccf7f60] no frame!
    
    展开全文
  • AD库文件(元件库+封装库+3D模型),某宝的。包括常用电容电阻的插件和贴片封装;STM32芯片封装;二极管、三极管封装;电源芯片封装;FPGA封装等。涉及厂商:TI、Altera、NXP、Atmel等
  • SOT封装(三维PCB封装库)AD用PCB封装库,作者主页下有全套的三维PCB封装库,欢迎大家下载使用。文件为作者千辛万苦整理的,请大家自用,不要随意传播,谢谢!~
  • 将Python文件封装exe文件

    千次阅读 2020-05-31 18:28:32
    前言:相信我们学会做一个简单的Python文件后,总会想...用了一个早上,总算会知道怎么把.py文件封装成.exe文件了,心累~ 首先,把py文件统一放在一个文件夹里,然后打开文件夹,按住shift+右键,点击 Powersheel

    前言:相信我们学会做一个简单的Python文件后,总会想迫不及待的给自己的小伙伴看看,奈何他们的电脑没有安装Python编译器,这该怎么办呢?

    我们比较常用封装的,就是pyinstaller模块,这个需要pip下载
    下载公式:Windows+R,写入cmd,然后输入 pip install pyinstaller  
    就可以下载安装了
    

    用了一个早上,总算会知道怎么把.py文件封装成.exe文件了,心累~
    首先,把py文件统一放在一个文件夹里,然后打开文件夹,按住shift+右键,点击 Powersheel
    注意一定要按住
    然后弹出此页面:
    在这里插入图片描述

    输入公式:pyinstaller -F -i F:/text/logo.ico -w xxx.py
    解释:
    -F ~如果直接只有一个.py文件,并且没有引用第三方模块(即不用pip下载的),就加上-F,这样只生成了一个.exe文件,自己看上去也比较完美,如果引用了第三方模块,就不用写 -F了

    -i F:/text/logo.ico ~这个是用来改变.exe的图标的,注意一点要用.ico的图片,不能用.jpg、.png类的
    Q:直接改后缀名不就可以了?
    A:那是不行的,不然后面会报很多bug,最好的办法是,点击这个链接,找到自己喜欢的logo,链接:https://www.easyicon.net/
    -w ~加上后,在双击.exe文件时,就不会出现黑色的窗口,如果码的代码用GUI页面的,就一定要加上;如果需要自己输入、输出的,就不用加-w了
    xxx.py ~需要封装的py文件

    然后稍等一下,如果全部都是INFO: ,那就证明欧克了
    在这里插入图片描述我们再打开py所在的文件夹,发现多了三个文件夹和一个.spec的文件,我们打开dist的文件夹,找到.exe文件,双击运行就好了
    在这里插入图片描述在这里插入图片描述因为我改了一下logo(在刚才那个链接里面找的),所以看上去像是微信的安装包,小伙伴们可以把.exe文件发给朋友了,注意:要让他们在Windows电脑上运行哦,在手机上是不行的。

    觉得有帮助就麻烦点个赞吧,谢谢~

    展开全文
  • 若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 本文章博客地址:... 目录 前言 YUV格式详解 ...H264编码 概述 功能 性价比 码率 帧数 M...
  • STM32F103C8开发板 STM32最小系统核心板 AD硬件原理图+PCB封装文件,手册,软件开发历程
  • 排针-排母封装(三维PCB封装库)AD用PCB封装库,作者主页下有全套的三维PCB封装库,欢迎大家下载使用。文件为作者千辛万苦整理的,请大家自用,不要随意传播,谢谢!~
  • 通过编码器得到的h264视频流仅仅是裸流,只包含一些流的头信息和视频数据,没有时间戳的概念,所以使用播放器播放h264视频时,会出现播放速度不正常的现象(我遇到的是快进现象),所以将h264封装成MP4格式可以添加...
  • AD库文件(元件库+封装库+3D模型),包含大量常用元器件、芯片封装,包括常用电容电阻的插件和贴片封装,二极管、三极管封装,以及TI、Altera、NXP、Atmel等各大厂商的芯片封装,包括电源芯片、FPGA、STM32芯片等...
  • c++封装ini文件的读写类

    热门讨论 2011-07-08 14:35:47
    一般应用程序都会写配置文件(设置启动的一些参数),而配置文件大多都采用ini文件格式,在MFC下ini文件有自己的封装的类,比较容易操作!在此提供纯c++下ini类的读写操作类,当然参数转换之后也可以应用到MFC框架之...
  • DXP各种晶振封装文件

    热门讨论 2015-06-09 20:05:26
    DXP各种晶振封装文件,无源有源晶振PCB封装
  • Python代码.py文件封装为.pyd文件

    千次阅读 2021-10-30 00:01:44
    1、首先安装cython、setuptools包,安装命令:...3、写一个封装程序,可命名为packup.py,和待封装.py文件位于同一目录下,代码如下: from setuptools import setup from Cython.Build import cythonize setup(name='
  • 在实际运用中上传是一个必不可少的功能,所以我们在封装二的基础上加入上传的功能,同时需要附带上传进度,结合rxjava使用;原理和封装方法 http://blog.csdn.net/wzgiceman/article/details/51939574
  • QFN封装文件

    热门讨论 2013-08-31 10:14:12
    QFN5*5封装,经验交流,共享给大家。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,263,946
精华内容 505,578
关键字:

未封装的264文件