欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++利用GPAC實(shí)現(xiàn)生成MP4文件的示例代碼

 更新時(shí)間:2023年02月06日 11:19:57   作者:byxdaz  
GPAC主要針對(duì)學(xué)生和內(nèi)容創(chuàng)作者,代表了一個(gè)跨平臺(tái)的多媒體框架,開(kāi)發(fā)人員可以使用它在?LGPL?許可下制作開(kāi)源媒體。本文就來(lái)用GPAC實(shí)現(xiàn)生成MP4文件,感興趣的可以了解一下

GPAC主要針對(duì)學(xué)生和內(nèi)容創(chuàng)作者,代表了一個(gè)跨平臺(tái)的多媒體框架,開(kāi)發(fā)人員可以使用它在 LGPL 許可下制作開(kāi)源媒體。GPAC多媒體框架兼容范圍廣泛的流行文件類型,從常見(jiàn)格式(如 AVI、MPEG 和 MOV)到復(fù)雜格式(如 MPEG-4 系統(tǒng)或 VRML/X3D)和 360 電影。

一、MP4Writer類

MP4Writer.h文件

#ifndef _MP4WRITER_H_
#define _MP4WRITER_H_
 
#define GPAC_MP4BOX_MINI
#include "gpac/setup.h"
 
 
 
#define MP4_AUDIO_TYPE_INVALID      0
#define MP4_AUDIO_TYPE_AAC_MAIN     1
#define MP4_AUDIO_TYPE_AAC_LC       2
#define MP4_AUDIO_TYPE_AAC_SSR      3
#define MP4_AUDIO_TYPE_AAC_LD      23
 
 
 
 
#ifdef __cplusplus
extern "C" {
#endif
 
void* MP4_Init();
s32  MP4_CreatFile(void *pCMP4Writer, char *strFileName);
s32  MP4_InitVideo265(void *pCMP4Writer, u32 TimeScale);
s32  MP4_Write265Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
s32  MP4_InitVideo264(void *pCMP4Writer, u32 TimeScale);
s32  MP4_Write264Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
s32  MP4_InitAudioAAC(void *pCMP4Writer, u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale);
s32  MP4_WriteAACSample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp);
void MP4_CloseFile(void *pCMP4Writer);
void MP4_Exit(void *pCMP4Writer);
 
 
#ifdef __cplusplus
}
#endif
 
 
 
#endif

MP4Writer.cpp文件

#include "MP4Writer.h"
 
#include <Winsock2.h>
 
 
extern "C" {
#include "gpac/isomedia.h"
#include "gpac/constants.h"
#include "gpac/internal/media_dev.h"
}
 
 
#define INIT_STATUS    0
#define CONFIG_STATUS  1
#define CONFIG_FINISH  2
 
 
static s8 GetSampleRateID(u32 SamplRate)
{
    switch (SamplRate)
    {
         case 96000: return  0;
         case 88200: return  1;
         case 64000: return  2;
         case 48000: return  3;
         case 44100: return  4;
         case 32000: return  5;
         case 24000: return  6;
         case 22050: return  7;
         case 16000: return  8;
         case 12000: return  9;
         case 11025: return 10;
         case 8000 : return 11;
         case 7350 : return 12;
         default:    return -1;
    }
}
 
 
//gf_m4a_get_profile
static u8 GetAACProfile(u8 AudioType, u32 SampleRate, u8 Channel)
{
    switch (AudioType)
    {
        case 2: /* AAC LC */
        {
            if (Channel <= 2)  return (SampleRate <= 24000) ? 0x28 : 0x29; /* LC@L1 or LC@L2 */
            if (Channel <= 5)  return (SampleRate <= 48000) ? 0x2A : 0x2B; /* LC@L4 or LC@L5 */
                               return (SampleRate <= 48000) ? 0x50 : 0x51; /* LC@L4 or LC@L5 */
        }
        case 5: /* HE-AAC - SBR */
        {
            if (Channel <= 2)  return (SampleRate <= 24000) ? 0x2C : 0x2D; /* HE@L2 or HE@L3 */
            if (Channel <= 5)  return (SampleRate <= 48000) ? 0x2E : 0x2F; /* HE@L4 or HE@L5 */
                               return (SampleRate <= 48000) ? 0x52 : 0x53; /* HE@L6 or HE@L7 */
        }
        case 29: /*HE-AACv2 - SBR+PS*/
        {
            if (Channel <= 2)  return (SampleRate <= 24000) ? 0x30 : 0x31; /* HE-AACv2@L2 or HE-AACv2@L3 */
            if (Channel <= 5)  return (SampleRate <= 48000) ? 0x32 : 0x33; /* HE-AACv2@L4 or HE-AACv2@L5 */
                               return (SampleRate <= 48000) ? 0x54 : 0x55; /* HE-AACv2@L6 or HE-AACv2@L7 */
        }
        default: /* default to HQ */
        {
            if (Channel <= 2)  return (SampleRate <  24000) ? 0x0E : 0x0F; /* HQ@L1 or HQ@L2 */
                               return 0x10; /* HQ@L3 */
        }
    }
}
 
static void GetAudioSpecificConfig(u8 AudioType, u8 SampleRateID, u8 Channel, u8 *pHigh, u8 *pLow)
{
    u16 Config;
 
    Config = (AudioType & 0x1f);
    Config <<= 4;
    Config |= SampleRateID & 0x0f;
    Config <<= 4;
    Config |= Channel & 0x0f;
    Config <<= 3;
 
    *pLow  = Config & 0xff;
    Config >>= 8;
    *pHigh = Config & 0xff;
}
 
/* 返回的數(shù)據(jù)包括起始的4個(gè)字節(jié)0x00000001 */
static u8* FindNalu(u8 *pStart, u32 Size, u8 *pNaluType, u32 *pNaluSize)
{
    u8 *pEnd;
    u8 *pCur;
    u8 *pOut;
    u8  NaluType;
 
    if (4 >= Size)
        return NULL;
 
    /* 找第一個(gè)0x00000001 */
    pCur = pStart;
    pEnd = pStart + Size - 4;
    while (pCur < pEnd)
    {
        if ( (0 == pCur[0]) && (0 == pCur[1]) && (0 == pCur[2]) && (1 == pCur[3]) )
            break;
        pCur++;
    }
    if (pCur >= pEnd)
        return NULL;
 
    NaluType = (pCur[4] >> 1) & 0x3f;
    *pNaluType = NaluType;
    if (1 == NaluType || 19 == NaluType) /* P幀、I幀, 假設(shè)每一包里P幀I幀都是最后一個(gè) */
    {
        *pNaluSize  = Size - (pCur - pStart);
        return pCur;
    }
 
    pOut = pCur;
 
    /* 找第二個(gè)0x00000001 */
    pCur += 5;
    while (pCur <= pEnd)
    {
        if ( (0 == pCur[0]) && (0 == pCur[1]) && (0 == pCur[2]) && (1 == pCur[3]) )
            break;
        pCur++;
    }
    if (pCur <= pEnd)
    {
        *pNaluSize  = pCur - pOut;
        return pOut;
    }
 
    *pNaluSize  = Size - (pOut - pStart);
    return pOut;
}
 
/* 返回的數(shù)據(jù)包括起始的4個(gè)字節(jié)0x00000001 */
static u8* FindNalu264(u8 *pStart, u32 Size, u8 *pNaluType, u32 *pNaluSize)
{
	u8 *pEnd;
	u8 *pCur;
	u8 *pOut;
	u8  NaluType;
 
	if (4 >= Size)
		return NULL;
 
	/* 找第一個(gè)0x00000001 */
	pCur = pStart;
	pEnd = pStart + Size - 4;
	while (pCur < pEnd)
	{
		if ((0 == pCur[0]) && (0 == pCur[1]) && (0 == pCur[2]) && (1 == pCur[3]))
			break;
		pCur++;
	}
	if (pCur >= pEnd)
		return NULL;
 
	NaluType = (pCur[4]) & 0x1f;
	*pNaluType = NaluType;
 
	if (1 == NaluType || 5 == NaluType) /* P幀、I幀, 假設(shè)每一包里P幀I幀都是最后一個(gè) */
	{
		*pNaluSize = Size - (pCur - pStart);
		return pCur;
	}
 
	pOut = pCur;
 
	/* 找第二個(gè)0x00000001 */
	pCur += 5;
	while (pCur <= pEnd)
	{
		if ((0 == pCur[0]) && (0 == pCur[1]) && (0 == pCur[2]) && (1 == pCur[3]))
			break;
		pCur++;
	}
	if (pCur <= pEnd)
	{
		*pNaluSize = pCur - pOut;
		return pOut;
	}
 
	*pNaluSize = Size - (pOut - pStart);
	return pOut;
}
 
 
// aac數(shù)據(jù)時(shí)記得除掉adts頭
static int AdtsDemux(unsigned char * data, unsigned int size, unsigned char** raw, int* raw_size)
{
	int ret = 1;
	if (size < 7) {
		ttf_human_trace("adts: demux size too small");
		return 0;
	}
	unsigned char* p = data;
	unsigned char* pend = data + size;
	//unsigned char* startp = 0;
 
	while (p < pend) {
 
		// decode the ADTS.
		// @see aac-iso-13818-7.pdf, page 26
		//      6.2 Audio Data Transport Stream, ADTS
		// @see https://github.com/ossrs/srs/issues/212#issuecomment-64145885
		// byte_alignment()
 
		// adts_fixed_header:
		//      12bits syncword,
		//      16bits left.
		// adts_variable_header:
		//      28bits
		//      12+16+28=56bits
		// adts_error_check:
		//      16bits if protection_absent
		//      56+16=72bits
		// if protection_absent:
		//      require(7bytes)=56bits
		// else
		//      require(9bytes)=72bits
 
		//startp = p;
 
		// for aac, the frame must be ADTS format.
		/*if (p[0] != 0xff || (p[1] & 0xf0) != 0xf0) {
			ttf_human_trace("adts: not this format.");
			return 0;
		}*/
 
		// syncword 12 bslbf
		p++;
		// 4bits left.
		// adts_fixed_header(), 1.A.2.2.1 Fixed Header of ADTS
		// ID 1 bslbf
		// layer 2 uimsbf
		// protection_absent 1 bslbf
		int8_t pav = (*p++ & 0x0f);
		//int8_t id = (pav >> 3) & 0x01;
		/*int8_t layer = (pav >> 1) & 0x03;*/
		int8_t protection_absent = pav & 0x01;
 
		/**
		* ID: MPEG identifier, set to '1' if the audio data in the ADTS stream are MPEG-2 AAC (See ISO/IEC 13818-7)
		* and set to '0' if the audio data are MPEG-4. See also ISO/IEC 11172-3, subclause 2.4.2.3.
		*/
		//if (id != 0x01) {
		//	//ttf_human_trace("adts: id must be 1(aac), actual 0(mp4a).");
 
		//	// well, some system always use 0, but actually is aac format.
		//	// for example, houjian vod ts always set the aac id to 0, actually 1.
		//	// we just ignore it, and alwyas use 1(aac) to demux.
		//	id = 0x01;
		//}
		//else {
		//	//ttf_human_trace("adts: id must be 1(aac), actual 1(mp4a).");
		//}
 
		//int16_t sfiv = (*p << 8) | (*(p + 1));
		p += 2;
		// profile 2 uimsbf
		// sampling_frequency_index 4 uimsbf
		// private_bit 1 bslbf
		// channel_configuration 3 uimsbf
		// original/copy 1 bslbf
		// home 1 bslbf
		//int8_t profile = (sfiv >> 14) & 0x03;
		//int8_t sampling_frequency_index = (sfiv >> 10) & 0x0f;
		/*int8_t private_bit = (sfiv >> 9) & 0x01;*/
		//int8_t channel_configuration = (sfiv >> 6) & 0x07;
		/*int8_t original = (sfiv >> 5) & 0x01;*/
		/*int8_t home = (sfiv >> 4) & 0x01;*/
		//int8_t Emphasis; @remark, Emphasis is removed, @see https://github.com/ossrs/srs/issues/212#issuecomment-64154736
		// 4bits left.
		// adts_variable_header(), 1.A.2.2.2 Variable Header of ADTS
		// copyright_identification_bit 1 bslbf
		// copyright_identification_start 1 bslbf
		/*int8_t fh_copyright_identification_bit = (fh1 >> 3) & 0x01;*/
		/*int8_t fh_copyright_identification_start = (fh1 >> 2) & 0x01;*/
		// frame_length 13 bslbf: Length of the frame including headers and error_check in bytes.
		// use the left 2bits as the 13 and 12 bit,
		// the frame_length is 13bits, so we move 13-2=11.
		//int16_t frame_length = (sfiv << 11) & 0x1800;
 
		//int32_t abfv = ((*p) << 16)
		//	| ((*(p + 1)) << 8)
		//	| (*(p + 2));
		p += 3;
		// frame_length 13 bslbf: consume the first 13-2=11bits
		// the fh2 is 24bits, so we move right 24-11=13.
		//frame_length |= (abfv >> 13) & 0x07ff;
		// adts_buffer_fullness 11 bslbf
		/*int16_t fh_adts_buffer_fullness = (abfv >> 2) & 0x7ff;*/
		// number_of_raw_data_blocks_in_frame 2 uimsbf
		/*int16_t number_of_raw_data_blocks_in_frame = abfv & 0x03;*/
		// adts_error_check(), 1.A.2.2.3 Error detection
		if (!protection_absent) {
			if (size < 9) {
				ttf_human_trace("adts: protection_absent disappare.");
				return 0;
			}
			// crc_check 16 Rpchof
			/*int16_t crc_check = */p += 2;
		}
 
		// TODO: check the sampling_frequency_index
		// TODO: check the channel_configuration
 
		// raw_data_blocks
		/*int adts_header_size = p - startp;
		int raw_data_size = frame_length - adts_header_size;
		if (raw_data_size > pend - p) {
			ttf_human_trace("adts: raw data size too little.");
			return 0;
		}*/
 
		//adts_codec_.protection_absent = protection_absent;
		//adts_codec_.aac_object = srs_codec_aac_ts2rtmp((SrsAacProfile)profile);
		//adts_codec_.sampling_frequency_index = sampling_frequency_index;
		//adts_codec_.channel_configuration = channel_configuration;
		//adts_codec_.frame_length = frame_length;
 
		 @see srs_audio_write_raw_frame().
		 TODO: FIXME: maybe need to resample audio.
		//adts_codec_.sound_format = 10; // AAC
		//if (sampling_frequency_index <= 0x0c && sampling_frequency_index > 0x0a) {
		//	adts_codec_.sound_rate = SrsCodecAudioSampleRate5512;
		//}
		//else if (sampling_frequency_index <= 0x0a && sampling_frequency_index > 0x07) {
		//	adts_codec_.sound_rate = SrsCodecAudioSampleRate11025;
		//}
		//else if (sampling_frequency_index <= 0x07 && sampling_frequency_index > 0x04) {
		//	adts_codec_.sound_rate = SrsCodecAudioSampleRate22050;
		//}
		//else if (sampling_frequency_index <= 0x04) {
		//	adts_codec_.sound_rate = SrsCodecAudioSampleRate44100;
		//}
		//else {
		//	adts_codec_.sound_rate = SrsCodecAudioSampleRate44100;
		//	//srs_warn("adts invalid sample rate for flv, rate=%#x", sampling_frequency_index);
		//}
		//adts_codec_.sound_type = srs_max(0, srs_min(1, channel_configuration - 1));
		 TODO: FIXME: finger it out the sound size by adts.
		//adts_codec_.sound_size = 1; // 0(8bits) or 1(16bits).
 
									// frame data.
		*raw = p;
		*raw_size = pend - p;
 
		break;
	}
 
	return ret;
}
 
class MP4Writer
{
public:
    MP4Writer();
    ~MP4Writer();
 
    s32  CreatFile(char *strFileName);
    s32  Init265(u32 TimeScale);
    s32  Write265Sample(u8 *pData, u32 Size, u64 TimeStamp);
	s32  Init264(u32 TimeScale);
	s32  Write264Sample(u8 *pData, u32 Size, u64 TimeStamp);
    s32  InitAAC(u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale);
    s32  WriteAACSample(u8 *pData, u32 Size, u64 TimeStamp);
    void CloseFile();
 
private:
    GF_ISOFile *m_ptFile;
 
    u32 m_265TrackIndex;
    u32 m_265StreamIndex;
    u8  m_Video265Statue;
	u32 m_264TrackIndex;
	u32 m_264StreamIndex;
	u8  m_Video264Statue;
    s64 m_VideoTimeStampStart;
 
    GF_HEVCConfig     *m_ptHEVCConfig;
    GF_HEVCParamArray*  m_tHEVCNaluParam_VPS;
    GF_HEVCParamArray*  m_tHEVCNaluParam_SPS;
    GF_HEVCParamArray*  m_tHEVCNaluParam_PPS;
    GF_AVCConfigSlot*   m_tAVCConfig_VPS;
    GF_AVCConfigSlot*   m_tAVCConfig_SPS;
    GF_AVCConfigSlot*   m_tAVCConfig_PPS;
 
	GF_AVCConfigSlot*   m_tAVCConfig_SPS264;
	GF_AVCConfigSlot*   m_tAVCConfig_PPS264;
 
	GF_AVCConfig      *m_ptAVCConfig;
 
	HEVCState    *m_ptHEVCState;
	AVCState     *m_ptAVCState;
 
    u32 m_AACTrackIndex;
    u32 m_AACStreamIndex;
    u8  m_AudioAACStatue;
    s64 m_AudioTimeStampStart;
	bool findfirsidr_;
 
 
    void FreeAllMem();
};
 
 
MP4Writer::MP4Writer()
{
    m_ptFile = NULL;
    m_ptHEVCConfig = NULL;
	m_ptAVCConfig = NULL;
 
    m_Video265Statue = INIT_STATUS;
    m_AudioAACStatue = INIT_STATUS;
	m_Video264Statue = INIT_STATUS;
 
	m_tHEVCNaluParam_VPS = NULL;
	m_tHEVCNaluParam_SPS = NULL;
	m_tHEVCNaluParam_PPS = NULL;
	m_tAVCConfig_VPS = NULL;
	m_tAVCConfig_SPS = NULL;
	m_tAVCConfig_PPS = NULL;
 
	m_tAVCConfig_SPS264 = NULL;
	m_tAVCConfig_PPS264 = NULL;
 
	m_ptHEVCState = NULL;
	m_ptAVCState = NULL;
 
	findfirsidr_ = false;
}
 
MP4Writer::~MP4Writer()
{
    CloseFile();
}
 
s32 MP4Writer::CreatFile(char *strFileName)
{
    if (NULL != m_ptFile)
    {
        return -1;
    }
 
    m_ptFile = gf_isom_open(strFileName, GF_ISOM_OPEN_WRITE, NULL);
    if (NULL == m_ptFile)
    {
        return -1;
    }
 
    gf_isom_set_brand_info(m_ptFile, GF_ISOM_BRAND_MP42, 0);
 
    return 0;
}
 
 
void MP4Writer::CloseFile()
{
    if (m_ptFile)
    {
        gf_isom_close(m_ptFile);
        m_ptFile = NULL;
 
        FreeAllMem();
    }
}
 
void MP4Writer::FreeAllMem()
{
 
    if (m_ptHEVCConfig)
    {
		gf_odf_hevc_cfg_del(m_ptHEVCConfig);
        //gf_list_del(m_ptHEVCConfig->param_array);
        //free(m_ptHEVCConfig);
        m_ptHEVCConfig = NULL;
    }
 
	if (m_ptAVCConfig) {
		gf_odf_avc_cfg_del(m_ptAVCConfig);
		//gf_list_del(m_ptAVCConfig->param_array);
		//free(m_ptAVCConfig);
		m_ptAVCConfig = NULL;
	}
 
	if (m_ptHEVCState) {
		free(m_ptHEVCState);
		m_ptHEVCState = NULL;
	}
		
	if (m_ptAVCState) {
		free(m_ptAVCState);
		m_ptAVCState = NULL;
	}
 
	m_tHEVCNaluParam_VPS = NULL;
	m_tHEVCNaluParam_SPS = NULL;
	m_tHEVCNaluParam_PPS = NULL;
	m_tAVCConfig_VPS = NULL;
	m_tAVCConfig_SPS = NULL;
	m_tAVCConfig_PPS = NULL;
 
	m_tAVCConfig_SPS264 = NULL;
	m_tAVCConfig_PPS264 = NULL;
 
	m_Video265Statue = INIT_STATUS;
	m_AudioAACStatue = INIT_STATUS;
	m_Video264Statue = INIT_STATUS;
 
	findfirsidr_ = false;
	
}
 
s32 MP4Writer::Init265(u32 TimeScale)
{
    if (NULL == m_ptFile || INIT_STATUS != m_Video265Statue)
        return -1;
 
 
    m_VideoTimeStampStart = -1;
 
    /* 創(chuàng)建Track */
    m_265TrackIndex = gf_isom_new_track(m_ptFile, 0, GF_ISOM_MEDIA_VISUAL, TimeScale);
    if (0 == m_265TrackIndex)
        return -1;
    if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_265TrackIndex, 1))
        return -1;
 
 
    /* 創(chuàng)建流 */
    m_ptHEVCConfig = gf_odf_hevc_cfg_new();
    if (NULL == m_ptHEVCConfig)
        return -1;
    m_ptHEVCConfig->nal_unit_size = 4;
    m_ptHEVCConfig->configurationVersion = 1;
 
    if (GF_OK != gf_isom_hevc_config_new(m_ptFile, m_265TrackIndex, m_ptHEVCConfig, NULL, NULL, &m_265StreamIndex))
        return -1;
 
 
 
    /* 初始化流的配置結(jié)構(gòu) */
	GF_SAFEALLOC(m_tHEVCNaluParam_VPS, GF_HEVCParamArray);
	GF_SAFEALLOC(m_tHEVCNaluParam_SPS, GF_HEVCParamArray);
	GF_SAFEALLOC(m_tHEVCNaluParam_PPS, GF_HEVCParamArray);
	GF_SAFEALLOC(m_tAVCConfig_VPS, GF_AVCConfigSlot);
	GF_SAFEALLOC(m_tAVCConfig_SPS, GF_AVCConfigSlot);
	GF_SAFEALLOC(m_tAVCConfig_PPS, GF_AVCConfigSlot);
 
    if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_VPS))
        return -1;
    if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_SPS))
        return -1;
    if (GF_OK != gf_list_add(m_ptHEVCConfig->param_array, m_tHEVCNaluParam_PPS))
        return -1;
 
    m_tHEVCNaluParam_VPS->nalus = gf_list_new();
    if (NULL == m_tHEVCNaluParam_VPS->nalus)
        return -1;
    m_tHEVCNaluParam_SPS->nalus = gf_list_new();
    if (NULL == m_tHEVCNaluParam_SPS->nalus)
        return -1;
    m_tHEVCNaluParam_PPS->nalus = gf_list_new();
    if (NULL == m_tHEVCNaluParam_PPS->nalus)
        return -1;
    m_tHEVCNaluParam_VPS->type  = GF_HEVC_NALU_VID_PARAM;
    m_tHEVCNaluParam_SPS->type  = GF_HEVC_NALU_SEQ_PARAM;
    m_tHEVCNaluParam_PPS->type  = GF_HEVC_NALU_PIC_PARAM;
    m_tHEVCNaluParam_VPS->array_completeness = 1;
    m_tHEVCNaluParam_SPS->array_completeness = 1;
    m_tHEVCNaluParam_PPS->array_completeness = 1;
 
    if (GF_OK != gf_list_add(m_tHEVCNaluParam_VPS->nalus, m_tAVCConfig_VPS))
        return -1;
    if (GF_OK != gf_list_add(m_tHEVCNaluParam_SPS->nalus, m_tAVCConfig_SPS))
        return -1;
    if (GF_OK != gf_list_add(m_tHEVCNaluParam_PPS->nalus, m_tAVCConfig_PPS))
        return -1;
 
 
	m_ptHEVCState = (HEVCState *)malloc(sizeof(HEVCState));//gf_malloc
	if (NULL == m_ptHEVCState)
			return -1;
	memset(m_ptHEVCState, 0, sizeof(HEVCState));
 
 
    m_Video265Statue = CONFIG_STATUS;
 
    return 0;
}
 
 
s32 MP4Writer::Write265Sample(u8 *pData, u32 Size, u64 TimeStamp)
{
    u8  *pStart = pData;
    u8   NaluType;
    u32  NaluSize = 0;
    s32  ID;
 
    GF_ISOSample  tISOSample;
 
    /* 265還未初始化 */
    if (INIT_STATUS == m_Video265Statue)
        return -1;
 
    while (1)
    {
        pData = FindNalu(pData + NaluSize, Size - (u32)(pData - pStart) - NaluSize, &NaluType, &NaluSize);
        if (NULL == pData)
            break;
 
        /* 配置完成后只處理IP幀 */
        if (CONFIG_FINISH == m_Video265Statue)
        {
            if (1 != NaluType && 19 != NaluType) /* P幀 I幀 */
                continue;
 
            if (-1 == m_VideoTimeStampStart)
                m_VideoTimeStampStart = TimeStamp;
 
            *((u32 *)pData) = htonl(NaluSize - 4); /* 這里的長(zhǎng)度不能包括前四個(gè)字節(jié)的頭! */
            tISOSample.data = (char *)pData;
            tISOSample.dataLength = NaluSize;
            tISOSample.IsRAP = (19 == NaluType)? RAP: RAP_NO;
            tISOSample.DTS = TimeStamp - m_VideoTimeStampStart;
            tISOSample.CTS_Offset = 0;
            tISOSample.nb_pack = 0;
            if (GF_OK != gf_isom_add_sample(m_ptFile, m_265TrackIndex, m_265StreamIndex, &tISOSample))
            {
                *((u32 *)pData) = htonl(1); /* 恢復(fù)0x00000001的頭 */
                return -1;
            }
 
            *((u32 *)pData) = htonl(1); /* 恢復(fù)0x00000001的頭 */
        }
        /* 配置未完成時(shí)只處理vps sps pps頭 */
        else if (CONFIG_STATUS == m_Video265Statue)
        {
            pData += 4;
            NaluSize -= 4;
 
            if (32 == NaluType && NULL == m_tAVCConfig_VPS->data) /* VPS */
            {
                ID = gf_media_hevc_read_vps((char *)pData , NaluSize, m_ptHEVCState);
                m_ptHEVCConfig->avgFrameRate      = m_ptHEVCState->vps[ID].rates[0].avg_pic_rate;
                m_ptHEVCConfig->temporalIdNested  = m_ptHEVCState->vps[ID].temporal_id_nesting;
                m_ptHEVCConfig->constantFrameRate = m_ptHEVCState->vps[ID].rates[0].constand_pic_rate_idc;
                m_ptHEVCConfig->numTemporalLayers = m_ptHEVCState->vps[ID].max_sub_layers;
                m_tAVCConfig_VPS->id   = ID;
                m_tAVCConfig_VPS->size = (u16)NaluSize;
                m_tAVCConfig_VPS->data = (char *)malloc(NaluSize);
                if (NULL == m_tAVCConfig_VPS->data)
                    continue;
                memcpy(m_tAVCConfig_VPS->data, pData, NaluSize);
            }
            else if (33 == NaluType && NULL == m_tAVCConfig_SPS->data) /* SPS */
            {
                ID = gf_media_hevc_read_sps((char *)pData, NaluSize, m_ptHEVCState);
                m_ptHEVCConfig->tier_flag     = m_ptHEVCState->sps[ID].ptl.tier_flag;
                m_ptHEVCConfig->profile_idc   = m_ptHEVCState->sps[ID].ptl.profile_idc;
                m_ptHEVCConfig->profile_space = m_ptHEVCState->sps[ID].ptl.profile_space;
                m_tAVCConfig_SPS->id   = ID;
                m_tAVCConfig_SPS->size = (u16)NaluSize;
                m_tAVCConfig_SPS->data = (char *)malloc(NaluSize);
                if (NULL == m_tAVCConfig_SPS->data)
                    continue;
                memcpy(m_tAVCConfig_SPS->data, pData, NaluSize);
 
                gf_isom_set_visual_info(m_ptFile, m_265TrackIndex, m_265StreamIndex, m_ptHEVCState->sps[ID].width, m_ptHEVCState->sps[ID].height);
            }
            else if (34 == NaluType && NULL == m_tAVCConfig_PPS->data) /* PPS */
            {
            	  ID = gf_media_hevc_read_pps((char *)pData, NaluSize, m_ptHEVCState);
                m_tAVCConfig_PPS->id   = ID;
                m_tAVCConfig_PPS->size = (u16)NaluSize;
                m_tAVCConfig_PPS->data = (char *)malloc(NaluSize);
                if (NULL == m_tAVCConfig_PPS->data)
                    continue;
                memcpy(m_tAVCConfig_PPS->data, pData, NaluSize);
            }
            else
            {
                continue;
            }
 
            if (m_tAVCConfig_VPS->data && m_tAVCConfig_SPS->data && m_tAVCConfig_PPS->data)
            {
                gf_isom_hevc_config_update(m_ptFile, m_265TrackIndex, m_265StreamIndex, m_ptHEVCConfig);
                m_Video265Statue = CONFIG_FINISH;
				if (m_ptHEVCState) {
					free(m_ptHEVCState);
					m_ptHEVCState = NULL;
				}
            }
        }
    }
 
    return 0;
}
 
s32 MP4Writer::Init264(u32 TimeScale)
{
	if (NULL == m_ptFile || INIT_STATUS != m_Video265Statue)
		return -1;
 
 
	m_VideoTimeStampStart = -1;
 
	/* 創(chuàng)建Track */
	m_264TrackIndex = gf_isom_new_track(m_ptFile, 0, GF_ISOM_MEDIA_VISUAL, TimeScale);
	if (0 == m_264TrackIndex)
		return -1;
	if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_264TrackIndex, 1))
		return -1;
 
 
	/* 創(chuàng)建流 */
	m_ptAVCConfig = gf_odf_avc_cfg_new();
	if (NULL == m_ptAVCConfig)
		return -1;
	//m_ptAVCConfig->nal_unit_size = 4;
	m_ptAVCConfig->configurationVersion = 1;
 
	if (GF_OK != gf_isom_avc_config_new(m_ptFile, m_264TrackIndex, m_ptAVCConfig, NULL, NULL, &m_264StreamIndex))
		return -1;
 
	/* 初始化流的配置結(jié)構(gòu) */
	GF_SAFEALLOC(m_tAVCConfig_SPS264, GF_AVCConfigSlot);
	GF_SAFEALLOC(m_tAVCConfig_PPS264, GF_AVCConfigSlot);
 
	gf_list_add(m_ptAVCConfig->sequenceParameterSets, m_tAVCConfig_SPS264);
	gf_list_add(m_ptAVCConfig->pictureParameterSets, m_tAVCConfig_PPS264);
 
	m_ptAVCState = (AVCState *)malloc(sizeof(AVCState));//gf_malloc
	if (NULL == m_ptAVCState)
		return -1;
	memset(m_ptAVCState, 0, sizeof(AVCState));
 
 
	m_Video264Statue = CONFIG_STATUS;
 
	return 0;
}
 
 
s32 MP4Writer::Write264Sample(u8 *pData, u32 Size, u64 TimeStamp)
{
	u8  *pStart = pData;
	u8   NaluType;
	u32  NaluSize = 0;
	s32  ID;
 
	GF_ISOSample  tISOSample;
 
	/* 265還未初始化 */
	if (INIT_STATUS == m_Video264Statue)
		return -1;
 
	while (1)
	{
		pData = FindNalu264(pData + NaluSize, Size - (u32)(pData - pStart) - NaluSize, &NaluType, &NaluSize);
		if (NULL == pData)
			break;
 
		/* 配置完成后只處理IP幀 */
		if (CONFIG_FINISH == m_Video264Statue)
		{
			if (!findfirsidr_) {
				if (5 != NaluType)
					continue;
				else
					findfirsidr_ = true;
			}
				
			if (1 != NaluType && 5 != NaluType) /* P幀 I幀 */
				continue;
 
			if (-1 == m_VideoTimeStampStart)
				m_VideoTimeStampStart = TimeStamp;
 
			*((u32 *)pData) = htonl(NaluSize - 4); /* 這里的長(zhǎng)度不能包括前四個(gè)字節(jié)的頭! */
			tISOSample.data = (char *)pData;
			tISOSample.dataLength = NaluSize;
			tISOSample.IsRAP = (5 == NaluType) ? RAP : RAP_NO;
			tISOSample.DTS = TimeStamp - m_VideoTimeStampStart;
			tISOSample.CTS_Offset = 0;
			tISOSample.nb_pack = 0;
			int ret = gf_isom_add_sample(m_ptFile, m_264TrackIndex, m_264StreamIndex, &tISOSample);
			if (GF_OK != ret)
			{
 
				//*((u32 *)pData) = htonl(1); /* 恢復(fù)0x00000001的頭 */
				return -1;
			}
 
			//*((u32 *)pData) = htonl(1); /* 恢復(fù)0x00000001的頭 */
		}
		/* 配置未完成時(shí)只處理vps sps pps頭 */
		else if (CONFIG_STATUS == m_Video264Statue)
		{
			pData += 4;
			NaluSize -= 4;
 
			if (7 == NaluType && NULL == m_tAVCConfig_SPS264->data) /* SPS */
			{
				ID = gf_media_avc_read_sps((char *)pData, NaluSize, m_ptAVCState,0,NULL);
				m_ptAVCConfig->AVCProfileIndication = m_ptAVCState->sps[ID].profile_idc;
				m_ptAVCConfig->profile_compatibility = m_ptAVCState->sps[ID].prof_compat;
				m_ptAVCConfig->AVCLevelIndication = m_ptAVCState->sps[ID].level_idc;
				m_tAVCConfig_SPS264->id = ID;
				m_tAVCConfig_SPS264->size = (u16)NaluSize;
				m_tAVCConfig_SPS264->data = (char *)malloc(NaluSize);
				if (NULL == m_tAVCConfig_SPS264->data)
					continue;
				memcpy(m_tAVCConfig_SPS264->data, pData, NaluSize);
 
				gf_isom_set_visual_info(m_ptFile, m_264TrackIndex, m_264StreamIndex, m_ptAVCState->sps[ID].width, m_ptAVCState->sps[ID].height);
			}
			else if (8 == NaluType && NULL == m_tAVCConfig_PPS264->data) /* PPS */
			{
				m_tAVCConfig_PPS264->id = ID;
				m_tAVCConfig_PPS264->size = (u16)NaluSize;
				m_tAVCConfig_PPS264->data = (char *)malloc(NaluSize);
				if (NULL == m_tAVCConfig_PPS264->data)
					continue;
				memcpy(m_tAVCConfig_PPS264->data, pData, NaluSize);
			}
			else
			{
				continue;
			}
 
			if (m_tAVCConfig_SPS264->data && m_tAVCConfig_PPS264->data)
			{
				gf_isom_avc_config_update(m_ptFile, m_264TrackIndex, m_264StreamIndex, m_ptAVCConfig);
				m_Video264Statue = CONFIG_FINISH;
				if (m_ptAVCState) {
					free(m_ptAVCState);
					m_ptAVCState = NULL;
				}
			}
		}
	}
 
	return 0;
}
 
 
s32 MP4Writer::InitAAC(u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale)
{
    GF_ESD *ptStreamDesc;
    s8      SampleRateID;
    u16     AudioConfig = 0;
    u8      AACProfile;
    s32     res = 0;
 
 
    if (NULL == m_ptFile || INIT_STATUS != m_AudioAACStatue)
        return -1;
 
 
    m_AudioTimeStampStart = -1;
 
    /* 創(chuàng)建Track */
    m_AACTrackIndex = gf_isom_new_track(m_ptFile, 0, GF_ISOM_MEDIA_AUDIO, TimeScale);
    if (0 == m_AACTrackIndex)
        return -1;
 
    if (GF_OK != gf_isom_set_track_enabled(m_ptFile, m_AACTrackIndex, 1))
        return -1;
 
 
    /* 創(chuàng)建并配置流 */
    SampleRateID = GetSampleRateID(SampleRate);
    if (0 > SampleRateID)
        return -1;
    GetAudioSpecificConfig(AudioType, (u8)SampleRateID, Channel, (u8*)(&AudioConfig), ((u8*)(&AudioConfig))+1);
 
    ptStreamDesc = gf_odf_desc_esd_new(SLPredef_MP4);
    ptStreamDesc->slConfig->timestampResolution = TimeScale;
    ptStreamDesc->decoderConfig->streamType = GF_STREAM_AUDIO;
    //ptStreamDesc->decoderConfig->bufferSizeDB = 20; //這參數(shù)干什么的
    ptStreamDesc->decoderConfig->objectTypeIndication = 0x40;//ptStreamDesc->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;
    ptStreamDesc->decoderConfig->decoderSpecificInfo->dataLength = 2;
    ptStreamDesc->decoderConfig->decoderSpecificInfo->data = (char *)&AudioConfig;
    ptStreamDesc->ESID = gf_isom_get_track_id(m_ptFile, m_AACTrackIndex);
    if (GF_OK != gf_isom_new_mpeg4_description(m_ptFile, m_AACTrackIndex, ptStreamDesc, NULL, NULL, &m_AACStreamIndex))
    {
        res = -1;
        goto ERR;
    }
 
    if (gf_isom_set_audio_info(m_ptFile, m_AACTrackIndex, m_AACStreamIndex, SampleRate, Channel, 16, GF_IMPORT_AUDIO_SAMPLE_ENTRY_NOT_SET))
    {
        res = -1;
        goto ERR;
    }
 
    AACProfile = GetAACProfile(AudioType, SampleRate, Channel);
    gf_isom_set_pl_indication(m_ptFile, GF_ISOM_PL_AUDIO, AACProfile);
 
    m_AudioAACStatue = CONFIG_FINISH;
 
 
    ERR:
    ptStreamDesc->decoderConfig->decoderSpecificInfo->data = NULL;
    gf_odf_desc_del((GF_Descriptor *)ptStreamDesc);
 
    return res;
}
 
 
s32 MP4Writer::WriteAACSample(u8 *pData, u32 Size, u64 TimeStamp)
{
    GF_ISOSample tISOSample;
 
    if (CONFIG_FINISH != m_AudioAACStatue)
        return 0;
 
	if (!findfirsidr_) {
		return 0;
	}
 
    if (-1 == m_AudioTimeStampStart)
        m_AudioTimeStampStart = TimeStamp;
 
    tISOSample.IsRAP = RAP;
    tISOSample.dataLength = Size;
    tISOSample.data = (char *)pData;
    tISOSample.DTS = TimeStamp - m_AudioTimeStampStart;
    tISOSample.CTS_Offset = 0;
	tISOSample.nb_pack = 0;
    if (GF_OK != gf_isom_add_sample(m_ptFile, m_AACTrackIndex, m_AACStreamIndex, &tISOSample))
        return -1;
 
    return 0;
}
 
 
 
 
extern "C" {
 
 
void* MP4_Init()
{
    return (void *)(new MP4Writer());
}
 
s32 MP4_CreatFile(void *pCMP4Writer, char *strFileName)
{
    if (NULL == pCMP4Writer)
        return -1;
 
    return ((MP4Writer *)pCMP4Writer)->CreatFile(strFileName);
}
 
s32 MP4_InitVideo265(void *pCMP4Writer, u32 TimeScale)
{
    if (NULL == pCMP4Writer)
        return -1;
 
    return ((MP4Writer *)pCMP4Writer)->Init265(TimeScale);
}
 
s32 MP4_Write265Sample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp)
{
    if (NULL == pCMP4Writer)
        return -1;
 
    return ((MP4Writer *)pCMP4Writer)->Write265Sample(pData, Size, TimeStamp);
}
 
s32 MP4_InitVideo264(void * pCMP4Writer, u32 TimeScale)
{
	if (NULL == pCMP4Writer)
		return -1;
 
	return ((MP4Writer *)pCMP4Writer)->Init264(TimeScale);
}
 
s32 MP4_Write264Sample(void * pCMP4Writer, u8 * pData, u32 Size, u64 TimeStamp)
{
	if (NULL == pCMP4Writer)
		return -1;
 
	return ((MP4Writer *)pCMP4Writer)->Write264Sample(pData, Size, TimeStamp);
}
 
s32 MP4_InitAudioAAC(void *pCMP4Writer, u8 AudioType, u32 SampleRate, u8 Channel, u32 TimeScale)
{
    if (NULL == pCMP4Writer)
        return -1;
 
    return ((MP4Writer *)pCMP4Writer)->InitAAC(AudioType, SampleRate, Channel, TimeScale);
}
 
s32 MP4_WriteAACSample(void *pCMP4Writer, u8 *pData, u32 Size, u64 TimeStamp)
{
    if (NULL == pCMP4Writer)
        return -1;
 
    return ((MP4Writer *)pCMP4Writer)->WriteAACSample(pData, Size, TimeStamp);
}
 
void MP4_CloseFile(void *pCMP4Writer)
{
    if (NULL == pCMP4Writer)
        return;
 
    ((MP4Writer *)pCMP4Writer)->CloseFile();
}
 
void MP4_Exit(void *pCMP4Writer)
{
    if (NULL == pCMP4Writer)
        return;
 
    delete pCMP4Writer;
}
 
 
}

注意:

1)MP4_InitAudioAAC那個(gè)audiotype指的是aac的profile,lc就是2。

    GF_M4A_AAC_MAIN = 1,
    GF_M4A_AAC_LC = 2,
    GF_M4A_AAC_SSR = 3,
    GF_M4A_AAC_LTP = 4,
    GF_M4A_AAC_SBR = 5,
    GF_M4A_AAC_SCALABLE = 6,
    GF_M4A_TWINVQ = 7,
    GF_M4A_CELP = 8,
    GF_M4A_HVXC = 9,
    GF_M4A_TTSI = 12,
    GF_M4A_MAIN_SYNTHETIC = 13,
    GF_M4A_WAVETABLE_SYNTHESIS = 14,
    GF_M4A_GENERAL_MIDI = 15,
    GF_M4A_ALGO_SYNTH_AUDIO_FX = 16,
    GF_M4A_ER_AAC_LC = 17,
    GF_M4A_ER_AAC_LTP = 19,
    GF_M4A_ER_AAC_SCALABLE = 20,
    GF_M4A_ER_TWINVQ = 21,
    GF_M4A_ER_BSAC = 22,
    GF_M4A_ER_AAC_LD = 23,
    GF_M4A_ER_CELP = 24,
    GF_M4A_ER_HVXC = 25,
    GF_M4A_ER_HILN = 26,
    GF_M4A_ER_PARAMETRIC = 27,
    GF_M4A_SSC = 28,
    GF_M4A_AAC_PS = 29,
    GF_M4A_LAYER1 = 32,
    GF_M4A_LAYER2 = 33,
    GF_M4A_LAYER3 = 34,
    GF_M4A_DST = 35,
    GF_M4A_ALS = 36

2)填aac數(shù)據(jù)時(shí)記得除掉adts頭,使用上面的AdtsDemux函數(shù)即可。

二、寫(xiě)h264流數(shù)據(jù)為mp4文件步驟

void * handleMp4 = NULL;
handleMp4 = MP4_Init();
Mp4_CreateFile(handleMp4,"d:\\test.mp4");
MP4_InitVideo264(handleMp4,1000);
//寫(xiě)h264流數(shù)據(jù),包含00 00 00 01標(biāo)記頭的數(shù)據(jù)
MP4_Write264Sample(handleMp4,h264data,datasize,timestamp);//h264data表示264數(shù)據(jù),datasize表示數(shù)據(jù)大小,timestamp表示時(shí)間戳,需要轉(zhuǎn)換成基準(zhǔn)為1000時(shí)間戳(1000\90000兩種)
...
MP4_CloseFile(handleMp4);
MP4_Exit(handleMp4);

三、寫(xiě)h265流數(shù)據(jù)為mp4文件步驟

void * handleMp4 = NULL;
handleMp4 = MP4_Init();
Mp4_CreateFile(handleMp4,"d:\\test.mp4");
MP4_InitVideo265(handleMp4,1000);
//寫(xiě)h265流數(shù)據(jù),包含00 00 00 01標(biāo)記頭的數(shù)據(jù)
MP4_Write265Sample(handleMp4,h264data,datasize,timestamp);//h264data表示264數(shù)據(jù),datasize表示數(shù)據(jù)大小,timestamp表示時(shí)間戳,需要轉(zhuǎn)換成基準(zhǔn)為1000時(shí)間戳
...
MP4_CloseFile(handleMp4);
MP4_Exit(handleMp4);

四、利用命令行生成mp4文件

GPAC除了 GPAC 核心,完整的軟件包還包括一個(gè) GPAC 插件:MPEG-4 BIF(場(chǎng)景解碼器)、MPEG-4 ODF(對(duì)象描述符解碼器)、MPEG-4 LASeR(場(chǎng)景解碼器)、MPEG-4 SAF 解復(fù)用器、文本 MPEG- 4 加載器(支持未壓縮的 MPEG-4 BT 和 XMT、VRML 和 X3D 文本格式)、圖像包(支持 PNG、JPEG、BMP、JPEG2000)等。

 1)將h265流轉(zhuǎn)換成MP4,執(zhí)行下面命令行。

./MP4Box -v -add Catus_1920x1080_50_qp32.bin:FMT=HEVC -fps 50 -new output.mp4

./MP4Box -add name_of_annexB_bitstream.(bit,bin,265) -fps 50 -new output.mp4

  播放h265視頻文件信息,執(zhí)行下面命令。

./MP4Client output.mp4

2)將h265流轉(zhuǎn)換成ts,執(zhí)行下面命令行。

./mp42ts -prog=hevc.mp4 -dst-file=test.ts

播放h265視頻文件流信息,執(zhí)行下面命令。

./MP4Client test.ts

備注:

1、GPAC模塊下載鏈接

GitHub - gpac/gpac: Modular Multimedia framework for packaging, streaming and playing your favorite content, see http://netflix.gpac.ioDownloads | GPAC

2、編譯指導(dǎo)

Build Introduction · gpac/gpac Wiki · GitHub

Windows:GPAC Build Guide for Windows · gpac/gpac Wiki · GitHub

Linux:GPAC Build Guide for Linux · gpac/gpac Wiki · GitHub

到此這篇關(guān)于C++利用GPAC實(shí)現(xiàn)生成MP4文件的示例代碼的文章就介紹到這了,更多相關(guān)C++ GPAC生成MP4文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++17中的std::optional的具體使用

    C++17中的std::optional的具體使用

    這篇文章主要介紹了C++17中的std::optional的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C++ 流插入和流提取運(yùn)算符的重載的實(shí)現(xiàn)

    C++ 流插入和流提取運(yùn)算符的重載的實(shí)現(xiàn)

    這篇文章主要介紹了C++ 流插入和流提取運(yùn)算符的重載的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • C++ 字符串的反轉(zhuǎn)五種方法實(shí)例

    C++ 字符串的反轉(zhuǎn)五種方法實(shí)例

    通過(guò)不同的方法,實(shí)現(xiàn)對(duì)所輸入字符串的反轉(zhuǎn),有需要的朋友可以參考一下
    2013-09-09
  • C語(yǔ)言中編寫(xiě)可變參數(shù)函數(shù)

    C語(yǔ)言中編寫(xiě)可變參數(shù)函數(shù)

    這篇文章主要介紹了C語(yǔ)言中編寫(xiě)可變參數(shù)函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • C語(yǔ)言實(shí)現(xiàn)貪吃蛇超詳細(xì)教程

    C語(yǔ)言實(shí)現(xiàn)貪吃蛇超詳細(xì)教程

    本文詳細(xì)講解了C語(yǔ)言實(shí)現(xiàn)貪吃蛇的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • 詳解C語(yǔ)言之緩沖區(qū)溢出

    詳解C語(yǔ)言之緩沖區(qū)溢出

    緩沖區(qū)是一塊連續(xù)的計(jì)算機(jī)內(nèi)存區(qū)域,可保存相同數(shù)據(jù)類型的多個(gè)實(shí)例。緩沖區(qū)可以是堆棧、堆和靜態(tài)數(shù)據(jù)區(qū)。在C/C++語(yǔ)言中,通常使用字符數(shù)組和malloc/new實(shí)現(xiàn)緩沖區(qū)。溢出指數(shù)據(jù)被添加到分配給該緩沖區(qū)的內(nèi)存塊之外。緩沖區(qū)溢出是最常見(jiàn)的程序缺陷
    2021-06-06
  • Opencv實(shí)現(xiàn)畫(huà)筆功能

    Opencv實(shí)現(xiàn)畫(huà)筆功能

    這篇文章主要為大家詳細(xì)介紹了Opencv實(shí)現(xiàn)畫(huà)筆功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • C語(yǔ)言編寫(xiě)一個(gè)鏈表

    C語(yǔ)言編寫(xiě)一個(gè)鏈表

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言編寫(xiě)一個(gè)鏈表,文中安裝步驟介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • C語(yǔ)言宏定義的擴(kuò)展定義講解

    C語(yǔ)言宏定義的擴(kuò)展定義講解

    這篇文章主要介紹了C語(yǔ)言宏定義的擴(kuò)展,宏定義是C語(yǔ)言提供的三種預(yù)處理功能的其中一種,這三種預(yù)處理包括:宏定義、文件包含、條件編譯
    2022-12-12
  • C++?Boost?Xpressive示例分析使用

    C++?Boost?Xpressive示例分析使用

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱
    2022-11-11

最新評(píng)論