bool MP4Encoder::Write264Metadata(MP4FileHandle hMp4File,LPMP4ENC_Metadata lpMetadata) { m_videoId = MP4AddH264VideoTrack (hMp4File, m_nTimeScale, m_nTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight,// height lpMetadata->Sps[1], // sps[1] AVCProfileIndication lpMetadata->Sps[2], // sps[2] profile_compat lpMetadata->Sps[3], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return false; } MP4SetVideoProfileLevel(hMp4File, 0x01); // Simple Profile @ Level 3 // write sps MP4AddH264SequenceParameterSet(hMp4File,m_videoId,lpMetadata->Sps,lpMetadata->nSpsLen); // write pps MP4AddH264PictureParameterSet(hMp4File,m_videoId,lpMetadata->Pps,lpMetadata->nPpsLen); return true; }
static void init_video_track(MP4FileHandle mp4, MP4TrackId *video, switch_frame_t *frame) { int width = 0; int height = 0; uint8_t *sps_buffer = frame->data; uint32_t sps_bytes = frame->datalen; sps_buffer++; if (frame->img) { width = frame->img->d_w; height = frame->img->d_h; } else { parse_sps_video_size(sps_buffer, sps_bytes, &width, &height); } MP4SetTimeScale(mp4, TIMESCALE); *video = MP4AddH264VideoTrack(mp4, TIMESCALE, MP4_INVALID_DURATION, width, height, *(sps_buffer), *(sps_buffer+1), *(sps_buffer+2), SampleLenFieldSize - 1); if (*video == MP4_INVALID_TRACK_ID) { return; } MP4AddH264SequenceParameterSet(mp4, *video, --sps_buffer, sps_bytes); /* MP4SetVideoProfileLevel sets the minumum profile/level of MPEG-4 video support necessary to render the contents of the file. ISO/IEC 14496-1:2001 MPEG-4 Systems defines the following values: 0x00 Reserved 0x01 Simple Profile @ Level 3 0x02 Simple Profile @ Level 2 0x03 Simple Profile @ Level 1 0x04 Simple Scalable Profile @ Level 2 0x05 Simple Scalable Profile @ Level 1 0x06 Core Profile @ Level 2 0x07 Core Profile @ Level 1 0x08 Main Profile @ Level 4 0x09 Main Profile @ Level 3 0x0A Main Profile @ Level 2 0x0B N-Bit Profile @ Level 2 0x0C Hybrid Profile @ Level 2 0x0D Hybrid Profile @ Level 1 0x0E Basic Animated Texture @ Level 2 0x0F Basic Animated Texture @ Level 1 0x10 Scalable Texture @ Level 3 0x11 Scalable Texture @ Level 2 0x12 Scalable Texture @ Level 1 0x13 Simple Face Animation @ Level 2 0x14 Simple Face Animation @ Level 1 0x15-0x7F Reserved 0x80-0xFD User private 0xFE No audio profile specified 0xFF No audio required */ MP4SetVideoProfileLevel(mp4, 0x7F); }
int Mp4Encoder::WriteH264Data(u_char * pData, int size) { int type = pData[4] & 0x1f; if (type == 0x07) { // sps // 添加h264 track if (m_videoId == MP4_INVALID_TRACK_ID) { m_videoId = MP4AddH264VideoTrack(m_hMp4File, m_nVTimeScale, m_nVTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight, // height pData[5], // sps[1] AVCProfileIndication pData[6], // sps[2] profile_compat pData[7], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return 0; } MP4SetVideoProfileLevel(m_hMp4File, 0x7F); // Simple Profile @ Level } MP4AddH264SequenceParameterSet(m_hMp4File, m_videoId, pData + 4, size - 4); } else if (type == 0x08) { // pps MP4AddH264PictureParameterSet(m_hMp4File, m_videoId, pData + 4, size - 4); } else { // MP4 Nalu前四个字节表示Nalu长度(no 00 00 00 01) pData[0] = (size - 4) >> 24; pData[1] = (size - 4) >> 16; pData[2] = (size - 4) >> 8; pData[3] = (size - 4) & 0xff; if (!MP4WriteSample (m_hMp4File, m_videoId, pData, size, MP4_INVALID_DURATION, 0, 1)) { return 0; } } return 0; }
bool mpeg_video_recorder::InitRecording(int width, int height){ coid::charstr mp4FileName(m_sVideoFolderPath); mp4FileName << "capture_"; mp4FileName << coid::msec_timer::get_time(); mp4FileName << ".mp4"; MP4FileHandle fileHandle = MP4Create(mp4FileName.c_str(), MP4FileMode::FILEMODE_CREATE); if (!MP4_IS_VALID_FILE_HANDLE(fileHandle)){ coid::charstr msg; msg << ERRORMESSAGE(" "); msg << "Can't create Mp4 file! Path: " << mp4FileName; log(msg); return false; } m_IsRecording = true; m_hMp4FileHandle = fileHandle; m_iVideoTrackID = MP4_INVALID_TRACK_ID; coid::bifstream cfgFile(m_sVideoFolderPath+"x264.cfg"); coid::fmtstreamcxx fmt; coid::metastream meta(fmt); if (cfgFile.is_open()){ try{ fmt.bind(cfgFile); meta.stream_in(m_oX264Cfg); } catch (coid::exception& e){ } } else{ log(WARNINGMESSAGE("x264 configuration file does not exists!")); fmt.bind(coid::nullstream); meta.xstream_in(m_oX264Cfg); } meta.stream_acknowledge(); x264_param_t param; x264_param_default_preset(¶m, m_oX264Cfg.m_sPreset.c_str(), "zerolatency"); param.i_threads = m_oX264Cfg.m_iThreadCount; param.i_width = width; param.i_height = height; param.i_fps_num = 30; param.i_fps_den = 1; // Intra refres: param.i_keyint_max = 30; param.b_intra_refresh = 1; //Rate control: param.rc.i_rc_method = X264_RC_CRF; param.rc.f_rf_constant = 25; param.rc.f_rf_constant_max = 35; //For streaming: param.b_repeat_headers = 1; param.b_annexb = 1; x264_param_apply_profile(¶m, "baseline"); m_pEncoder = x264_encoder_open(¶m); MP4TrackId videoTrackID = MP4AddH264VideoTrack(m_hMp4FileHandle, 90000, MP4_INVALID_DURATION, width, height, 0, 1, 0, 3); if (!MP4_IS_VALID_TRACK_ID(videoTrackID)){ MP4Close(m_hMp4FileHandle); return false; } m_iVideoTrackID = videoTrackID; m_iWidth = width; m_iHeight = height; m_pLastNals = NULL; m_uiLastTimestampNs = 0; m_uiFrameIndex = 0; return true; }
int MP4Encoder::WriteH264Data(MP4FileHandle hMp4File,const unsigned char* pData,int size) { if(hMp4File == NULL) { return -1; } if(pData == NULL) { return -1; } MP4ENC_NaluUnit nalu; int pos = 0, len = 0; while (len = ReadOneNaluFromBuf(pData,size,pos,nalu)) { if(nalu.type == 0x07) // sps { // 添加h264 track m_videoId = MP4AddH264VideoTrack (hMp4File, m_nTimeScale, m_nTimeScale / m_nFrameRate, m_nWidth, // width m_nHeight, // height nalu.data[1], // sps[1] AVCProfileIndication nalu.data[2], // sps[2] profile_compat nalu.data[3], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (m_videoId == MP4_INVALID_TRACK_ID) { printf("add video track failed.\n"); return 0; } MP4SetVideoProfileLevel(hMp4File, 1); // Simple Profile @ Level 3 MP4AddH264SequenceParameterSet(hMp4File,m_videoId,nalu.data,nalu.size); } else if(nalu.type == 0x08) // pps { MP4AddH264PictureParameterSet(hMp4File,m_videoId,nalu.data,nalu.size); } else { int datalen = nalu.size+4; unsigned char *data = new unsigned char[datalen]; // MP4 Nalu前四个字节表示Nalu长度 data[0] = nalu.size>>24; data[1] = nalu.size>>16; data[2] = nalu.size>>8; data[3] = nalu.size&0xff; memcpy(data+4,nalu.data,nalu.size); if(!MP4WriteSample(hMp4File, m_videoId, data, datalen,MP4_INVALID_DURATION, 0, 1)) { return 0; } delete[] data; } pos += len; } return pos; }