📄 video_encoder_base.cpp
字号:
static void Mpeg2SendVideo (CMediaFrame *pFrame, CRtpDestination *list, uint32_t rtpTimestamp, uint16_t maxPayloadSize){ uint8_t rfc2250[4], rfc2250_2; uint32_t sampleSize; uint8_t *pData, *pbuffer; uint32_t scode; int have_seq; bool stop; uint32_t offset; uint8_t *pstart; uint8_t type; uint32_t next_slice, prev_slice; bool slice_at_begin; CRtpDestination *rdptr; pData = (uint8_t *)pFrame->GetData(); sampleSize = pFrame->GetDataLength(); offset = 0; have_seq = 0; pbuffer = pData; stop = false; do { uint32_t oldoffset; oldoffset = offset; if (MP4AV_Mpeg3FindNextStart(pData + offset, sampleSize - offset, &offset, &scode) < 0) { // didn't find the start code#ifdef DEBUG_MPEG3_HINT printf("didn't find start code\n");#endif stop = true; } else { offset += oldoffset;#ifdef DEBUG_MPEG3_HINT printf("next sscode %x found at %d\n", scode, offset);#endif if (scode == MPEG3_SEQUENCE_START_CODE) have_seq = 1; offset += 4; // start with next value } } while (scode != MPEG3_PICTURE_START_CODE && stop == false); pstart = pbuffer + offset; // point to inside of picture start type = (pstart[1] >> 3) & 0x7; rfc2250[0] = (*pstart >> 6) & 0x3; rfc2250[1] = (pstart[0] << 2) | ((pstart[1] >> 6) & 0x3); // temporal ref rfc2250[2] = type; rfc2250_2 = rfc2250[2]; rfc2250[3] = 0; if (type == 2 || type == 3) { rfc2250[3] = pstart[3] << 5; if ((pstart[4] & 0x80) != 0) rfc2250[3] |= 0x10; if (type == 3) { rfc2250[3] |= (pstart[4] >> 3) & 0xf; } } prev_slice = 0; if (MP4AV_Mpeg3FindNextSliceStart(pbuffer, offset, sampleSize, &next_slice) < 0) { slice_at_begin = false; } else { slice_at_begin = true; } offset = 0; bool nomoreslices = false; bool found_slice = slice_at_begin; bool onfirst = true; maxPayloadSize -= sizeof(rfc2250); // make sure we have room while (sampleSize > 0) { bool isLastPacket; uint32_t len_to_write; if (sampleSize <= maxPayloadSize) { // leave started_slice alone len_to_write = sampleSize; isLastPacket = true; prev_slice = 0; } else { found_slice = (onfirst == false) && (nomoreslices == false) && (next_slice <= maxPayloadSize); onfirst = false; isLastPacket = false; while (nomoreslices == false && next_slice <= maxPayloadSize) { prev_slice = next_slice; if (MP4AV_Mpeg3FindNextSliceStart(pbuffer, next_slice + 4, sampleSize, &next_slice) >= 0) {#ifdef DEBUG_MPEG3_HINT printf("prev_slice %u next slice %u %u\n", prev_slice, next_slice, offset + next_slice);#endif found_slice = true; } else { // at end nomoreslices = true; } } // prev_slice should have the end value. If it's not 0, we have // the end of the slice. if (found_slice) len_to_write = prev_slice; else len_to_write = MIN(maxPayloadSize, sampleSize); } rfc2250[2] = rfc2250_2; if (have_seq != 0) { rfc2250[2] |= 0x20; have_seq = 0; } if (slice_at_begin) { rfc2250[2] |= 0x10; // set b bit } if (found_slice || isLastPacket) { rfc2250[2] |= 0x08; // set end of slice bit slice_at_begin = true; // for next time } else { slice_at_begin = false; } struct iovec iov[2]; iov[0].iov_base = rfc2250; iov[0].iov_len = sizeof(rfc2250); iov[1].iov_base = pData + offset; iov[1].iov_len = len_to_write; rdptr = list; while (rdptr != NULL) { int rc = rdptr->send_iov(iov, 2, rtpTimestamp, len_to_write >= sampleSize ? 1 : 0); rc -= sizeof(rtp_packet_header); rc -= sizeof(rfc2250); if (rc != (int)len_to_write) { error_message("send_iov error - returned %d %d", rc, len_to_write); } rdptr = rdptr->get_next(); } offset += len_to_write; sampleSize -= len_to_write; prev_slice = 0; next_slice -= len_to_write; pbuffer += len_to_write; } if (pFrame->RemoveReference()) delete pFrame;}// we're going to assume that we get complete frames here...static void H263SendVideoRfc2429 (CMediaFrame *pFrame, CRtpDestination *list, uint32_t rtpTimestamp, uint16_t mtu){ struct iovec iov[2]; uint8_t* pBuf = (uint8_t*)pFrame->GetData(); uint32_t dataLength = pFrame->GetDataLength(); uint8_t mode_header[2]; bool first = true; uint32_t tosend; if (pBuf[0] == 0 && pBuf[1] == 0 && (pBuf[2] & 0xfc) == 0x80) { first = true; } else { first = false; } mtu -= 2; // subtract off header. while (dataLength > 0) { if (first) { pBuf += 2; dataLength -= 2; mode_header[0] = 0x4; first = false; } else mode_header[0] = 0; mode_header[1] = 0; iov[0].iov_base = mode_header; iov[0].iov_len = 2; tosend = MIN(mtu, dataLength); iov[1].iov_base = pBuf; iov[1].iov_len = tosend; pBuf += tosend; dataLength -= tosend; //error_message("sending %d", iov[1].iov_len); CRtpDestination *rdptr = list; while (rdptr != NULL) { rdptr->send_iov(iov, 2, rtpTimestamp, dataLength > 0 ? 0 : 1); rdptr = rdptr->get_next(); } } if (pFrame->RemoveReference()) delete pFrame;}/* * H264SendVideo - send h264 video according to rfc proposal */static void H264SendVideo (CMediaFrame *pFrame, CRtpDestination *list, uint32_t rtpTimestamp, uint16_t mtu){ h264_media_frame_t *mf = (h264_media_frame_t *)pFrame->GetData(); uint32_t nal_on = 0; struct iovec iov[32]; //#define DEBUG_H264_TX 1#ifdef DEBUG_H264_TX debug_message("send h264 - %u nals", mf->nal_number);#endif while (nal_on < mf->nal_number) { uint32_t nal_len = mf->nal_bufs[nal_on].nal_length; const uint8_t *nal_ptr = mf->buffer + mf->nal_bufs[nal_on].nal_offset; /* * We have 3 types of packets we can send: * fragmentation units - if the NAL is > mtu * single nal units - if the NAL is < mtu, and can only fit 1 NAL * single time aggregation units - if we can put multiple NALs * * We don't send multiple time aggregation units */ bool have_non_unique_seq_or_pic;#if 1 have_non_unique_seq_or_pic = (mf->nal_bufs[nal_on].unique == false && (mf->nal_bufs[nal_on].nal_type == H264_NAL_TYPE_SEQ_PARAM || mf->nal_bufs[nal_on].nal_type == H264_NAL_TYPE_PIC_PARAM));#else have_non_unique_seq_or_pic = false;#endif if (have_non_unique_seq_or_pic) { nal_on++; } else if (nal_len > mtu) { // fragmentation unit - break up into mtu size chunks#ifdef DEBUG_H264_TX debug_message("%u fu %u", nal_on, nal_len);#endif uint8_t header[2], head; header[0] = (*nal_ptr & 0x60) | 28; header[1] = 0x80; // s indication head = *nal_ptr & 0x1f; nal_ptr++; // remove the first byte nal_len--; // increment nal_on, so we can compare against mf->nal_number for end // of buffer nal_on++; while (nal_len > 0) { uint32_t write_size; bool last = false; header[1] |= head; if ((nal_len + 2) <= mtu) { header[1] |= 0x40; write_size = nal_len; last = true; } else { write_size = mtu - 2; } iov[0].iov_base = header; iov[0].iov_len = 2; iov[1].iov_base = (void *)nal_ptr; iov[1].iov_len = write_size; // send#ifdef DEBUG_H264_TX debug_message("frag %u %u %02x %02x", write_size, (last && nal_on >= mf->nal_number) ? 1 : 0, header[0], header[1]);#endif CRtpDestination *rdptr = list; while (rdptr != NULL) { rdptr->send_iov(iov, 2, rtpTimestamp, (last && nal_on >= mf->nal_number) ? 1 : 0); rdptr = rdptr->get_next(); } header[1] = 0; nal_ptr += write_size; nal_len -= write_size; } // end while (nal_len > 0) } else if (((nal_on + 1) >= mf->nal_number) || ((nal_len + mf->nal_bufs[nal_on].nal_length + 5) > mtu)) { // single nal unit packet iov[0].iov_base = (void *)nal_ptr; iov[0].iov_len = nal_len; nal_on++; // needs to be before, so we trigger on M bit setting#ifdef DEBUG_H264_TX debug_message("%u snup %u %u", nal_on, nal_len, nal_on >= mf->nal_number ? 1 : 0);#endif CRtpDestination *rdptr = list; while (rdptr != NULL) { rdptr->send_iov(iov, 1, rtpTimestamp, nal_on >= mf->nal_number ? 1 : 0); rdptr = rdptr->get_next(); } } else { // single time aggregation packet (stap) - first check how // many nals we want to put into the packet uint32_t nal_check = nal_on; uint32_t size = 1; do { size += 2 + mf->nal_bufs[nal_check].nal_length; nal_check++; } while (nal_check < mf->nal_number && size < mtu);#ifdef DEBUG_H264_TX debug_message("nal on %u check %u size %u", nal_on, nal_check, size);#endif if (size > mtu) nal_check--; if (nal_check - nal_on > 15) { // so we fit in iov nal_check = nal_on + 15; } uint8_t stap = 24; uint8_t max_nri = 0; // first, put the stap header iov[0].iov_base = &stap; iov[0].iov_len = 1; uint8_t lens[30]; uint32_t iov_on = 1; uint len_on = 0; while (nal_on < nal_check) { nal_len = mf->nal_bufs[nal_on].nal_length; nal_ptr = mf->buffer + mf->nal_bufs[nal_on].nal_offset; // ready the length lens[len_on] = nal_len >> 8; lens[len_on + 1] = nal_len & 0xff; iov[iov_on].iov_base = &lens[len_on]; len_on += 2; iov[iov_on].iov_len = 2; iov_on++; // then store the nal iov[iov_on].iov_base = (void *)nal_ptr; iov[iov_on].iov_len = nal_len; if ((*nal_ptr & 0x60) > max_nri) max_nri = *nal_ptr & 0x60;#ifdef DEBUG_H264_TX debug_message("%u stap %u", nal_on, nal_len);#endif nal_on++; iov_on++; } // set the nri value in the stap header stap |= max_nri;#ifdef DEBUG_H264_TX debug_message("stap %u %u", iov_on, nal_on >= mf->nal_number ? 1 : 0);#endif // send the packet CRtpDestination *rdptr = list; while (rdptr != NULL) { rdptr->send_iov(iov, iov_on, rtpTimestamp, nal_on >= mf->nal_number ? 1 : 0); rdptr = rdptr->get_next(); } } } if (pFrame->RemoveReference()) delete pFrame;}static void DummySendVideo (CMediaFrame *pFrame, CRtpDestination *list, uint32_t rtpTimestamp, uint16_t mtu){ if (pFrame->RemoveReference()) delete pFrame;} rtp_transmitter_f GetVideoRtpTransmitRoutineBase(CVideoProfile *pConfig, MediaType *pType, uint8_t *pPayload){ const char *encodingName = pConfig->GetStringValue(CFG_VIDEO_ENCODING); if (!strcasecmp(encodingName, VIDEO_ENCODING_MPEG4)) { *pType = MPEG4VIDEOFRAME; *pPayload = 96; return Mpeg43016SendVideo; } else if (strcasecmp(encodingName, VIDEO_ENCODING_H261) == 0) { *pPayload = 31; *pType = H261VIDEOFRAME; return H261SendVideo; } else if (strcasecmp(encodingName, VIDEO_ENCODING_MPEG2) == 0) { *pPayload =32; *pType = MPEG2VIDEOFRAME; return Mpeg2SendVideo; } else if (strcasecmp(encodingName, VIDEO_ENCODING_H263) == 0) { *pPayload = 96; *pType = H263VIDEOFRAME; return H263SendVideoRfc2429; } else if (strcasecmp(encodingName, VIDEO_ENCODING_H264) == 0) { *pPayload = 96; *pType = H264VIDEOFRAME; return H264SendVideo; } return DummySendVideo;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -