void Streamer::h264_send_frame(uint8_t* frame, int frame_size) { _frame_type = Source::frame_type(frame[0]); SBL_MSG(MSG::STREAMER, "H264 Frame '%c', size %d, timestamp %d", _frame_type, frame_size, _timestamp); if (_frame_type == 's' || _frame_type == 'p' || _frame_type == 'I') _frame_index = 0; if (frame_size <= _packet_size) { // small frame, doesn't need to be fragmented write_rtp_header(frame - RTP_HEADER, !(frame_type() == 'p' || frame_type() == 's')); send_packet(frame - RTP_HEADER, frame_size + RTP_HEADER, true); } else { // large frame, will have to be segmented. create_fu_header(frame); // move frame pointer back to make place for RTP header and FU-A (Fragmentation Unit type A) byte // FU-A header is in fact NAL header and is already in the frame, but FU-A indicator is not frame -= RTP_HEADER + FU_INDICATOR; // Only first fragment has FU-A header in the frame, subsequent ones don't and it has to be added int first_fragment = FU_HEADER; do { bool last_packet = frame_size <= _packet_size; write_rtp_header(frame, last_packet && !(frame_type() == 'p' || frame_type() == 's')); // It is unclear if End bit of FU Header should be set for SPS/PPS frames. I *assume* it does. // It probably doesn't matter, because SPS/PPS frames are small and don't need to be fragmented, // therefore they don't use FU Header at all ('small frame' 'if' clause above). write_fu_header(frame, last_packet); send_packet(frame, (frame_size < _packet_size ? frame_size : _packet_size) + RTP_HEADER + FU_INDICATOR + FU_HEADER, last_packet); frame += _packet_size; frame_size -= _packet_size + first_fragment; first_fragment = 0; } while (frame_size > 0); } _frame_index++; }
// send a frame void Streamer::mpeg4_send_frame(uint8_t* frame, int frame_size) { _mp4_starter_frame = (frame[3]==0xb0); SBL_MSG(MSG::STREAMER, "MPEG4 Frame '%d', size %d, timestamp %d", _mp4_starter_frame, frame_size, _timestamp); if (frame_size <= _packet_size) { // small frame, doesn't need to be fragmented write_rtp_header(frame - RTP_HEADER, !_mp4_starter_frame); send_packet(frame - RTP_HEADER, frame_size + RTP_HEADER, !_mp4_starter_frame); } else { // large frame, will have to be segmented. // move frame pointer back to make place for RTP header bytes frame -= RTP_HEADER; do { bool last_packet = frame_size <= _packet_size; write_rtp_header(frame, last_packet); send_packet(frame, (frame_size < _packet_size ? frame_size : _packet_size) + RTP_HEADER, last_packet); frame += _packet_size; frame_size -= _packet_size; } while (frame_size > 0); } }
int32_t create_new_rtp_packet(rtp_packet_builder_t *bldr) { rtp_header_t *rtp; mpeg4_es_desc_t *esd; size_t alloc_size; alloc_size = 0; esd = bldr->es_desc; rtp = &bldr->header; rtp->version = 0x02; rtp->padding = 0; rtp->extension = 0; rtp->CSRC_count = 0; rtp->marker = 1; rtp->payload_type = bldr->rtp_payload_type; rtp->sequence_num++; rtp->timestamp = bldr->nal->DTS; bldr->payload_size = 0; bldr->payload_hdr_size = 0; bldr->rtp_pkts = (uint8_t*)nkn_calloc_type(1, RTP_PKT_SIZE +\ bldr->mtu_size +\ AU_HDR_SIZE, mod_vpe_rtp_pkt_buf); alloc_size = RTP_PKT_SIZE + bldr->mtu_size + AU_HDR_SIZE; //bldr->rtp_pkt_size = (int32_t*)nkn_calloc_type(1, sizeof(int32_t)); //*bldr->rtp_pkt_size = bldr->mtu_size; bldr->payload_hdr = bldr->rtp_pkts + 12; bldr->payload_hdr_size = 0; bldr->payload_writer = bio_init_bitstream(bldr->rtp_pkts, RTP_PKT_SIZE + bldr->mtu_size + AU_HDR_SIZE);//*bldr->rtp_pkt_size); //write the RTP header write_rtp_header(bldr); //skip the forbidden section reseverved for AU-HEADERS, we will pack later bio_aligned_seek_bitstream(bldr->payload_writer, 12 + AU_HDR_SIZE, SEEK_SET); //reserve space for AU-Headers bldr->payload_hdr_writer = bio_init_bitstream(bldr->payload_hdr, AU_HDR_SIZE); //write the AU-Header Size Field*/ bio_write_int(bldr->payload_hdr_writer, 0, esd->auh->size_length + esd->auh->index_length); //reserve space for AU-Header Size bldr->payload_hdr_size += esd->auh->size_length + esd->auh->index_length; return 0; }
/* JPEG Header, RFC 2435 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type-specific | Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Q | Width | Height | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Type-specific: 8 bits Interpretation depends on the value of the type field. If no interpretation is specified, this field MUST be zeroed on transmission and ignored on reception. Fragment Offset: 24 bits The Fragment Offset is the offset in bytes of the current packet in the JPEG frame data. This value is encoded in network byte order (most significant byte first). The Fragment Offset plus the length of the payload data in the packet MUST NOT exceed 2^24 bytes. Type: 8 bits The type field specifies the information that would otherwise be present in a JPEG abbreviated table-specification as well as the additional JFIF-style parameters not defined by JPEG. Types 0-63 are reserved as fixed, well-known mappings to be defined by this document and future revisions of this document. Types 64-127 are the same as types 0-63, except that restart markers are present in the JPEG data and a Restart Marker header appears immediately following the main JPEG header. Types 128-255 are free to be dynamically defined by a session setup protocol (which is beyond the scope of this document). Q: 8 bits The Q field defines the quantization tables for this frame. Q values 0-127 indicate the quantization tables are computed using an algorithm determined by the Type field (see below). Q values 128-255 indicate that a Quantization Table header appears after the main JPEG header (and the Restart Marker header, if present) in the first packet of the frame (fragment offset 0). This header can be used to explicitly specify the quantization tables in-band. Width: 8 bits This field encodes the width of the image in 8-pixel multiples (e.g., a width of 40 denotes an image 320 pixels wide). The maximum width is 2040 pixels. Height: 8 bits This field encodes the height of the image in 8-pixel multiples (e.g., a height of 30 denotes an image 240 pixels tall). When encoding interlaced video, this is the height of a video field, since fields are individually JPEG encoded. The maximum height is 2040 pixels. */ void Streamer::mjpeg_send_frame(uint8_t* frame, int frame_size) { SBL_MSG(MSG::STREAMER, "MJPEG frame size %d, timestamp %d", frame_size, _timestamp); frame -= RTP_HEADER + MJPEG_HEADER; uint8_t* frame_start = frame; do { bool last_packet = frame_size <= _packet_size; write_rtp_header(frame, last_packet); write_mjpeg_header(frame + RTP_HEADER, frame - frame_start); send_packet(frame, (frame_size < _packet_size ? frame_size : _packet_size) + RTP_HEADER + MJPEG_HEADER, last_packet); frame += _packet_size; frame_size -= _packet_size; } while (frame_size > 0); }