int InputProcessor::unpackageVideo(unsigned char* inBuff, int inBuffLen, unsigned char* outBuff, int* gotFrame) { if (videoUnpackager == 0) { ELOG_DEBUG("Unpackager not correctly initialized"); return -1; } int inBuffOffset = 0; *gotFrame = 0; RtpHeader* head = reinterpret_cast<RtpHeader*>(inBuff); if (head->getPayloadType() != 100) { return -1; } int l = inBuffLen - head->getHeaderLength(); inBuffOffset+=head->getHeaderLength(); erizo::RTPPayloadVP8* parsed = pars.parseVP8((unsigned char*) &inBuff[inBuffOffset], l); memcpy(outBuff, parsed->data, parsed->dataLength); if (head->getMarker()) { *gotFrame = 1; } int ret = parsed->dataLength; delete parsed; return ret; }
int main(int argc, const char * argv[]) { // data setup uint32_t first = 0xFFFF | 0x1FFFFFFF; uint32_t timestamp = 0x0128; uint32_t ssrc = 0x01 | 0x02 | 0x04 | 0x08 | 0x256; int somedata[4]; // The htonl() function converts the unsigned integer hostlong from host byte order to network byte order. // on the other side: // The ntohl() function converts the unsigned integer netlong from network byte order to host byte order. somedata[0] = htonl(first); somedata[1] = htonl(timestamp); somedata[2] = htonl(ssrc); somedata[2] = htonl(ssrc); somedata[3] = htonl(ssrc); RtpHeader* head = reinterpret_cast<RtpHeader*>(somedata); printf("version: %" PRIu8 "\n", head->getVersion()); printf("padding: %" PRIu8 "\n", head->hasPadding()); printf("extension: %" PRIu8 "\n", head->getExtension()); printf("marker: %" PRIu8 "\n", head->getMarker()); printf("payload type: %" PRIu8 "\n", head->getPayloadType()); printf("sequence number: %" PRIu16 "\n", head->getSeqNumber()); printf("timestamp %" PRIu32 "\n", head->getTimestamp()); printf("ssrc %" PRIu32 "\n", head->getSSRC()); printf("header length: %u\n", head->getHeaderLength()); return 0; }
void ExternalOutput::writeVideoData(char* buf, int len){ RtpHeader* head = reinterpret_cast<RtpHeader*>(buf); uint16_t currentVideoSeqNumber = head->getSeqNumber(); if (currentVideoSeqNumber != lastVideoSequenceNumber_ + 1) { // Something screwy. We should always see sequence numbers incrementing monotonically. ELOG_DEBUG("Unexpected video sequence number; current %d, previous %d", currentVideoSeqNumber, lastVideoSequenceNumber_); // Set our search state to look for the start of a frame, and discard what we currently have (if anything). it's now worthless. vp8SearchState_ = lookingForStart; unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; } lastVideoSequenceNumber_ = currentVideoSeqNumber; if (firstVideoTimestamp_ == -1) { firstVideoTimestamp_ = head->getTimestamp(); } // TODO we should be tearing off RTP padding here, if it exists. But WebRTC currently does not use padding. RtpVP8Parser parser; erizo::RTPPayloadVP8* payload = parser.parseVP8(reinterpret_cast<unsigned char*>(buf + head->getHeaderLength()), len - head->getHeaderLength()); bool endOfFrame = (head->getMarker() > 0); bool startOfFrame = payload->beginningOfPartition; bool deliver = false; switch(vp8SearchState_) { case lookingForStart: if(startOfFrame && endOfFrame) { // This packet is a standalone frame. Send it on. Look for start. unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; memcpy(unpackagedBufferpart_, payload->data, payload->dataLength); unpackagedSize_ += payload->dataLength; unpackagedBufferpart_ += payload->dataLength; deliver = true; } else if (!startOfFrame && !endOfFrame) { // This is neither the start nor the end of a frame. Reset our buffers. Look for start. unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; } else if (startOfFrame && !endOfFrame) { // Found start frame. Copy to buffers. Look for our end. memcpy(unpackagedBufferpart_, payload->data, payload->dataLength); unpackagedSize_ += payload->dataLength; unpackagedBufferpart_ += payload->dataLength; vp8SearchState_ = lookingForEnd; } else { // (!startOfFrame && endOfFrame) // We got the end of a frame. Reset our buffers. unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; } break; case lookingForEnd: if(startOfFrame && endOfFrame) { // Unexpected. We were looking for the end of a frame, and got a whole new frame. // Reset our buffers, send this frame on, and go to the looking for start state. vp8SearchState_ = lookingForStart; unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; memcpy(unpackagedBufferpart_, payload->data, payload->dataLength); unpackagedSize_ += payload->dataLength; unpackagedBufferpart_ += payload->dataLength; deliver = true; } else if (!startOfFrame && !endOfFrame) { // This is neither the start nor the end. Add it to our unpackage buffer. memcpy(unpackagedBufferpart_, payload->data, payload->dataLength); unpackagedSize_ += payload->dataLength; unpackagedBufferpart_ += payload->dataLength; } else if (startOfFrame && !endOfFrame) { // Unexpected. We got the start of a frame. Clear out our buffer, toss this payload in, and continue looking for the end. unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; memcpy(unpackagedBufferpart_, payload->data, payload->dataLength); unpackagedSize_ += payload->dataLength; unpackagedBufferpart_ += payload->dataLength; } else { // (!startOfFrame && endOfFrame) // Got the end of a frame. Let's deliver and start looking for the start of a frame. vp8SearchState_ = lookingForStart; memcpy(unpackagedBufferpart_, payload->data, payload->dataLength); unpackagedSize_ += payload->dataLength; unpackagedBufferpart_ += payload->dataLength; deliver = true; } break; } delete payload; //ELOG_DEBUG("Parsed VP8 payload, endOfFrame: %d, startOfFrame: %d, partitionId: %d", endOfFrame, startOfFrame, partitionId); this->initContext(); if (video_stream_ == NULL) { // could not init our context yet. return; } if (deliver) { unpackagedBufferpart_ -= unpackagedSize_; long long currentTimestamp = head->getTimestamp(); if (currentTimestamp - firstVideoTimestamp_ < 0) { // we wrapped. add 2^32 to correct this. We only handle a single wrap around since that's ~13 hours of recording, minimum. currentTimestamp += 0xFFFFFFFF; } long long timestampToWrite = (currentTimestamp - firstVideoTimestamp_) / (90000 / video_stream_->time_base.den); // All of our video offerings are using a 90khz clock. // Adjust for our start time offset timestampToWrite += videoOffsetMsec_ / (1000 / video_stream_->time_base.den); // in practice, our timebase den is 1000, so this operation is a no-op. /* ELOG_DEBUG("Writing video frame %d with timestamp %u, normalized timestamp %u, video offset msec %u, length %d, input timebase: %d/%d, target timebase: %d/%d", */ /* head->getSeqNumber(), head->getTimestamp(), timestampToWrite, videoOffsetMsec_, unpackagedSize_, */ /* video_stream_->codec->time_base.num, video_stream_->codec->time_base.den, // timebase we requested */ /* video_stream_->time_base.num, video_stream_->time_base.den); // actual timebase */ AVPacket avpkt; av_init_packet(&avpkt); avpkt.data = unpackagedBufferpart_; avpkt.size = unpackagedSize_; avpkt.pts = timestampToWrite; avpkt.stream_index = 0; av_write_frame(context_, &avpkt); av_free_packet(&avpkt); unpackagedSize_ = 0; unpackagedBufferpart_ = unpackagedBuffer_; } }