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); }
static int mpeg2dec_decode (codec_data_t *ptr, frame_timestamp_t *pts, int from_rtp, int *sync_frame, uint8_t *buffer, uint32_t buflen, void *ud) { mpeg2dec_codec_t *mpeg2dec = (mpeg2dec_codec_t *)ptr; mpeg2dec_t *decoder; const mpeg2_info_t *info; mpeg2_state_t state; uint64_t ts = pts->msec_timestamp; decoder = mpeg2dec->m_decoder; #if 0 mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "ts buflen %d "U64, buflen, ts); //if (mpeg2dec->m_did_pause != 0) { for (uint32_t ix = 0; ix < buflen + 3; ix++) { if (buffer[ix] == 0 && buffer[ix + 1] == 0 && buffer[ix + 2] == 1) { mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "index %d - value %x %x %x", ix, buffer[ix + 3], buffer[ix + 4], buffer[ix + 5]); } } } #endif info = mpeg2_info(decoder); bool passed_buffer = false; bool finished_buffer = false; do { state = mpeg2_parse(decoder); //mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "state %d", state); const mpeg2_sequence_t *sequence; sequence = info->sequence; switch (state) { case STATE_BUFFER: if (passed_buffer == false) { mpeg2_buffer(decoder, buffer, buffer + buflen); passed_buffer = true; } else { finished_buffer = true; } break; case STATE_SEQUENCE: { if (mpeg2dec->m_video_initialized == 0) { mpeg2dec->m_h = sequence->height; mpeg2dec->m_w = sequence->width; int have_mpeg2; uint32_t height; uint32_t width; double frame_rate; double bitrate; double aspect_ratio; uint8_t profile; if (MP4AV_Mpeg3ParseSeqHdr(buffer, buflen, &have_mpeg2, &height, &width, &frame_rate, &bitrate, &aspect_ratio, &profile) < 0) { mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "pix w %u pix h %u", sequence->pixel_width, sequence->pixel_height); aspect_ratio = sequence->pixel_width; aspect_ratio *= mpeg2dec->m_w; aspect_ratio /= (double)(sequence->pixel_height * mpeg2dec->m_h); } mpeg2dec->pts_convert.frame_rate = frame_rate; mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "%ux%u aspect %g", mpeg2dec->m_w, mpeg2dec->m_h, aspect_ratio); mpeg2dec->m_vft->video_configure(mpeg2dec->m_ifptr, mpeg2dec->m_w, mpeg2dec->m_h, VIDEO_FORMAT_YUV, aspect_ratio); mpeg2dec->m_video_initialized = 1; } break; } case STATE_SLICE: case STATE_END: case STATE_INVALID_END: // INVALID_END state means they found a new sequence header, with a // new size #ifdef DEBUG_MPEG2DEC_FRAME mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "frame "U64" decoded", mpeg2dec->cached_ts); #endif if (info->display_fbuf) { mpeg2dec->m_vft->video_have_frame(mpeg2dec->m_ifptr, info->display_fbuf->buf[0], info->display_fbuf->buf[1], info->display_fbuf->buf[2], sequence->width, sequence->chroma_width, mpeg2dec->m_cached_ts_invalid ? ts : mpeg2dec->cached_ts); } break; case STATE_SEQUENCE_REPEATED: // we don't care here case STATE_GOP: case STATE_PICTURE: case STATE_SLICE_1ST: case STATE_PICTURE_2ND: case STATE_INVALID: // default: break; } } while (finished_buffer == false); mpeg2dec->m_cached_ts_invalid = false; if (pts->timestamp_is_pts) { if (info->current_picture == NULL || mpeg3_find_dts_from_pts(&mpeg2dec->pts_convert, ts, info->current_picture->flags & PIC_MASK_CODING_TYPE, info->current_picture->temporal_reference, &mpeg2dec->cached_ts) < 0) { mpeg2dec->m_cached_ts_invalid = true; } #if 0 mpeg2dec->m_vft->log_msg(LOG_DEBUG, "mpeg2dec", "pts "U64" dts "U64" temp %u type %u", pts->msec_timestamp, mpeg2dec->cached_ts, info->current_picture->temporal_reference, info->current_picture->flags & PIC_MASK_CODING_TYPE); #endif } else { mpeg2dec->cached_ts = ts; } return (buflen); }