static codec_data_t *ffmpeg_create (const char *stream_type, const char *compressor, int type, int profile, format_list_t *media_fmt, video_info_t *vinfo, const uint8_t *userdata, uint32_t ud_size, video_vft_t *vft, void *ifptr) { ffmpeg_codec_t *ffmpeg; ffmpeg = MALLOC_STRUCTURE(ffmpeg_codec_t); memset(ffmpeg, 0, sizeof(*ffmpeg)); ffmpeg->m_vft = vft; ffmpeg->m_ifptr = ifptr; avcodec_init(); avcodec_register_all(); av_log_set_level(AV_LOG_QUIET); ffmpeg->m_codecId = ffmpeg_find_codec(stream_type, compressor, type, profile, media_fmt, userdata, ud_size); // must have a codecID - we checked it earlier ffmpeg->m_codec = avcodec_find_decoder(ffmpeg->m_codecId); ffmpeg->m_c = avcodec_alloc_context(); ffmpeg->m_picture = avcodec_alloc_frame(); bool open_codec = true; bool run_userdata = false; bool free_userdata = false; switch (ffmpeg->m_codecId) { case CODEC_ID_MJPEG: break; case CODEC_ID_H264: // need to find height and width if (media_fmt != NULL && media_fmt->fmt_param != NULL) { userdata = h264_sdp_parse_sprop_param_sets(media_fmt->fmt_param, &ud_size, ffmpeg->m_vft->log_msg); if (userdata != NULL) free_userdata = true; ffmpeg_message(LOG_DEBUG, "ffmpeg", "sprop len %d", ud_size); } if (ud_size > 0) { ffmpeg_message(LOG_DEBUG, "ffmpeg", "userdata len %d", ud_size); open_codec = ffmpeg_find_h264_size(ffmpeg, userdata, ud_size); ffmpeg_message(LOG_DEBUG, "ffmpeg", "open codec is %d", open_codec); run_userdata = true; } else { open_codec = false; } break; case CODEC_ID_MPEG4: { fmtp_parse_t *fmtp = NULL; open_codec = false; if (media_fmt != NULL) { fmtp = parse_fmtp_for_mpeg4(media_fmt->fmt_param, ffmpeg->m_vft->log_msg); if (fmtp->config_binary != NULL) { userdata = fmtp->config_binary; ud_size = fmtp->config_binary_len; fmtp->config_binary = NULL; free_userdata = true; } } if (ud_size > 0) { uint8_t *vol = MP4AV_Mpeg4FindVol((uint8_t *)userdata, ud_size); u_int8_t TimeBits; u_int16_t TimeTicks; u_int16_t FrameDuration; u_int16_t FrameWidth; u_int16_t FrameHeight; u_int8_t aspectRatioDefine; u_int8_t aspectRatioWidth; u_int8_t aspectRatioHeight; if (vol) { if (MP4AV_Mpeg4ParseVol(vol, ud_size - (vol - userdata), &TimeBits, &TimeTicks, &FrameDuration, &FrameWidth, &FrameHeight, &aspectRatioDefine, &aspectRatioWidth, &aspectRatioHeight)) { ffmpeg->m_c->width = FrameWidth; ffmpeg->m_c->height = FrameHeight; open_codec = true; run_userdata = true; } } } if (fmtp != NULL) { free_fmtp_parse(fmtp); } } break; case CODEC_ID_SVQ3: ffmpeg->m_c->extradata = (void *)userdata; ffmpeg->m_c->extradata_size = ud_size; if (vinfo != NULL) { ffmpeg->m_c->width = vinfo->width; ffmpeg->m_c->height = vinfo->height; } 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 NULL; } ffmpeg_message(LOG_DEBUG, "ffmpeg", "pixel format is %d", ffmpeg->m_c->pix_fmt); ffmpeg->m_codec_opened = true; if (run_userdata) { uint32_t offset = 0; do { int got_picture; offset += avcodec_decode_video(ffmpeg->m_c, ffmpeg->m_picture, &got_picture, (uint8_t *)userdata + offset, ud_size - offset); } while (offset < ud_size); } } if (free_userdata) { CHECK_AND_FREE(userdata); } ffmpeg->m_did_pause = 1; return ((codec_data_t *)ffmpeg); }
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_codec_check (lib_message_func_t message, const char *compressor, int type, int profile, format_list_t *fptr, const uint8_t *userdata, uint32_t userdata_size, CConfigSet *pConfig) { int retval; retval = 3; if (compressor != NULL && (strcasecmp(compressor, "MP4 FILE") == 0)) { if ((type == MP4_MPEG4_VIDEO_TYPE) && ((profile >= MPEG4_SP_L1 && profile <= MPEG4_SP_L3) || (profile == MPEG4_SP_L0))) { return retval; } return -1; } if (fptr != NULL) { // find format. If matches, call parse_fmtp_for_mpeg4, look at // profile level. if (fptr->rtpmap != NULL && fptr->rtpmap->encode_name != NULL) { if (strcasecmp(fptr->rtpmap->encode_name, "MP4V-ES") == 0) { fmtp_parse_t *fmtp; media_desc_t *mptr = fptr->media; if (find_unparsed_a_value(mptr->unparsed_a_lines, "a=x-mpeg4-simple-profile-decoder") != NULL) { // our own special code for simple profile decoder return retval; } fmtp = parse_fmtp_for_mpeg4(fptr->fmt_param, message); int retvl = -1; if (fmtp != NULL) { int profile = fmtp->profile_level_id; if ((profile >= MPEG4_SP_L1 && profile <= MPEG4_SP_L3) || (profile == MPEG4_SP_L0)) { retvl = retval; } else if (fmtp->config_binary != NULL) { // see if they indicate simple tools in VOL #if 0 uint8_t *volptr; volptr = MP4AV_Mpeg4FindVol(fmtp->config_binary, fmtp->config_binary_len); if (volptr != NULL && ((volptr[4] & 0x7f) == 0) && ((volptr[5] & 0x80) == 0x80)) { message(LOG_ERR, "xvid", "indicated simple tools in xvid"); retvl = retval; } #endif } free_fmtp_parse(fmtp); } return retvl; } } return -1; } if (compressor != NULL) { const char **lptr = xvid_compressors; while (*lptr != NULL) { if (strcasecmp(*lptr, compressor) == 0) { return retval; } lptr++; } } return -1; }
static int look_and_parse_vol (xvid_codec_t *xvid, uint8_t *bufptr, uint32_t len) { uint8_t *volptr; uint32_t vollen; int ret; volptr = MP4AV_Mpeg4FindVol(bufptr, len); if (volptr == NULL) { return -1; } vollen = len - (volptr - bufptr); uint8_t timeBits; uint16_t timeTicks, dur, width, height; uint8_t aspect_ratio, aspect_ratio_w, aspect_ratio_h; if (MP4AV_Mpeg4ParseVol(volptr, vollen, &timeBits, &timeTicks, &dur, &width, &height, &aspect_ratio, &aspect_ratio_w, &aspect_ratio_h) == false) { return -1; } xvid_message(LOG_DEBUG, "xvid", "aspect ratio %x %d %d", aspect_ratio, aspect_ratio_w, aspect_ratio_h); // Get the VO/VOL header. If we fail, set the bytestream back ret = 0; XVID_DEC_PARAM param; param.width = width; param.height = height; ret = xvid_decore(NULL, XVID_DEC_CREATE, ¶m, NULL); if (ret != XVID_ERR_OK) { return -1; } double ar = 0.0; switch (aspect_ratio) { default: aspect_ratio_h = 0; break; case 2: aspect_ratio_w = 12; aspect_ratio_h = 11; break; case 3: aspect_ratio_w = 10; aspect_ratio_h = 11; break; case 4: aspect_ratio_w = 16; aspect_ratio_h = 11; break; case 5: aspect_ratio_w = 40; aspect_ratio_h = 33; break; case 0xf: break; } if (aspect_ratio_h != 0) { ar = (double)aspect_ratio_w; ar *= (double) param.width; ar /= (double)aspect_ratio_h; ar /= (double)param.height; } xvid->m_xvid_handle = param.handle; xvid->m_vft->video_configure(xvid->m_ifptr, param.width, param.height, VIDEO_FORMAT_YUV, ar); // we need to then run the VOL through the decoder. XVID_DEC_FRAME frame; XVID_DEC_PICTURE decpict; frame.bitstream = (void *)volptr; frame.length = vollen; frame.colorspace = XVID_CSP_USER; frame.image = &decpict; ret = xvid_decore(xvid->m_xvid_handle, XVID_DEC_DECODE, &frame, NULL); xvid_message(LOG_NOTICE, "xvidif", "decoded vol ret %d", ret); return ret == XVID_ERR_OK ? 0 : -1; }
static int look_for_vol (xvid_codec_t *xvid, uint8_t *bufptr, uint32_t len) { uint8_t *volptr; int vollen; int ret; volptr = MP4AV_Mpeg4FindVol(bufptr, len); if (volptr == NULL) { return -1 ; } vollen = len - (volptr - bufptr); uint8_t timeBits; uint16_t timeTicks, dur, width, height; uint8_t aspect_ratio, aspect_ratio_w, aspect_ratio_h; if (MP4AV_Mpeg4ParseVol(volptr, vollen, &timeBits, &timeTicks, &dur, &width, &height, &aspect_ratio, &aspect_ratio_w, &aspect_ratio_h) == false) { return -1; } xvid_message(LOG_DEBUG, "xvid", "aspect ratio %x %d %d", aspect_ratio, aspect_ratio_w, aspect_ratio_h); // Get the VO/VOL header. If we fail, set the bytestream back xvid_dec_create_t create; create.version = XVID_VERSION; create.width = width; create.height = height; ret = xvid_decore(NULL, XVID_DEC_CREATE, &create, NULL); double ar = 0.0; switch (aspect_ratio) { default: aspect_ratio_h = 0; break; case 2: aspect_ratio_w = 12; aspect_ratio_h = 11; break; case 3: aspect_ratio_w = 10; aspect_ratio_h = 11; break; case 4: aspect_ratio_w = 16; aspect_ratio_h = 11; break; case 5: aspect_ratio_w = 40; aspect_ratio_h = 33; break; case 0xf: break; } if (aspect_ratio_h != 0) { ar = (double)aspect_ratio_w; ar *= (double) create.width; ar /= (double)aspect_ratio_h; ar /= (double)create.height; } xvid->m_xvid_handle = create.handle; xvid->m_vft->video_configure(xvid->m_ifptr, create.width, create.height, VIDEO_FORMAT_YUV, ar); // we need to then run the VOL through the decoder. xvid_dec_frame_t dec; xvid_dec_stats_t stats; do { dec.version = XVID_VERSION; dec.bitstream = volptr; dec.length = vollen; dec.output.csp = XVID_CSP_INTERNAL; stats.version = XVID_VERSION; ret = xvid_decore(xvid->m_xvid_handle, XVID_DEC_DECODE, &dec, &stats); if (ret < 0) { xvid_message(LOG_NOTICE, "xvidif", "decoded vol ret %d", ret); } if (ret < 0 || ret > vollen) { vollen = 0; } else { vollen -= ret; volptr += ret; } // we could check for vol changes, etc here, if we wanted. } while (vollen > 4 && stats.type == 0); return 0; }