extern "C" u_int16_t MP4AV_AudioGetSamplingWindow( MP4FileHandle mp4File, MP4TrackId audioTrackId) { u_int8_t audioType = MP4GetTrackEsdsObjectTypeId(mp4File, audioTrackId); if (audioType == MP4_INVALID_AUDIO_TYPE) { return 0; } if (MP4_IS_MP3_AUDIO_TYPE(audioType)) { MP4AV_Mp3Header mp3Hdr = GetMp3Header(mp4File, audioTrackId); return MP4AV_Mp3GetHdrSamplingWindow(mp3Hdr); } else if (MP4_IS_AAC_AUDIO_TYPE(audioType)) { u_int8_t* pAacConfig = NULL; u_int32_t aacConfigLength; MP4GetTrackESConfiguration( mp4File, audioTrackId, &pAacConfig, &aacConfigLength); if (pAacConfig == NULL || aacConfigLength < 2) { return 0; } u_int32_t samplingWindow = MP4AV_AacConfigGetSamplingWindow(pAacConfig); free(pAacConfig); return samplingWindow; } else if ((audioType == MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE)|| (audioType == MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE)) { MP4Duration frameDuration = MP4GetSampleDuration(mp4File, audioTrackId, 1); // assumes track time scale == sampling rate // and constant frame size was used return frameDuration; } return 0; }
//#define DEBUG_G711 1 extern "C" bool G711Hinter (MP4FileHandle mp4file, MP4TrackId trackid, uint16_t maxPayloadSize) { uint32_t numSamples; uint8_t audioType; MP4SampleId sampleId; uint32_t sampleSize; MP4TrackId hintTrackId; uint8_t payload; uint32_t bytes_this_hint; uint32_t sampleOffset; numSamples = MP4GetTrackNumberOfSamples(mp4file, trackid); if (numSamples == 0) return false; audioType = MP4GetTrackEsdsObjectTypeId(mp4file, trackid); if (audioType != MP4_ALAW_AUDIO_TYPE && audioType != MP4_ULAW_AUDIO_TYPE) return false; hintTrackId = MP4AddHintTrack(mp4file, trackid); if (hintTrackId == MP4_INVALID_TRACK_ID) { return false; } const char *type; if (audioType == MP4_ALAW_AUDIO_TYPE) { payload = 8; type = "PCMA"; } else { payload = 0; type = "PCMU"; } MP4SetHintTrackRtpPayload(mp4file, hintTrackId, type, &payload, 0,NULL, false); MP4Duration sampleDuration; bool have_skip; sampleId = 1; sampleSize = MP4GetSampleSize(mp4file, trackid, sampleId); sampleDuration = MP4GetSampleDuration(mp4file, trackid, sampleId); have_skip = sampleDuration != sampleSize; sampleOffset = 0; bytes_this_hint = 0; if (maxPayloadSize > 160) maxPayloadSize = 160; while (1) { if (bytes_this_hint == 0) { #ifdef DEBUG_G711 printf("Adding hint/packet\n"); #endif MP4AddRtpHint(mp4file, hintTrackId); MP4AddRtpPacket(mp4file, hintTrackId, false); // marker bit 0 } uint16_t bytes_left_this_packet; bytes_left_this_packet = maxPayloadSize - bytes_this_hint; if (sampleSize >= bytes_left_this_packet) { MP4AddRtpSampleData(mp4file, hintTrackId, sampleId, sampleOffset, bytes_left_this_packet); bytes_this_hint += bytes_left_this_packet; sampleSize -= bytes_left_this_packet; sampleOffset += bytes_left_this_packet; #ifdef DEBUG_G711 printf("Added sample with %u bytes\n", bytes_left_this_packet); #endif } else { MP4AddRtpSampleData(mp4file, hintTrackId, sampleId, sampleOffset, sampleSize); bytes_this_hint += sampleSize; #ifdef DEBUG_G711 printf("Added sample with %u bytes\n", sampleSize); #endif sampleSize = 0; } if (bytes_this_hint >= maxPayloadSize) { // Write the hint // duration is bytes written MP4WriteRtpHint(mp4file, hintTrackId, bytes_this_hint); #ifdef DEBUG_G711 printf("Finished packet - bytes %u\n", bytes_this_hint); #endif bytes_this_hint = 0; } if (sampleSize == 0) { // next sample if (have_skip && bytes_this_hint != 0) { #ifdef DEBUG_G711 printf("duration - ending packet - bytes %u\n", bytes_this_hint); #endif MP4WriteRtpHint(mp4file, hintTrackId, bytes_this_hint); bytes_this_hint = 0; } sampleId++; if (sampleId > numSamples) { // finish it and exit if (bytes_this_hint != 0) { MP4WriteRtpHint(mp4file, hintTrackId, bytes_this_hint); } return true; } sampleSize = MP4GetSampleSize(mp4file, trackid, sampleId); sampleDuration = MP4GetSampleDuration(mp4file, trackid, sampleId); have_skip = sampleDuration != sampleSize; #ifdef DEBUG_G711 printf("Next sample %u - size %u %u\n", sampleId, sampleSize, have_skip); #endif sampleOffset = 0; } } return true; // will never reach here }
extern "C" bool MP4AV_Rfc2429Hinter (MP4FileHandle file, MP4TrackId mediaTrackId, uint16_t maxPayloadSize) { uint32_t numSamples, maxSampleSize; MP4TrackId hid; MP4Duration duration; numSamples = MP4GetTrackNumberOfSamples(file, mediaTrackId); if (numSamples == 0) { return false; } maxSampleSize = MP4GetTrackMaxSampleSize(file, mediaTrackId); u_int8_t* pSampleBuffer = (u_int8_t*)malloc(maxSampleSize); if (pSampleBuffer == NULL) { return false; } hid = MP4AddHintTrack(file, mediaTrackId); if (hid == MP4_INVALID_TRACK_ID) { return false; } uint8_t payloadNumber = MP4_SET_DYNAMIC_PAYLOAD; MP4SetHintTrackRtpPayload(file, hid, "H263-2000", &payloadNumber, 0, NULL, true, false); // strictly speaking, this is not required for H.263 - it's a quicktime // thing. u_int16_t videoWidth = MP4GetTrackVideoWidth(file, mediaTrackId); u_int16_t videoHeight = MP4GetTrackVideoHeight(file, mediaTrackId); char sdpString[80]; sprintf(sdpString, "a=cliprect:0,0,%d,%d\015\012", videoHeight, videoWidth); MP4AppendHintTrackSdp(file, hid, sdpString); for (uint32_t sid = 1; sid <= numSamples; sid++) { duration = MP4GetSampleDuration(file, mediaTrackId, sid); MP4AddRtpVideoHint(file, hid, false, 0); u_int32_t sampleSize = maxSampleSize; MP4Timestamp startTime; MP4Duration duration; MP4Duration renderingOffset; bool isSyncSample; bool rc = MP4ReadSample(file, mediaTrackId, sid, &pSampleBuffer, &sampleSize, &startTime, &duration, &renderingOffset, &isSyncSample); if (!rc) { MP4DeleteTrack(file, hid); free(pSampleBuffer); return false; } // need to skip the first 2 bytes of the packet - it is the //start code uint16_t payload_head = htons(0x400); uint32_t offset = sizeof(payload_head); uint32_t remaining = sampleSize - sizeof(payload_head); while (remaining) { bool last_pak = false; uint32_t len; if (remaining + 2 <= maxPayloadSize) { len = remaining; last_pak = true; } else { len = maxPayloadSize - 2; } MP4AddRtpPacket(file, hid, last_pak); MP4AddRtpImmediateData(file, hid, (u_int8_t*)&payload_head, sizeof(payload_head)); payload_head = 0; MP4AddRtpSampleData(file, hid, sid, offset, len); offset += len; remaining -= len; } MP4WriteRtpHint(file, hid, duration, true); } free(pSampleBuffer); return true; }
QWORD MP4RtpTrack::Read(Listener *listener) { int last = 0; uint8_t* data; bool isSyncSample; // If it's first packet of a frame if (!numHintSamples) { // Get number of rtp packets for this sample if (!MP4ReadRtpHint(mp4, hint, sampleId, &numHintSamples)) { //Print error Error("Error reading hintt"); //Exit return MP4_INVALID_TIMESTAMP; } // Get number of samples for this sample frameSamples = MP4GetSampleDuration(mp4, hint, sampleId); // Get size of sample frameSize = MP4GetSampleSize(mp4, hint, sampleId); // Get sample timestamp frameTime = MP4GetSampleTime(mp4, hint, sampleId); //Convert to miliseconds frameTime = MP4ConvertFromTrackTimestamp(mp4, hint, frameTime, 1000); // Check if it is H264 and it is a Sync frame if (codec==VideoCodec::H264 && MP4GetSampleSync(mp4,track,sampleId)) // Send SEI info SendH263SEI(listener); //Get max data lenght BYTE *data = NULL; DWORD dataLen = 0; MP4Timestamp startTime; MP4Duration duration; MP4Duration renderingOffset; //Get values data = frame->GetData(); dataLen = frame->GetMaxMediaLength(); // Read next rtp packet if (!MP4ReadSample( mp4, // MP4FileHandle hFile track, // MP4TrackId hintTrackId sampleId, // MP4SampleId sampleId, (u_int8_t **) &data, // u_int8_t** ppBytes (u_int32_t *) &dataLen, // u_int32_t* pNumBytes &startTime, // MP4Timestamp* pStartTime &duration, // MP4Duration* pDuration &renderingOffset, // MP4Duration* pRenderingOffset &isSyncSample // bool* pIsSyncSample )) { Error("Error reading sample"); //Last return MP4_INVALID_TIMESTAMP; } //Check type if (media == MediaFrame::Video) { //Get video frame VideoFrame *video = (VideoFrame*)frame; //Set lenght video->SetLength(dataLen); //Timestamp video->SetTimestamp(startTime*90000/timeScale); //Set intra video->SetIntra(isSyncSample); } else { //Get Audio frame AudioFrame *audio = (AudioFrame*)frame; //Set lenght audio->SetLength(dataLen); //Timestamp audio->SetTimestamp(startTime*8000/timeScale); } //Check listener if (listener) //Frame callback listener->onMediaFrame(*frame); } // if it's the last if (packetIndex + 1 == numHintSamples) //Set last mark last = 1; // Set mark bit rtp.SetMark(last); // Get data pointer data = rtp.GetMediaData(); //Get max data lenght DWORD dataLen = rtp.GetMaxMediaLength(); // Read next rtp packet if (!MP4ReadRtpPacket( mp4, // MP4FileHandle hFile hint, // MP4TrackId hintTrackId packetIndex++, // u_int16_t packetIndex (u_int8_t **) &data, // u_int8_t** ppBytes (u_int32_t *) &dataLen, // u_int32_t* pNumBytes 0, // u_int32_t ssrc DEFAULT(0) 0, // bool includeHeader DEFAULT(true) 1 // bool includePayload DEFAULT(true) )) { //Error Error("Error reading packet [%d,%d,%d]\n", hint, track,packetIndex); //Exit return MP4_INVALID_TIMESTAMP; } //Check if (dataLen>rtp.GetMaxMediaLength()) { //Error Error("RTP packet too big [%u,%u]\n",dataLen,rtp.GetMaxMediaLength()); //Exit return MP4_INVALID_TIMESTAMP; } //Set lenght rtp.SetMediaLength(dataLen); // Write frame listener->onRTPPacket(rtp); // Are we the last packet in a hint? if (last) { // The first hint packetIndex = 0; // Go for next sample sampleId++; numHintSamples = 0; //Return next frame time return GetNextFrameTime(); } // This packet is this one return frameTime; }