static void upipe_rtp_h264_output_nalu(struct upipe *upipe, uint8_t nalu, struct uref *uref, struct upump **upump_p) { size_t size = 0; if (unlikely(!ubase_check(uref_block_size(uref, &size)))) { upipe_err(upipe, "fail to get block size"); return; } bool split = size > RTP_SPLIT_SIZE; uint32_t fragment = 0; while (size) { bool last_fragment = size <= RTP_SPLIT_SIZE; size_t split_size = last_fragment ? size : RTP_SPLIT_SIZE; uint8_t hdr[2] = { nalu, 0 }; size_t hdr_size = 1; if (split) { if (!fragment) hdr[1] = FU_START; else if (last_fragment) hdr[1] = FU_END; hdr[1] |= NALU_TYPE(hdr[0]); hdr[0] = NALU_F(hdr[0]) | NALU_NRI(hdr[0]) | FU_A; hdr_size++; } struct uref *next = NULL; if (!last_fragment) { next = uref_block_split(uref, split_size); if (unlikely(next == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } } /* FIXME should require a ubuf_mgr */ struct ubuf *header = ubuf_block_alloc(uref->ubuf->mgr, hdr_size * sizeof (hdr[0])); if (unlikely(header == NULL)) { upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); uref_free(uref); uref_free(next); return; } uint8_t *buf = NULL; int buf_size = hdr_size; ubuf_block_write(header, 0, &buf_size, &buf); memcpy(buf, hdr, hdr_size * sizeof (hdr[0])); ubuf_block_unmap(header, 0); /* append payload (current ubuf) to header to form segmented ubuf */ struct ubuf *payload = uref_detach_ubuf(uref); if (unlikely(!ubase_check(ubuf_block_append(header, payload)))) { upipe_warn(upipe, "could not append payload to header"); ubuf_free(header); ubuf_free(payload); uref_free(uref); uref_free(next); return; } uref_attach_ubuf(uref, header); uref_clock_set_cr_dts_delay(uref, 0); upipe_rtp_h264_output(upipe, uref, upump_p); size -= split_size; fragment++; uref = next; } }
bool OutNetRTMP4TSStream::FeedVideoData(uint8_t *pData, uint32_t dataLength, double absoluteTimestamp) { switch (NALU_TYPE(pData[0])) { case NALU_TYPE_SPS: { //1. Prepare the SPS part from video codec if (dataLength > 128) { FATAL("SPS too big"); return false; } memcpy(_pSPSPPS + 6, pData + 1, 3); //profile,profile compat,level EHTONSP(_pSPSPPS + 11, (uint16_t) dataLength); memcpy(_pSPSPPS + 13, pData, dataLength); _PPSStart = 13 + dataLength; _spsAvailable = true; return true; } case NALU_TYPE_PPS: { //2. Prepare the PPS part from video codec if (dataLength > 128) { FATAL("PPS too big"); return false; } if (!_spsAvailable) { WARN("No SPS available yet"); return true; } _pSPSPPS[_PPSStart] = 1; EHTONSP(_pSPSPPS + _PPSStart + 1, (uint16_t) dataLength); memcpy(_pSPSPPS + _PPSStart + 1 + 2, pData, dataLength); _spsAvailable = false; //3. Send the video codec if (!BaseOutNetRTMPStream::FeedData( _pSPSPPS, //pData _PPSStart + 1 + 2 + dataLength, //dataLength 0, //processedLength _PPSStart + 1 + 2 + dataLength, //totalLength absoluteTimestamp, //absoluteTimestamp false //isAudio )) { FATAL("Unable to send video codec setup"); return false; } _videoCodecSent = true; return true; } case NALU_TYPE_IDR: case NALU_TYPE_SLICE: { //10. Make room for the RTMP header _videoBuffer.ReadFromRepeat(0, 9); //11. Add the raw data _videoBuffer.ReadFromBuffer(pData, dataLength); uint8_t *pBuffer = GETIBPOINTER(_videoBuffer); //12. Setup the RTMP header pBuffer[0] = (NALU_TYPE(pData[0]) == NALU_TYPE_IDR) ? 0x17 : 0x27; pBuffer[1] = 0x01; pBuffer[2] = pBuffer[3] = pBuffer[4] = 0; EHTONLP(pBuffer + 5, dataLength); //----MARKED-LONG--- //13. Send it if (!BaseOutNetRTMPStream::FeedData( pBuffer, //pData dataLength + 9, //dataLength 0, //processedLength dataLength + 9, //totalLength absoluteTimestamp, //absoluteTimestamp false //isAudio )) { FATAL("Unable to send video"); return false; } //14. Cleanup _videoBuffer.IgnoreAll(); return true; } case NALU_TYPE_PD: case NALU_TYPE_SEI: case NALU_TYPE_FILL: { return true; } default: { WARN("Ignoring NAL: %s", STR(NALUToString(pData[0]))); return true; } } }