static int ffmpeg_frame_is_sync (codec_data_t *ifptr, uint8_t *buffer, uint32_t buflen, void *userdata) { int ret; int ftype; uint32_t offset; ffmpeg_codec_t *ffmpeg = (ffmpeg_codec_t *)ifptr; switch (ffmpeg->m_codecId) { case CODEC_ID_H264: // look for idr nal do { uint8_t nal_type = h264_nal_unit_type(buffer); if (nal_type == H264_NAL_TYPE_SEQ_PARAM) return 1; //ffmpeg_message(LOG_DEBUG, "ffmpeg", "nal type %u", nal_type); if (h264_nal_unit_type_is_slice(nal_type)) { if (nal_type == H264_NAL_TYPE_IDR_SLICE) return 1; #if 0 uint8_t slice_type; if (h264_find_slice_type(buffer, buflen, &slice_type) >= 0) { return H264_TYPE_IS_I(slice_type) ? 1 : 0; } return 0; #else return 0; #endif } offset = h264_find_next_start_code(buffer, buflen); buffer += offset; buflen -= offset; } while (offset != 0); break; case CODEC_ID_MPEG2VIDEO: // this would be for mpeg2 ret = MP4AV_Mpeg3FindPictHdr(buffer, buflen, &ftype); ffmpeg_message(LOG_ERR, "ffmpeg", "ret %u type %u", ret, ftype); if (ret >= 0 && ftype == 1) { return 1; } break; case CODEC_ID_MPEG4: { uint8_t *vop = MP4AV_Mpeg4FindVop(buffer, buflen); if (vop == NULL) return 0; if (MP4AV_Mpeg4GetVopType(vop, buflen - (vop - buffer)) == VOP_TYPE_I) return 1; } break; default: // for every other, return that it is sync return 1; } return 0; }
static uint8_t h264_get_sample_nal_type (uint8_t *pSampleBuffer, uint32_t sampleSize, uint32_t sizeLength) { uint32_t offset = 0; while (offset < sampleSize) { uint8_t nal_type = pSampleBuffer[sizeLength] & 0x1f; uint32_t add; if (h264_nal_unit_type_is_slice(nal_type)) { return nal_type; } add = h264_get_nal_size(pSampleBuffer, sizeLength) + sizeLength; offset += add; pSampleBuffer += add; } return 0; }
static void ParseH264 (uint8_t *bptr, uint32_t blen, uint32_t len_size, bool dump_off) { uint8_t *fptr = bptr; while (blen > len_size) { uint32_t nal_len = 0; switch (len_size) { case 1: nal_len = *bptr; break; case 2: nal_len = (bptr[0] << 8) | bptr[1]; break; case 3: nal_len = (bptr[0] << 16) | (bptr[1] << 8) | bptr[2]; break; case 4: nal_len = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8) | bptr[3]; break; } bptr += len_size; blen -= len_size; uint8_t nal_type = *bptr & 0x1f; switch (nal_type) { case H264_NAL_TYPE_NON_IDR_SLICE: printf(" NIDR-"); break; case H264_NAL_TYPE_DP_A_SLICE: printf(" DPA-"); break; case H264_NAL_TYPE_DP_B_SLICE: printf(" DPB-"); break; case H264_NAL_TYPE_DP_C_SLICE: printf(" DPC-"); break; case H264_NAL_TYPE_IDR_SLICE: printf(" IDR-"); break; case H264_NAL_TYPE_SEI: printf(" SEI"); break; case H264_NAL_TYPE_SEQ_PARAM: printf(" SEQ"); break; case H264_NAL_TYPE_PIC_PARAM: printf(" PIC"); break; case H264_NAL_TYPE_ACCESS_UNIT: printf(" AU"); break; case H264_NAL_TYPE_END_OF_SEQ: printf(" EOS"); break; case H264_NAL_TYPE_END_OF_STREAM: printf(" EOST"); break; case H264_NAL_TYPE_FILLER_DATA: printf(" FILL"); break; default: printf(" UNK(0x%x)", nal_type); break; } if (h264_nal_unit_type_is_slice(nal_type)) { uint8_t slice_type; h264_find_slice_type(bptr, nal_len, &slice_type, true); printf("%s", h264_get_slice_name(slice_type)); } uint32_t off = bptr - fptr - len_size; if (dump_off) printf("(%u)", off); bptr += nal_len; if (nal_len > blen) { blen = 0; } else blen -= nal_len; } }
bool CX264VideoEncoder::EncodeImage( const u_int8_t* pY, const u_int8_t* pU, const u_int8_t* pV, u_int32_t yStride, u_int32_t uvStride, bool wantKeyFrame, Duration elapsedDuration, Timestamp srcFrameTimestamp) { //debug_message("encoding at "U64, srcFrameTimestamp); m_push->Push(srcFrameTimestamp); if (m_vopBuffer == NULL) { m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize); if (m_vopBuffer == NULL) { error_message("Cannot malloc vop size"); return false; } } m_count++; if (m_count >= m_key_frame_count) { wantKeyFrame = true; m_count = 0; } #ifdef USE_OUR_YUV m_pic_input.img.plane[0] = (uint8_t *)pY; m_pic_input.img.i_stride[0] = yStride; m_pic_input.img.plane[1] = (uint8_t *)pU; m_pic_input.img.i_stride[1] = uvStride; m_pic_input.img.plane[2] = (uint8_t *)pV; m_pic_input.img.i_stride[2] = uvStride; #else CopyYuv(pY, pU, pV, yStride, uvStride, uvStride, m_pic_input.img.plane[0],m_pic_input.img.plane[1],m_pic_input.img.plane[2], m_pic_input.img.i_stride[0],m_pic_input.img.i_stride[1],m_pic_input.img.i_stride[2], Profile()->m_videoWidth, Profile()->m_videoHeight); #endif m_pic_input.i_type = wantKeyFrame ? X264_TYPE_IDR : X264_TYPE_AUTO; m_pic_input.i_pts = srcFrameTimestamp; x264_nal_t *nal; int i_nal; if (x264_encoder_encode(m_h, &nal, &i_nal, &m_pic_input, &m_pic_output) < 0) { error_message("x264_encoder_encode failed"); return false; } CHECK_AND_FREE(m_nal_info); m_nal_info = (h264_nal_buf_t *)malloc(i_nal * sizeof(h264_nal_buf_t)); uint8_t *vopBuffer = m_vopBuffer; int vopBufferLen = m_vopBufferLength; uint32_t loaded = 0; uint32_t nal_on = 0; // read the nals out of the encoder. Nice... for (int ix = 0; ix < i_nal; ix++) { int i_size; bool skip = false; i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]); if (i_size > 0) { m_nal_info[nal_on].nal_length = i_size; m_nal_info[nal_on].nal_offset = loaded; m_nal_info[nal_on].nal_type = nal[ix].i_type; m_nal_info[nal_on].unique = false; uint32_t header = 0; if (h264_is_start_code(vopBuffer)) { header = vopBuffer[2] == 1 ? 3 : 4; } m_nal_info[nal_on].nal_length -= header; m_nal_info[nal_on].nal_offset += header; // we will send picture or sequence header through - let the // sinks decide to send or not if (skip == false) { #ifdef DEBUG_H264 uint8_t nal_type = nal[ix].i_type; if (h264_nal_unit_type_is_slice(nal_type)) { uint8_t stype; h264_find_slice_type(vopBuffer, i_size, &stype, true); debug_message("nal %d - type %u slice type %u %d", ix, nal_type, stype, i_size); } else { debug_message("nal %d - type %u %d", ix, nal_type, i_size); } #endif nal_on++; loaded += i_size; vopBufferLen -= i_size; vopBuffer += i_size; } else { #ifdef DEBUG_H264 debug_message("skipped nal %u", nal[ix].i_type); #endif } } else { error_message("Need to increase vop buffer size by %d", -i_size); } } m_nal_num = nal_on; m_vopBufferLength = loaded; #ifdef DEBUG_H264 debug_message("x264 loaded %d nals, %u len", i_nal, loaded); #endif #ifdef OUTPUT_RAW if (m_vopBufferLength) { fwrite(m_vopBuffer, m_vopBufferLength, 1, m_outfile); } #endif return true; }
static int ffmpeg_decode (codec_data_t *ptr, frame_timestamp_t *pts, int from_rtp, int *sync_frame, uint8_t *buffer, uint32_t buflen, void *ud) { ffmpeg_codec_t *ffmpeg = (ffmpeg_codec_t *)ptr; uint32_t bytes_used = 0; int got_picture = 0; uint64_t ts = pts->msec_timestamp; //ffmpeg_message(LOG_ERR, "ffmpeg", "%u timestamp "U64, buflen, ts); if (ffmpeg->m_codec_opened == false) { // look for header, like above, and open it bool open_codec = true; switch (ffmpeg->m_codecId) { case CODEC_ID_H264: open_codec = ffmpeg_find_h264_size(ffmpeg, buffer, buflen); break; default: break; } if (open_codec) { if (avcodec_open(ffmpeg->m_c, ffmpeg->m_codec) < 0) { ffmpeg_message(LOG_CRIT, "ffmpeg", "failed to open codec"); return buflen; } ffmpeg->m_codec_opened = true; ffmpeg_message(LOG_ERR, "ffmpeg", "opened codec"); } else { ffmpeg_message(LOG_ERR, "ffmpeg", "no open %u "U64, buflen, ts); return buflen; } } // look and see if we have read the I frame. if (ffmpeg->m_got_i == false) { if (ffmpeg_frame_is_sync(ptr, buffer, buflen, NULL) == 0) { return buflen; } ffmpeg->m_got_i = true; } int ret; do { int local_got_picture; ret = avcodec_decode_video(ffmpeg->m_c, ffmpeg->m_picture, &local_got_picture, buffer + bytes_used, buflen - bytes_used); bytes_used += ret; //ffmpeg_message(LOG_CRIT, "ffmpeg", "used %d %d", ret, local_got_picture); got_picture |= local_got_picture; } while (ret != -1 && bytes_used < buflen); if (pts->timestamp_is_pts) { //ffmpeg_message(LOG_ERR, "ffmpeg", "pts timestamp "U64, ts); if (ffmpeg->m_codecId == CODEC_ID_MPEG2VIDEO) { if (ffmpeg->pts_convert.frame_rate == 0.0) { int have_mpeg2; uint32_t h, w; double bitrate, aspect_ratio; uint8_t profile; MP4AV_Mpeg3ParseSeqHdr(buffer, buflen, &have_mpeg2, &h, &w, &ffmpeg->pts_convert.frame_rate, &bitrate, &aspect_ratio, &profile); } int ftype; int header = MP4AV_Mpeg3FindPictHdr(buffer, buflen, &ftype); if (header >= 0) { uint16_t temp_ref = MP4AV_Mpeg3PictHdrTempRef(buffer + header); uint64_t ret; if (got_picture == 0 || mpeg3_find_dts_from_pts(&ffmpeg->pts_convert, ts, ftype, temp_ref, &ret) < 0) { ffmpeg->have_cached_ts = false; return buflen; } #if 0 ffmpeg->m_vft->log_msg(LOG_DEBUG, "ffmpeg", "pts "U64" dts "U64" temp %u type %u %u", ts, ret, temp_ref, ftype, got_picture); #endif ts = ret; // ffmpeg_message(LOG_ERR, "ffmpeg", "type %d ref %u "U64, ftype, temp_ref, ret); } } else if (ffmpeg->m_codecId == CODEC_ID_MPEG4) { uint8_t *vopstart = MP4AV_Mpeg4FindVop(buffer, buflen); if (vopstart) { int ftype = MP4AV_Mpeg4GetVopType(vopstart, buflen); uint64_t dts; if (MP4AV_calculate_dts_from_pts(&ffmpeg->pts_to_dts, ts, ftype, &dts) < 0) { ffmpeg->have_cached_ts = false; #ifdef DEBUG_FFMPEG_PTS ffmpeg_message(LOG_DEBUG, "ffmpeg", "type %d %d pts "U64" failed to calc", ftype, got_picture, ts); #endif return buflen; } #ifdef DEBUG_FFMPEG_PTS ffmpeg_message(LOG_DEBUG, "ffmpeg", "type %d %d pts "U64" dts "U64, ftype, got_picture, ts, dts); #endif ts = dts; } } else if (ffmpeg->m_codecId == CODEC_ID_H264) { uint8_t *nal_ptr = buffer; uint32_t len = buflen; bool have_b_nal = false; do { if (h264_nal_unit_type_is_slice(h264_nal_unit_type(nal_ptr))) { uint8_t slice_type; if (h264_find_slice_type(nal_ptr, len, &slice_type, false) >= 0) { have_b_nal = H264_TYPE_IS_B(slice_type); } } uint32_t offset = h264_find_next_start_code(nal_ptr, len); if (offset == 0) { len = 0; } else { nal_ptr += offset; len -= offset; } } while (len > 0 && have_b_nal == false); uint64_t dts; if (MP4AV_calculate_dts_from_pts(&ffmpeg->pts_to_dts, ts, have_b_nal ? VOP_TYPE_B : VOP_TYPE_P, &dts) < 0) { ffmpeg->have_cached_ts = false; #ifdef DEBUG_FFMPEG_PTS ffmpeg_message(LOG_DEBUG, "ffmpeg", "pts "U64" failed to calc", ts); #endif return buflen; } ts = dts; } } if (got_picture != 0) { if (ffmpeg->m_video_initialized == false) { double aspect; if (ffmpeg->m_c->sample_aspect_ratio.den == 0) { aspect = 0.0; // don't have one } else { aspect = av_q2d(ffmpeg->m_c->sample_aspect_ratio); } if (ffmpeg->m_c->width == 0) { return buflen; } ffmpeg->m_vft->video_configure(ffmpeg->m_ifptr, ffmpeg->m_c->width, ffmpeg->m_c->height, VIDEO_FORMAT_YUV, aspect); ffmpeg->m_video_initialized = true; } if (ffmpeg->m_c->pix_fmt != PIX_FMT_YUV420P) { // convert the image from whatever it is to YUV 4:2:0 AVPicture from, to; int ret; // get the buffer to copy into (put it right into the ring buffer) ret = ffmpeg->m_vft->video_get_buffer(ffmpeg->m_ifptr, &to.data[0], &to.data[1], &to.data[2]); if (ret == 0) { return buflen; } // set up the AVPicture structures to.linesize[0] = ffmpeg->m_c->width; to.linesize[1] = ffmpeg->m_c->width / 2; to.linesize[2] = ffmpeg->m_c->width / 2; for (int ix = 0; ix < 4; ix++) { from.data[ix] = ffmpeg->m_picture->data[ix]; from.linesize[ix] = ffmpeg->m_picture->linesize[ix]; } img_convert(&to, PIX_FMT_YUV420P, &from, ffmpeg->m_c->pix_fmt, ffmpeg->m_c->width, ffmpeg->m_c->height); ffmpeg->m_vft->video_filled_buffer(ffmpeg->m_ifptr, ffmpeg->have_cached_ts ? ffmpeg->cached_ts : ts); } else { ffmpeg->m_vft->video_have_frame(ffmpeg->m_ifptr, ffmpeg->m_picture->data[0], ffmpeg->m_picture->data[1], ffmpeg->m_picture->data[2], ffmpeg->m_picture->linesize[0], ffmpeg->m_picture->linesize[1], ffmpeg->have_cached_ts ? ffmpeg->cached_ts : ts); } ffmpeg->cached_ts = ts; } else { ffmpeg->cached_ts = ts; ffmpeg->have_cached_ts = true; } #ifdef DEBUG_FFMPEG_FRAME ffmpeg_message(LOG_DEBUG, "ffmpeg", "used %u of %u", bytes_used, buflen); #endif return (buflen); }