📄 h264.cpp
字号:
return 1;}/* * Parse the RBSP with NAL unit type of IDR(Coded slice of an IDR picture), and * get the slice type(I,P,B) of this slice. */static int parseNALU_IDR_SLICE(u_int8_t* pBuf, u_int32_t* pBufSize, u_int32_t* slice_type){ u_int32_t tmp, i = 0, j = 0; // SH: first_mb_in_slice : ue(v) ue_v(pBuf, &i, &j); // SH: slice_type : ue(v) tmp = ue_v(pBuf, &i, &j); if (tmp > 4) { tmp -= 5; } *slice_type = tmp; return 1;}MP4TrackId H264Creator(MP4FileHandle mp4File, FILE* inFile){ bool rc; u_int8_t sampleBuffer[256 * 1024]; u_int8_t analyzeBuffer[256 * 1024]; u_int32_t maxSampleSize = sizeof(sampleBuffer); u_int8_t* pCurrentBuf = sampleBuffer; u_int8_t* pNaluBuf = sampleBuffer; u_int32_t naluBufSize; u_int8_t* pRbspBuf = analyzeBuffer; u_int32_t rbspBufSize; // the current sample MP4SampleId sampleId = 1; MP4Timestamp currentSampleTime = 0; // the last reference VOP MP4SampleId refVopId = 1; MP4Timestamp refVopTime = 0; // track configuration info u_int8_t videoProfileLevel = 0x03; u_int16_t timeTicks = 1; u_int16_t slice_width = 320; u_int16_t slice_height = 240; u_int32_t esConfigSize = 0; u_int32_t slice_type = 0; u_int32_t forbidden_bit; u_int32_t nal_ref_idc; u_int32_t nal_unit_type; bool foundSPS = false, foundPPS = false, foundIDR = false; // start reading NAL unit until we get the first NAL unit with IDR do { if (!LoadNextNALU(inFile, pNaluBuf, &naluBufSize)) { fprintf(stderr, "%s : No NAL unit with type of IDR!\n", ProgName); return MP4_INVALID_TRACK_ID; } rbspBufSize = naluBufSize; memcpy(pRbspBuf, pNaluBuf, naluBufSize); parseAnnexbNALU(pRbspBuf, &rbspBufSize, &forbidden_bit, &nal_ref_idc, &nal_unit_type); switch (nal_unit_type) { case NALU_TYPE_SPS: // NALU_TYPE_SPS parseNALU_SPS(pRbspBuf, &rbspBufSize, &slice_width, &slice_height); fprintf(stderr, "Parse SPS NALU: img_width = %d, img_height = %d\n",slice_width, slice_height); foundSPS = true; break; case NALU_TYPE_PPS: // NALU_TYPE_PPS foundPPS = true; break; case NALU_TYPE_IDR: foundIDR = true; break; case NALU_TYPE_SLICE: break; } if (!foundIDR) { esConfigSize += naluBufSize; pNaluBuf += naluBufSize; } } while (!foundIDR); if (foundSPS == false) { fprintf(stderr, "%s: fatal: No NAL unit type of SPS found in video stream\n", ProgName); return MP4_INVALID_TRACK_ID; } if (foundPPS == false) { fprintf(stderr, "%s: fatal: No NAL unit type of PPS found in video stream\n", ProgName); return MP4_INVALID_TRACK_ID; } timeTicks = 1; u_int32_t mp4FrameDuration; // convert frame duration to canonical time scale if (VideoFrameRate) { mp4FrameDuration = (u_int32_t)(((float)Mp4TimeScale) / VideoFrameRate); } else { mp4FrameDuration = (u_int32_t)(((float)Mp4TimeScale) / 25); } // create the new video track MP4TrackId trackId = MP4AddVideoTrack( mp4File, Mp4TimeScale, mp4FrameDuration, slice_width, slice_height, MP4_H264_VIDEO_TYPE); if (trackId == MP4_INVALID_TRACK_ID) { fprintf(stderr, "%s: can't create video track\n", ProgName); return MP4_INVALID_TRACK_ID; } if (VideoProfileLevelSpecified) { videoProfileLevel = VideoProfileLevel; } if (MP4GetNumberOfTracks(mp4File, MP4_VIDEO_TRACK_TYPE) == 1) { MP4SetVideoProfileLevel(mp4File, MP4AV_Mpeg4VideoToSystemsProfileLevel(videoProfileLevel)); } if (esConfigSize) { MP4SetTrackESConfiguration(mp4File, trackId, pCurrentBuf, esConfigSize);// pCurrentBuf += esConfigSize; } // now process the rest of the video stream while (true) { if (nal_unit_type != NALU_TYPE_IDR && nal_unit_type != NALU_TYPE_SLICE) { // keep it in the buffer until a IDR comes along pNaluBuf += naluBufSize; } else { // we have a IDR u_int32_t sampleSize = (pNaluBuf + naluBufSize) - pCurrentBuf; memcpy(pRbspBuf, pNaluBuf, naluBufSize); rbspBufSize = naluBufSize; parseAnnexbNALU(pRbspBuf, &rbspBufSize, &forbidden_bit, &nal_ref_idc, &nal_unit_type); parseNALU_IDR_SLICE(pRbspBuf, &rbspBufSize, &slice_type); rc = MP4WriteSample(mp4File, trackId, pCurrentBuf, sampleSize, mp4FrameDuration, 0, slice_type==I_SLICE); if (!rc) { fprintf(stderr, "%s: can't write video frame %u\n", ProgName, sampleId); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } // deal with rendering time offsets // that can occur when B frames are being used // which is the case for all profiles except Simple Profile if (slice_type != 1) { if (videoProfileLevel > 3) { // Note - this writes to the previous // I or P frame MP4SetSampleRenderingOffset( mp4File, trackId, refVopId, currentSampleTime - refVopTime); } refVopId = sampleId; refVopTime = currentSampleTime; } fprintf(stderr,"Frame:%d, type(%d): %s, size: %d bytes\n", sampleId, slice_type, slice_type==I_SLICE?"I":slice_type==P_SLICE?"P":slice_type==B_SLICE?"B":slice_type==SI_SLICE?"SI":slice_type==SP_SLICE?"SP":"?", sampleSize); sampleId++; currentSampleTime += mp4FrameDuration; // reset pointers pNaluBuf = pCurrentBuf = sampleBuffer; } // load next NAL unit from bitstream if (!LoadNextNALU(inFile, pNaluBuf, &naluBufSize)) { break; } // guard against buffer overflow if (pNaluBuf + naluBufSize >= pCurrentBuf + maxSampleSize) { fprintf(stderr, "%s: buffer overflow, invalid video stream?\n", ProgName); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } } // Left over at end - make sure we set the last P or I frame // with the last time if (videoProfileLevel > 3) { MP4SetSampleRenderingOffset(mp4File, trackId, refVopId, currentSampleTime - refVopTime); } return trackId;}bool MP4AV_H264Hinter( MP4FileHandle mp4File, MP4TrackId mediaTrackId, u_int16_t maxPayloadSize){ u_int32_t numSamples = MP4GetTrackNumberOfSamples(mp4File, mediaTrackId); u_int32_t maxSampleSize = MP4GetTrackMaxSampleSize(mp4File, mediaTrackId); if (numSamples == 0 || maxSampleSize == 0) { return false; } MP4TrackId hintTrackId = MP4AddHintTrack(mp4File, mediaTrackId); if (hintTrackId == MP4_INVALID_TRACK_ID) { return false; } u_int8_t payloadNumber = MP4_SET_DYNAMIC_PAYLOAD; MP4SetHintTrackRtpPayload(mp4File, hintTrackId, "H264", &payloadNumber, 0); /* get the mpeg4 video configuration */ u_int8_t* pConfig; u_int32_t configSize; u_int8_t systemsProfileLevel = 0x01; // temporary value MP4GetTrackESConfiguration(mp4File, mediaTrackId, &pConfig, &configSize); if (pConfig) { /* convert it into ASCII form */ char* sConfig = MP4BinaryToBase16(pConfig, configSize); if (sConfig == NULL) { MP4DeleteTrack(mp4File, hintTrackId); return false; } /* create the appropriate SDP attribute */ char* sdpBuf = (char*)malloc(strlen(sConfig) + 128); sprintf(sdpBuf, "a=fmtp:%u profile-level-id=%u; config=%s;\015\012", payloadNumber, systemsProfileLevel, sConfig); /* add this to the track's sdp */ MP4AppendHintTrackSdp(mp4File, hintTrackId, sdpBuf); free(sConfig); free(sdpBuf); } u_int8_t* pSampleBuffer = (u_int8_t*)malloc(maxSampleSize); if (pSampleBuffer == NULL) { MP4DeleteTrack(mp4File, hintTrackId); return false; } for (MP4SampleId sampleId = 1; sampleId <= numSamples; sampleId++) { u_int32_t sampleSize = maxSampleSize; MP4Timestamp startTime; MP4Duration duration; MP4Duration renderingOffset; bool isSyncSample; u_int32_t forbidden_bit, nal_ref_idc, nal_unit_type; u_int32_t slice_type; bool rc = MP4ReadSample( mp4File, mediaTrackId, sampleId, &pSampleBuffer, &sampleSize, &startTime, &duration, &renderingOffset, &isSyncSample); // FILE *file; // file = fopen("out.dat","ab");// fwrite(pSampleBuffer, 1, sampleSize, file);// fclose(file);// file = fopen("out.txt", "a");// fprintf(file, "SampleId = %d, Size = %d\n", sampleId, sampleSize);// fclose(file); if (!rc) { MP4DeleteTrack(mp4File, hintTrackId); return false; } u_int32_t tempSize = sampleSize; parseAnnexbNALU(pSampleBuffer, &tempSize, &forbidden_bit, &nal_ref_idc, &nal_unit_type); parseNALU_IDR_SLICE(pSampleBuffer, &tempSize, &slice_type); bool isBFrame = (slice_type==B_SLICE); MP4AddRtpVideoHint(mp4File, hintTrackId, isBFrame, renderingOffset); if (sampleId == 1) { MP4AddRtpESConfigurationPacket(mp4File, hintTrackId); } u_int32_t offset = 0; u_int32_t remaining = sampleSize; // TBD should scan for resync markers (if enabled in ES config) // and packetize on those boundaries while (remaining) { bool isLastPacket = false; u_int32_t length; if (remaining <= maxPayloadSize) { length = remaining; isLastPacket = true; } else { length = maxPayloadSize; } MP4AddRtpPacket(mp4File, hintTrackId, isLastPacket); MP4AddRtpSampleData(mp4File, hintTrackId, sampleId, offset, length); offset += length; remaining -= length; } MP4WriteRtpHint(mp4File, hintTrackId, duration, isSyncSample); } return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -