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 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 iso_decode (codec_data_t *ptr, frame_timestamp_t *ts, int from_rtp, int *sync_frame, uint8_t *buffer, uint32_t buflen, void *userdata) { Int iEof = 1; iso_decode_t *iso = (iso_decode_t *)ptr; uint32_t used = 0; if (buflen <= 4) return -1; // iso_message(LOG_DEBUG, "iso", "frame %d", iso->m_total_frames); iso->m_total_frames++; buffer[buflen] = 0; buffer[buflen + 1] = 0; buffer[buflen + 2] = 1; switch (iso->m_decodeState) { case DECODE_STATE_VOL_SEARCH: { if (buffer[0] == 0 && buffer[1] == 0 && (buffer[2] & 0xfc) == 0x80 && (buffer[3] & 0x03) == 0x02) { // we have the short header iso->m_short_header = 1; iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)buffer, buflen); iso->m_pvodec->video_plane_with_short_header(); iso->m_pvodec->postVO_VOLHeadInit(iso->m_pvodec->getWidth(), iso->m_pvodec->getHeight(), &iso->m_bSpatialScalability); iso_message(LOG_INFO, mp4iso, "Decoding using short headers"); iso->m_vft->video_configure(iso->m_ifptr, iso->m_pvodec->getWidth(), iso->m_pvodec->getHeight(), VIDEO_FORMAT_YUV, calculate_aspect_ratio(iso)); iso->m_decodeState = DECODE_STATE_NORMAL; try { iEof = iso->m_pvodec->h263_decode(FALSE); } catch (...) { iso_message(LOG_ERR, mp4iso, "Couldn't decode h263 in vol search"); } break; } else { uint8_t *volhdr = MP4AV_Mpeg4FindVol(buffer, buflen); if (volhdr != NULL) { used = volhdr - buffer; try { iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)volhdr, buflen - used); iso->m_pvodec->decodeVOLHead(); iso->m_pvodec->postVO_VOLHeadInit(iso->m_pvodec->getWidth(), iso->m_pvodec->getHeight(), &iso->m_bSpatialScalability); iso_message(LOG_INFO, mp4iso, "Found VOL"); iso->m_vft->video_configure(iso->m_ifptr, iso->m_pvodec->getWidth(), iso->m_pvodec->getHeight(), VIDEO_FORMAT_YUV, calculate_aspect_ratio(iso)); iso->m_decodeState = DECODE_STATE_WAIT_I; used += iso->m_pvodec->get_used_bytes(); } catch (int err) { iso_message(LOG_DEBUG, mp4iso, "Caught exception in VOL search %d", err); if (err == 1) used = buflen; else used += iso->m_pvodec->get_used_bytes(); } } } if (iso->m_decodeState != DECODE_STATE_WAIT_I) { if (iso->m_vinfo != NULL) { iso->m_pvodec->FakeOutVOVOLHead(iso->m_vinfo->height, iso->m_vinfo->width, 30, &iso->m_bSpatialScalability); iso->m_vft->video_configure(iso->m_ifptr, iso->m_vinfo->width, iso->m_vinfo->height, VIDEO_FORMAT_YUV, calculate_aspect_ratio(iso)); iso->m_decodeState = DECODE_STATE_NORMAL; } return used; } // else fall through } case DECODE_STATE_WAIT_I: { uint8_t *vophdr = MP4AV_Mpeg4FindVop(buffer, buflen); if (vophdr != NULL) { used = vophdr - buffer; } iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)buffer + used, buflen + 3 - used); try { iEof = iso->m_pvodec->decode(NULL, TRUE); if (iEof == -1) { iso->m_num_wait_i_frames++; return(iso->m_pvodec->get_used_bytes()); } iso_message(LOG_DEBUG, mp4iso, "Back to normal decode"); iso->m_decodeState = DECODE_STATE_NORMAL; iso->m_bCachedRefFrame = FALSE; iso->m_bCachedRefFrameCoded = FALSE; iso->m_cached_valid = FALSE; iso->m_cached_time = 0; } catch (int err) { if (err != 1) iso_message(LOG_DEBUG, mp4iso, "ts "U64",Caught exception in wait_i %d", ts->msec_timestamp, err); return (iso->m_pvodec->get_used_bytes()); //return (-1); } break; } case DECODE_STATE_NORMAL: try { if (iso->m_short_header != 0) { iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)buffer, buflen + 3); iEof = iso->m_pvodec->h263_decode(TRUE); } else { uint8_t *vophdr = MP4AV_Mpeg4FindVop(buffer, buflen); if (vophdr != NULL && vophdr != buffer) { iso_message(LOG_DEBUG, mp4iso, "Illegal code before VOP header"); used = vophdr - buffer; buflen -= used; buffer = vophdr; } iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)buffer, buflen + 3); iEof = iso->m_pvodec->decode(NULL, FALSE, FALSE); } } catch (int err) { // This is because sometimes, the encoder doesn't read all the bytes // it should out of the rtp packet. The rtp bytestream does a read // and determines that we're trying to read across bytestreams. // If we get this, we don't want to change anything - just fall up // to the decoder thread so it gives us a new timestamp. if (err == 1) { // throw from running past end of frame return -1; } iso_message(LOG_DEBUG, mp4iso, "Mpeg4 ncaught %d -> waiting for I", err); iso->m_decodeState = DECODE_STATE_WAIT_I; return (iso->m_pvodec->get_used_bytes()); } catch (...) { iso_message(LOG_DEBUG, mp4iso, "Mpeg4 ncaught -> waiting for I"); iso->m_decodeState = DECODE_STATE_WAIT_I; //return (-1); return (iso->m_pvodec->get_used_bytes()); } break; } /* * We've got a good frame. See if we need to display it */ const CVOPU8YUVBA *pvopcQuant = NULL; if (iso->m_pvodec->fSptUsage() == 1) { //player_debug_message("Sprite"); } uint64_t displaytime = 0; int cached_ts = 0; if (iEof == EOF) { if (iso->m_bCachedRefFrame) { iso->m_bCachedRefFrame = FALSE; if (iso->m_bCachedRefFrameCoded) { pvopcQuant = iso->m_pvodec->pvopcRefQLater(); displaytime = ts->msec_timestamp; } } } else { #if 0 iso_message(LOG_DEBUG, mp4iso, "frame "U64" type %d", ts->msec_timestamp, iso->m_pvodec->vopmd().vopPredType); #endif if (iso->m_pvodec->vopmd().vopPredType == BVOP) { if (iEof != FALSE) { pvopcQuant = iso->m_pvodec->pvopcReconCurr(); displaytime = ts->msec_timestamp; } } else { if (iso->m_bCachedRefFrame) { iso->m_bCachedRefFrame = FALSE; if (iso->m_bCachedRefFrameCoded) { pvopcQuant = iso->m_pvodec->pvopcRefQPrev(); if (ts->timestamp_is_pts) { int old_was_valid = iso->m_cached_valid; displaytime = iso->m_cached_time; cached_ts = 1; // old time stamp wasn't valid - instead of calculating it // ourselves, just punt on it. if (old_was_valid == 0) { return (iEof == EOF ? -1 : 0); } } else { displaytime = ts->msec_timestamp; } } } iso->m_cached_time = ts->msec_timestamp; iso->m_cached_valid = TRUE; iso->m_bCachedRefFrame = TRUE; iso->m_bCachedRefFrameCoded = (iEof != FALSE); } } if (pvopcQuant != NULL) { #if 0 player_debug_message("frame rtp_ts "U64" disp "U64" cached %d", ts->msec_timestamp, displaytime, cached_ts); #endif /* * Get the information to the video sync structure */ const uint8_t *y, *u, *v; int pixelw_y, pixelw_uv; pixelw_y = pvopcQuant->getPlane(Y_PLANE)->where().width; pixelw_uv = pvopcQuant->getPlane(U_PLANE)->where().width; y = (const uint8_t *)pvopcQuant->getPlane(Y_PLANE)->pixels(0,0); u = (const uint8_t *)pvopcQuant->getPlane(U_PLANE)->pixels(0,0); v = (const uint8_t *)pvopcQuant->getPlane(V_PLANE)->pixels(0,0); iso->m_last_time = displaytime; #if 0 player_debug_message("Adding video at "U64" %d", displaytime, iso->m_pvodec->vopmd().vopPredType); #endif iso->m_vft->video_have_frame(iso->m_ifptr, y, u, v, pixelw_y, pixelw_uv, displaytime); } else { iso_message(LOG_DEBUG, mp4iso, "decode but no frame "U64, ts->msec_timestamp); } return (iso->m_pvodec->get_used_bytes() + used); }
static int xvid_decode (codec_data_t *ptr, frame_timestamp_t *pts, int from_rtp, int *sync_frame, uint8_t *buffer, uint32_t blen, void *ud) { int ret; xvid_codec_t *xvid = (xvid_codec_t *)ptr; uint64_t ts = pts->msec_timestamp; int buflen = blen, used = 0; uint8_t *vop = MP4AV_Mpeg4FindVop(buffer, blen); int type = 0; if (vop != NULL) { type = MP4AV_Mpeg4GetVopType(vop, blen); uint64_t dts; if (MP4AV_calculate_dts_from_pts(&xvid->pts_to_dts, ts, type, &dts) < 0) { return buflen; } ts = dts; } #if 0 xvid_message(LOG_DEBUG, "xvidif", "%u at %llu %d", blen, ts, type); #endif if (xvid->m_decodeState == XVID_STATE_VO_SEARCH) { ret = look_for_vol(xvid, buffer, buflen); if (ret < 0) { return buflen; } xvid->m_decodeState = XVID_STATE_NORMAL; } xvid_dec_frame_t dec; xvid_dec_stats_t stats; do { memset(&dec, 0, sizeof(dec)); memset(&stats, 0, sizeof(dec)); dec.version = XVID_VERSION; dec.bitstream = buffer; dec.length = buflen; dec.general = 0; dec.output.csp = XVID_CSP_INTERNAL; stats.version = XVID_VERSION; ret = xvid_decore(xvid->m_xvid_handle, XVID_DEC_DECODE, &dec, &stats); #if 0 xvid_message(LOG_DEBUG, "xvidif", "ret %d type %d blen %d of %u", ret, stats.type, buflen, blen); #endif if (ret < 0 || ret > buflen) { buflen = 0; used = blen; } else { buflen -= ret; buffer += ret; used += ret; } // we could check for vol changes, etc here, if we wanted. } while (buflen > 4 && stats.type <= 0); if (stats.type > 0) { xvid->m_vft->video_have_frame(xvid->m_ifptr, (const uint8_t *)dec.output.plane[0], (const uint8_t *)dec.output.plane[1], (const uint8_t *)dec.output.plane[2], dec.output.stride[0], dec.output.stride[1], ts); } #if 0 xvid->m_vft->log_msg(LOG_DEBUG, "xvid", "error returned %d", ret); #endif xvid->m_total_frames++; return (used); }