* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/opt.h"
#include "mpegvideo.h"
#include "mpeg4video.h"
#include "h263.h"
{
int i;
int16_t *ac_val, *ac_val1;
- int8_t * const qscale_table= s->current_picture.qscale_table;
+ int8_t * const qscale_table = s->current_picture.f.qscale_table;
/* find prediction */
ac_val = s->ac_val[0][0] + s->block_index[n] * 16;
v|= 0x7F >> (7-(bits_count&7));
if(v==0x7F)
- return 1;
+ return s->mb_num;
}else{
if(v == ff_mpeg4_resync_prefix[bits_count&7]){
- int len;
+ int len, mb_num;
+ int mb_num_bits= av_log2(s->mb_num - 1) + 1;
GetBitContext gb= s->gb;
skip_bits(&s->gb, 1);
if(get_bits1(&s->gb)) break;
}
+ mb_num= get_bits(&s->gb, mb_num_bits);
+ if(!mb_num || mb_num > s->mb_num || get_bits_count(&s->gb)+6 > s->gb.size_in_bits)
+ mb_num= -1;
+
s->gb= gb;
if(len>=ff_mpeg4_get_video_packet_prefix_length(s))
- return 1;
+ return mb_num;
}
}
return 0;
av_log(s->avctx, AV_LOG_ERROR, "illegal mb_num in video packet (%d %d) \n", mb_num, s->mb_num);
return -1;
}
- if(s->pict_type == AV_PICTURE_TYPE_B){
- int mb_x = 0, mb_y = 0;
-
- while(s->next_picture.mbskip_table[ s->mb_index2xy[ mb_num ] ]) {
- if (!mb_x) ff_thread_await_progress((AVFrame*)s->next_picture_ptr, mb_y++, 0);
- mb_num++;
- if (++mb_x == s->mb_width) mb_x = 0;
- }
- if(mb_num >= s->mb_num) return -1; // slice contains just skipped MBs which where already decoded
- }
s->mb_x= mb_num % s->mb_width;
s->mb_y= mb_num / s->mb_width;
}while(cbpc == 8);
s->cbp_table[xy]= cbpc & 3;
- s->current_picture.mb_type[xy]= MB_TYPE_INTRA;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_INTRA;
s->mb_intra = 1;
if(cbpc & 4) {
ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]);
}
- s->current_picture.qscale_table[xy]= s->qscale;
+ s->current_picture.f.qscale_table[xy]= s->qscale;
s->mbintra_table[xy]= 1;
for(i=0; i<6; i++){
s->pred_dir_table[xy]= dir;
}else{ /* P/S_TYPE */
int mx, my, pred_x, pred_y, bits;
- int16_t * const mot_val= s->current_picture.motion_val[0][s->block_index[0]];
+ int16_t * const mot_val = s->current_picture.f.motion_val[0][s->block_index[0]];
const int stride= s->b8_stride*2;
try_again:
if(bits&0x10000){
/* skip mb */
if(s->pict_type==AV_PICTURE_TYPE_S && s->vol_sprite_usage==GMC_SPRITE){
- s->current_picture.mb_type[xy]= MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_L0;
mx= get_amv(s, 0);
my= get_amv(s, 1);
}else{
- s->current_picture.mb_type[xy]= MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0;
mx=my=0;
}
mot_val[0 ]= mot_val[2 ]=
s->mb_intra = ((cbpc & 4) != 0);
if(s->mb_intra){
- s->current_picture.mb_type[xy]= MB_TYPE_INTRA;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_INTRA;
s->mbintra_table[xy]= 1;
mot_val[0 ]= mot_val[2 ]=
mot_val[0+stride]= mot_val[2+stride]= 0;
my = h263_decode_motion(s, pred_y, s->f_code);
if (my >= 0xffff)
return -1;
- s->current_picture.mb_type[xy]= MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0;
} else {
mx = get_amv(s, 0);
my = get_amv(s, 1);
- s->current_picture.mb_type[xy]= MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_GMC | MB_TYPE_L0;
}
mot_val[0 ]= mot_val[2 ] =
mot_val[1+stride]= mot_val[3+stride]= my;
} else {
int i;
- s->current_picture.mb_type[xy]= MB_TYPE_8x8 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_L0;
for(i=0;i<4;i++) {
int16_t *mot_val= h263_pred_motion(s, i, 0, &pred_x, &pred_y);
mx = h263_decode_motion(s, pred_x, s->f_code);
}
s->cbp_table[xy]|= cbpy<<2;
- s->current_picture.mb_type[xy] |= ac_pred*MB_TYPE_ACPRED;
+ s->current_picture.f.mb_type[xy] |= ac_pred*MB_TYPE_ACPRED;
}else{ /* P || S_TYPE */
- if(IS_INTRA(s->current_picture.mb_type[xy])){
+ if (IS_INTRA(s->current_picture.f.mb_type[xy])) {
int dir=0,i;
int ac_pred = get_bits1(&s->gb);
int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc.table, CBPY_VLC_BITS, 1);
if(s->cbp_table[xy] & 8) {
ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]);
}
- s->current_picture.qscale_table[xy]= s->qscale;
+ s->current_picture.f.qscale_table[xy] = s->qscale;
for(i=0; i<6; i++){
int dc_pred_dir;
}
s->cbp_table[xy]&= 3; //remove dquant
s->cbp_table[xy]|= cbpy<<2;
- s->current_picture.mb_type[xy] |= ac_pred*MB_TYPE_ACPRED;
+ s->current_picture.f.mb_type[xy] |= ac_pred*MB_TYPE_ACPRED;
s->pred_dir_table[xy]= dir;
- }else if(IS_SKIP(s->current_picture.mb_type[xy])){
- s->current_picture.qscale_table[xy]= s->qscale;
+ } else if (IS_SKIP(s->current_picture.f.mb_type[xy])) {
+ s->current_picture.f.qscale_table[xy] = s->qscale;
s->cbp_table[xy]= 0;
}else{
int cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc.table, CBPY_VLC_BITS, 1);
if(s->cbp_table[xy] & 8) {
ff_set_qscale(s, s->qscale + quant_tab[get_bits(&s->gb, 2)]);
}
- s->current_picture.qscale_table[xy]= s->qscale;
+ s->current_picture.f.qscale_table[xy] = s->qscale;
s->cbp_table[xy]&= 3; //remove dquant
s->cbp_table[xy]|= (cbpy^0xf)<<2;
int cbp, mb_type;
const int xy= s->mb_x + s->mb_y*s->mb_stride;
- mb_type= s->current_picture.mb_type[xy];
+ mb_type = s->current_picture.f.mb_type[xy];
cbp = s->cbp_table[xy];
s->use_intra_dc_vlc= s->qscale < s->intra_dc_threshold;
- if(s->current_picture.qscale_table[xy] != s->qscale){
- ff_set_qscale(s, s->current_picture.qscale_table[xy] );
+ if (s->current_picture.f.qscale_table[xy] != s->qscale) {
+ ff_set_qscale(s, s->current_picture.f.qscale_table[xy]);
}
if (s->pict_type == AV_PICTURE_TYPE_P || s->pict_type==AV_PICTURE_TYPE_S) {
int i;
for(i=0; i<4; i++){
- s->mv[0][i][0] = s->current_picture.motion_val[0][ s->block_index[i] ][0];
- s->mv[0][i][1] = s->current_picture.motion_val[0][ s->block_index[i] ][1];
+ s->mv[0][i][0] = s->current_picture.f.motion_val[0][s->block_index[i]][0];
+ s->mv[0][i][1] = s->current_picture.f.motion_val[0][s->block_index[i]][1];
}
s->mb_intra = IS_INTRA(mb_type);
s->mb_skipped = 1;
}
}else if(s->mb_intra){
- s->ac_pred = IS_ACPRED(s->current_picture.mb_type[xy]);
+ s->ac_pred = IS_ACPRED(s->current_picture.f.mb_type[xy]);
}else if(!s->mb_intra){
// s->mcsel= 0; //FIXME do we need to init that
}
} else { /* I-Frame */
s->mb_intra = 1;
- s->ac_pred = IS_ACPRED(s->current_picture.mb_type[xy]);
+ s->ac_pred = IS_ACPRED(s->current_picture.f.mb_type[xy]);
}
if (!IS_SKIP(mb_type)) {
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
if(s->pict_type==AV_PICTURE_TYPE_S && s->vol_sprite_usage==GMC_SPRITE){
- s->current_picture.mb_type[xy]= MB_TYPE_SKIP | MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_L0;
s->mcsel=1;
s->mv[0][0][0]= get_amv(s, 0);
s->mv[0][0][1]= get_amv(s, 1);
s->mb_skipped = 0;
}else{
- s->current_picture.mb_type[xy]= MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0;
s->mcsel=0;
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
s->mv_dir = MV_DIR_FORWARD;
if ((cbpc & 16) == 0) {
if(s->mcsel){
- s->current_picture.mb_type[xy]= MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_GMC | MB_TYPE_16x16 | MB_TYPE_L0;
/* 16x16 global motion prediction */
s->mv_type = MV_TYPE_16X16;
mx= get_amv(s, 0);
s->mv[0][0][0] = mx;
s->mv[0][0][1] = my;
}else if((!s->progressive_sequence) && get_bits1(&s->gb)){
- s->current_picture.mb_type[xy]= MB_TYPE_16x8 | MB_TYPE_L0 | MB_TYPE_INTERLACED;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_16x8 | MB_TYPE_L0 | MB_TYPE_INTERLACED;
/* 16x8 field motion prediction */
s->mv_type= MV_TYPE_FIELD;
s->mv[0][i][1] = my;
}
}else{
- s->current_picture.mb_type[xy]= MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0;
/* 16x16 motion prediction */
s->mv_type = MV_TYPE_16X16;
h263_pred_motion(s, 0, 0, &pred_x, &pred_y);
s->mv[0][0][1] = my;
}
} else {
- s->current_picture.mb_type[xy]= MB_TYPE_8x8 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_8x8 | MB_TYPE_L0;
s->mv_type = MV_TYPE_8X8;
for(i=0;i<4;i++) {
mot_val = h263_pred_motion(s, i, 0, &pred_x, &pred_y);
}
/* if we skipped it in the future P Frame than skip it now too */
- s->mb_skipped= s->next_picture.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]; // Note, skiptab=0 if last was GMC
+ s->mb_skipped = s->next_picture.f.mbskip_table[s->mb_y * s->mb_stride + s->mb_x]; // Note, skiptab=0 if last was GMC
if(s->mb_skipped){
/* skip mb */
s->mv[0][0][1] = 0;
s->mv[1][0][0] = 0;
s->mv[1][0][1] = 0;
- s->current_picture.mb_type[xy]= MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_SKIP | MB_TYPE_16x16 | MB_TYPE_L0;
goto end;
}
s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT;
mb_type |= ff_mpeg4_set_direct_mv(s, mx, my);
}
- s->current_picture.mb_type[xy]= mb_type;
+ s->current_picture.f.mb_type[xy] = mb_type;
} else { /* I-Frame */
do{
cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc.table, INTRA_MCBPC_VLC_BITS, 2);
intra:
s->ac_pred = get_bits1(&s->gb);
if(s->ac_pred)
- s->current_picture.mb_type[xy]= MB_TYPE_INTRA | MB_TYPE_ACPRED;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_INTRA | MB_TYPE_ACPRED;
else
- s->current_picture.mb_type[xy]= MB_TYPE_INTRA;
+ s->current_picture.f.mb_type[xy] = MB_TYPE_INTRA;
cbpy = get_vlc2(&s->gb, ff_h263_cbpy_vlc.table, CBPY_VLC_BITS, 1);
if(cbpy<0){
/* per-MB end of slice check */
if(s->codec_id==CODEC_ID_MPEG4){
- if(mpeg4_is_resync(s)){
- const int delta= s->mb_x + 1 == s->mb_width ? 2 : 1;
+ int next= mpeg4_is_resync(s);
+ if(next) {
+ if (s->mb_x + s->mb_y*s->mb_width + 1 > next && s->avctx->error_recognition >= FF_ER_AGGRESSIVE) {
+ return -1;
+ } else if (s->mb_x + s->mb_y*s->mb_width + 1 >= next)
+ return SLICE_END;
if(s->pict_type==AV_PICTURE_TYPE_B){
+ const int delta= s->mb_x + 1 == s->mb_width ? 2 : 1;
ff_thread_await_progress((AVFrame*)s->next_picture_ptr,
(s->mb_x + delta >= s->mb_width) ? FFMIN(s->mb_y+1, s->mb_height-1) : s->mb_y, 0);
+ if (s->next_picture.f.mbskip_table[xy + delta])
+ return SLICE_OK;
}
- if(s->pict_type==AV_PICTURE_TYPE_B && s->next_picture.mbskip_table[xy + delta])
- return SLICE_OK;
return SLICE_END;
}
}
return 0;
}
+static int mpeg4_decode_profile_level(MpegEncContext * s, GetBitContext *gb){
+
+ s->avctx->profile = get_bits(gb, 4);
+ s->avctx->level = get_bits(gb, 4);
+
+ // for Simple profile, level 0
+ if (s->avctx->profile == 0 && s->avctx->level == 8) {
+ s->avctx->level = 0;
+ }
+
+ return 0;
+}
+
static int decode_vol_header(MpegEncContext *s, GetBitContext *gb){
int width, height, vo_ver_id;
}
}
- /* ffmpeg detection */
+ /* libavcodec detection */
e=sscanf(buf, "FFmpe%*[^b]b%d", &build)+3;
if(e!=4)
e=sscanf(buf, "FFmpeg v%d.%d.%d / libavcodec build: %d", &ver, &ver2, &ver3, &build);
}
if(s->avctx->time_base.num)
- s->current_picture_ptr->pts= (s->time + s->avctx->time_base.num/2) / s->avctx->time_base.num;
+ s->current_picture_ptr->f.pts = (s->time + s->avctx->time_base.num / 2) / s->avctx->time_base.num;
else
- s->current_picture_ptr->pts= AV_NOPTS_VALUE;
+ s->current_picture_ptr->f.pts = AV_NOPTS_VALUE;
if(s->avctx->debug&FF_DEBUG_PTS)
- av_log(s->avctx, AV_LOG_DEBUG, "MPEG4 PTS: %"PRId64"\n", s->current_picture_ptr->pts);
+ av_log(s->avctx, AV_LOG_DEBUG, "MPEG4 PTS: %"PRId64"\n",
+ s->current_picture_ptr->f.pts);
check_marker(gb, "before vop_coded");
*/
int ff_mpeg4_decode_picture_header(MpegEncContext * s, GetBitContext *gb)
{
- int startcode, v;
+ unsigned startcode, v;
/* search next start code */
align_get_bits(gb);
startcode = 0xff;
for(;;) {
if(get_bits_count(gb) >= gb->size_in_bits){
- if(gb->size_in_bits==8 && (s->divx_version>=0 || s->xvid_build>=0)){
- av_log(s->avctx, AV_LOG_WARNING, "frame skip %d\n", gb->size_in_bits);
+ if(gb->size_in_bits==8 && (s->divx_version>=0 || s->xvid_build>=0) || s->codec_tag == AV_RL32("QMP4")){
+ av_log(s->avctx, AV_LOG_VERBOSE, "frame skip %d\n", gb->size_in_bits);
return FRAME_SKIPPED; //divx bug
}else
return -1; //end of stream
else if(startcode == GOP_STARTCODE){
mpeg4_decode_gop_header(s, gb);
}
+ else if(startcode == VOS_STARTCODE){
+ mpeg4_decode_profile_level(s, gb);
+ }
else if(startcode == VOP_STARTCODE){
break;
}
return 0;
}
+static const AVProfile mpeg4_video_profiles[] = {
+ { FF_PROFILE_MPEG4_SIMPLE, "Simple Profile" },
+ { FF_PROFILE_MPEG4_SIMPLE_SCALABLE, "Simple Scalable Profile" },
+ { FF_PROFILE_MPEG4_CORE, "Core Profile" },
+ { FF_PROFILE_MPEG4_MAIN, "Main Profile" },
+ { FF_PROFILE_MPEG4_N_BIT, "N-bit Profile" },
+ { FF_PROFILE_MPEG4_SCALABLE_TEXTURE, "Scalable Texture Profile" },
+ { FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION, "Simple Face Animation Profile" },
+ { FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE, "Basic Animated Texture Profile" },
+ { FF_PROFILE_MPEG4_HYBRID, "Hybrid Profile" },
+ { FF_PROFILE_MPEG4_ADVANCED_REAL_TIME, "Advanced Real Time Simple Profile" },
+ { FF_PROFILE_MPEG4_CORE_SCALABLE, "Code Scalable Profile" },
+ { FF_PROFILE_MPEG4_ADVANCED_CODING, "Advanced Coding Profile" },
+ { FF_PROFILE_MPEG4_ADVANCED_CORE, "Advanced Core Profile" },
+ { FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE, "Advanced Scalable Texture Profile" },
+ { FF_PROFILE_MPEG4_SIMPLE_STUDIO, "Simple Studio Profile" },
+ { FF_PROFILE_MPEG4_ADVANCED_SIMPLE, "Advanced Simple Profile" },
+};
+
+static const AVOption mpeg4_options[] = {
+ {"quarter_sample", "1/4 subpel MC", offsetof(MpegEncContext, quarter_sample), FF_OPT_TYPE_INT, {.dbl = 0}, 0, 1, 0},
+ {"divx_packed", "divx style packed b frames", offsetof(MpegEncContext, divx_packed), FF_OPT_TYPE_INT, {.dbl = 0}, 0, 1, 0},
+ {NULL}
+};
+
+static const AVClass mpeg4_class = {
+ "MPEG4 Video Decoder",
+ av_default_item_name,
+ mpeg4_options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+static const AVClass mpeg4_vdpau_class = {
+ "MPEG4 Video VDPAU Decoder",
+ av_default_item_name,
+ mpeg4_options,
+ LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_mpeg4_decoder = {
- "mpeg4",
- AVMEDIA_TYPE_VIDEO,
- CODEC_ID_MPEG4,
- sizeof(MpegEncContext),
- decode_init,
- NULL,
- ff_h263_decode_end,
- ff_h263_decode_frame,
- CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY | CODEC_CAP_FRAME_THREADS,
+ .name = "mpeg4",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = CODEC_ID_MPEG4,
+ .priv_data_size = sizeof(MpegEncContext),
+ .init = decode_init,
+ .close = ff_h263_decode_end,
+ .decode = ff_h263_decode_frame,
+ .capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY | CODEC_CAP_FRAME_THREADS,
.flush= ff_mpeg_flush,
.max_lowres= 3,
.long_name= NULL_IF_CONFIG_SMALL("MPEG-4 part 2"),
.pix_fmts= ff_hwaccel_pixfmt_list_420,
- .update_thread_context= ONLY_IF_THREADS_ENABLED(ff_mpeg_update_thread_context)
+ .profiles = NULL_IF_CONFIG_SMALL(mpeg4_video_profiles),
+ .update_thread_context= ONLY_IF_THREADS_ENABLED(ff_mpeg_update_thread_context),
+ .priv_class = &mpeg4_class,
};
#if CONFIG_MPEG4_VDPAU_DECODER
AVCodec ff_mpeg4_vdpau_decoder = {
- "mpeg4_vdpau",
- AVMEDIA_TYPE_VIDEO,
- CODEC_ID_MPEG4,
- sizeof(MpegEncContext),
- decode_init,
- NULL,
- ff_h263_decode_end,
- ff_h263_decode_frame,
- CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
+ .name = "mpeg4_vdpau",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = CODEC_ID_MPEG4,
+ .priv_data_size = sizeof(MpegEncContext),
+ .init = decode_init,
+ .close = ff_h263_decode_end,
+ .decode = ff_h263_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
.long_name= NULL_IF_CONFIG_SMALL("MPEG-4 part 2 (VDPAU)"),
.pix_fmts= (const enum PixelFormat[]){PIX_FMT_VDPAU_MPEG4, PIX_FMT_NONE},
+ .priv_class = &mpeg4_vdpau_class,
};
#endif