/***************************************************************************** * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a * picture_t structure (when not in direct rendering mode). *****************************************************************************/ static void ffmpeg_CopyPicture( decoder_t *p_dec, picture_t *p_pic, AVFrame *p_ff_pic ) { decoder_sys_t *p_sys = p_dec->p_sys; if( p_sys->p_va ) { vlc_va_Extract( p_sys->p_va, p_pic, p_ff_pic->opaque, p_ff_pic->data[3] ); } else if( FindVlcChroma( p_sys->p_context->pix_fmt ) ) { int i_plane, i_size, i_line; uint8_t *p_dst, *p_src; int i_src_stride, i_dst_stride; if( p_sys->p_context->pix_fmt == PIX_FMT_PAL8 ) { if( !p_pic->format.p_palette ) p_pic->format.p_palette = calloc( 1, sizeof(video_palette_t) ); if( p_pic->format.p_palette ) { p_pic->format.p_palette->i_entries = AVPALETTE_COUNT; memcpy( p_pic->format.p_palette->palette, p_ff_pic->data[1], AVPALETTE_SIZE ); } } for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { p_src = p_ff_pic->data[i_plane]; p_dst = p_pic->p[i_plane].p_pixels; i_src_stride = p_ff_pic->linesize[i_plane]; i_dst_stride = p_pic->p[i_plane].i_pitch; i_size = __MIN( i_src_stride, i_dst_stride ); for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ ) { memcpy( p_dst, p_src, i_size ); p_src += i_src_stride; p_dst += i_dst_stride; } } } else { const char *name = av_get_pix_fmt_name( p_sys->p_context->pix_fmt ); msg_Err( p_dec, "Unsupported decoded output format %d (%s)", p_sys->p_context->pix_fmt, name ? name : "unknown" ); p_dec->b_error = 1; } }
/***************************************************************************** * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a * picture_t structure (when not in direct rendering mode). *****************************************************************************/ static void ffmpeg_CopyPicture( decoder_t *p_dec, picture_t *p_pic, AVFrame *p_ff_pic ) { decoder_sys_t *p_sys = p_dec->p_sys; if( p_sys->p_va ) { vlc_va_Extract( p_sys->p_va, p_pic, p_ff_pic ); } else if( FindVlcChroma( p_sys->p_context->pix_fmt ) ) { int i_plane, i_size, i_line; uint8_t *p_dst, *p_src; int i_src_stride, i_dst_stride; for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { p_src = p_ff_pic->data[i_plane]; p_dst = p_pic->p[i_plane].p_pixels; i_src_stride = p_ff_pic->linesize[i_plane]; i_dst_stride = p_pic->p[i_plane].i_pitch; i_size = __MIN( i_src_stride, i_dst_stride ); for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ ) { memcpy( p_dst, p_src, i_size ); p_src += i_src_stride; p_dst += i_dst_stride; } } } else { const char *name = av_get_pix_fmt_name( p_sys->p_context->pix_fmt ); msg_Err( p_dec, "Unsupported decoded output format %d (%s)", p_sys->p_context->pix_fmt, name ? name : "unknown" ); p_dec->b_error = 1; } }
/***************************************************************************** * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a * picture_t structure (when not in direct rendering mode). *****************************************************************************/ static void ffmpeg_CopyPicture( decoder_t *p_dec, picture_t *p_pic, AVFrame *p_ff_pic ) { decoder_sys_t *p_sys = p_dec->p_sys; if( p_sys->p_va ) { vlc_va_Extract( p_sys->p_va, p_pic, p_ff_pic ); } else if( TestFfmpegChroma( p_sys->p_context->pix_fmt, -1 ) == VLC_SUCCESS ) { int i_plane, i_size, i_line; uint8_t *p_dst, *p_src; int i_src_stride, i_dst_stride; for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { p_src = p_ff_pic->data[i_plane]; p_dst = p_pic->p[i_plane].p_pixels; i_src_stride = p_ff_pic->linesize[i_plane]; i_dst_stride = p_pic->p[i_plane].i_pitch; i_size = __MIN( i_src_stride, i_dst_stride ); for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ ) { vlc_memcpy( p_dst, p_src, i_size ); p_src += i_src_stride; p_dst += i_dst_stride; } } } else { msg_Err( p_dec, "don't know how to convert chroma %i", p_sys->p_context->pix_fmt ); p_dec->b_error = 1; } }
/***************************************************************************** * DecodeVideo: Called to decode one or more frames *****************************************************************************/ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; AVCodecContext *p_context = p_sys->p_context; int b_drawpicture; block_t *p_block; if( !pp_block ) return NULL; if( !p_context->extradata_size && p_dec->fmt_in.i_extra ) { ffmpeg_InitCodec( p_dec ); if( p_sys->b_delayed_open ) OpenVideoCodec( p_dec ); } p_block = *pp_block; if(!p_block && !(p_sys->p_codec->capabilities & CODEC_CAP_DELAY) ) return NULL; if( p_sys->b_delayed_open ) { if( p_block ) block_Release( p_block ); return NULL; } if( p_block) { if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */ p_sys->i_late_frames = 0; post_mt( p_sys ); if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) avcodec_flush_buffers( p_context ); wait_mt( p_sys ); block_Release( p_block ); return NULL; } if( p_block->i_flags & BLOCK_FLAG_PREROLL ) { /* Do not care about late frames when prerolling * TODO avoid decoding of non reference frame * (ie all B except for H264 where it depends only on nal_ref_idc) */ p_sys->i_late_frames = 0; } } if( !p_dec->b_pace_control && (p_sys->i_late_frames > 0) && (mdate() - p_sys->i_late_frames_start > INT64_C(5000000)) ) { if( p_sys->i_pts > VLC_TS_INVALID ) { p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */ } if( p_block ) block_Release( p_block ); p_sys->i_late_frames--; msg_Err( p_dec, "more than 5 seconds of late video -> " "dropping frame (computer too slow ?)" ); return NULL; } /* A good idea could be to decode all I pictures and see for the other */ if( !p_dec->b_pace_control && p_sys->b_hurry_up && (p_sys->i_late_frames > 4) ) { b_drawpicture = 0; if( p_sys->i_late_frames < 12 ) { p_context->skip_frame = (p_sys->i_skip_frame <= AVDISCARD_NONREF) ? AVDISCARD_NONREF : p_sys->i_skip_frame; } else { /* picture too late, won't decode * but break picture until a new I, and for mpeg4 ...*/ p_sys->i_late_frames--; /* needed else it will never be decrease */ if( p_block ) block_Release( p_block ); msg_Warn( p_dec, "More than 4 late frames, dropping frame" ); return NULL; } } else { if( p_sys->b_hurry_up ) p_context->skip_frame = p_sys->i_skip_frame; if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) ) b_drawpicture = 1; else b_drawpicture = 0; } if( p_context->width <= 0 || p_context->height <= 0 ) { if( p_sys->b_hurry_up ) p_context->skip_frame = p_sys->i_skip_frame; } else if( !b_drawpicture ) { /* It creates broken picture * FIXME either our parser or ffmpeg is broken */ #if 0 if( p_sys->b_hurry_up ) p_context->skip_frame = __MAX( p_context->skip_frame, AVDISCARD_NONREF ); #endif } /* * Do the actual decoding now */ /* Don't forget that libavcodec requires a little more bytes * that the real frame size */ if( p_block && p_block->i_buffer > 0 ) { p_sys->b_flush = ( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE ) != 0; p_block = block_Realloc( p_block, 0, p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE ); if( !p_block ) return NULL; p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE; *pp_block = p_block; memset( p_block->p_buffer + p_block->i_buffer, 0, FF_INPUT_BUFFER_PADDING_SIZE ); } while( !p_block || p_block->i_buffer > 0 || p_sys->b_flush ) { int i_used, b_gotpicture; AVPacket pkt; AVFrame *frame = av_frame_alloc(); if (unlikely(frame == NULL)) { p_dec->b_error = true; break; } post_mt( p_sys ); av_init_packet( &pkt ); if( p_block ) { pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; pkt.pts = p_block->i_pts; pkt.dts = p_block->i_dts; } else { /* Return delayed frames if codec has CODEC_CAP_DELAY */ pkt.data = NULL; pkt.size = 0; } if( !p_sys->palette_sent ) { uint8_t *pal = av_packet_new_side_data(&pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); if (pal) { memcpy(pal, p_dec->fmt_in.video.p_palette->palette, AVPALETTE_SIZE); p_sys->palette_sent = true; } } /* Make sure we don't reuse the same timestamps twice */ if( p_block ) { p_block->i_pts = p_block->i_dts = VLC_TS_INVALID; } i_used = avcodec_decode_video2( p_context, frame, &b_gotpicture, &pkt ); av_free_packet( &pkt ); wait_mt( p_sys ); if( p_sys->b_flush ) p_sys->b_first_frame = true; if( p_block ) { if( p_block->i_buffer <= 0 ) p_sys->b_flush = false; if( i_used < 0 ) { av_frame_unref(frame); if( b_drawpicture ) msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", p_block->i_buffer ); break; } else if( (unsigned)i_used > p_block->i_buffer || p_context->thread_count > 1 ) { i_used = p_block->i_buffer; } /* Consumed bytes */ p_block->i_buffer -= i_used; p_block->p_buffer += i_used; } /* Nothing to display */ if( !b_gotpicture ) { av_frame_unref(frame); if( i_used == 0 ) break; continue; } /* Compute the PTS */ mtime_t i_pts = frame->pkt_pts; if (i_pts <= VLC_TS_INVALID) i_pts = frame->pkt_dts; if( i_pts <= VLC_TS_INVALID ) i_pts = p_sys->i_pts; /* Interpolate the next PTS */ if( i_pts > VLC_TS_INVALID ) p_sys->i_pts = i_pts; if( p_sys->i_pts > VLC_TS_INVALID ) { /* interpolate the next PTS */ if( p_dec->fmt_in.video.i_frame_rate > 0 && p_dec->fmt_in.video.i_frame_rate_base > 0 ) { p_sys->i_pts += CLOCK_FREQ * (2 + frame->repeat_pict) * p_dec->fmt_in.video.i_frame_rate_base / (2 * p_dec->fmt_in.video.i_frame_rate); } else if( p_context->time_base.den > 0 ) { int i_tick = p_context->ticks_per_frame; if( i_tick <= 0 ) i_tick = 1; p_sys->i_pts += CLOCK_FREQ * (2 + frame->repeat_pict) * i_tick * p_context->time_base.num / (2 * p_context->time_base.den); } } /* Update frame late count (except when doing preroll) */ mtime_t i_display_date = 0; if( !p_block || !(p_block->i_flags & BLOCK_FLAG_PREROLL) ) i_display_date = decoder_GetDisplayDate( p_dec, i_pts ); if( i_display_date > 0 && i_display_date <= mdate() ) { p_sys->i_late_frames++; if( p_sys->i_late_frames == 1 ) p_sys->i_late_frames_start = mdate(); } else { p_sys->i_late_frames = 0; } if( !b_drawpicture || ( !p_sys->p_va && !frame->linesize[0] ) ) { av_frame_unref(frame); continue; } picture_t *p_pic = frame->opaque; if( p_pic == NULL ) { /* Get a new picture */ if( p_sys->p_va == NULL ) p_pic = ffmpeg_NewPictBuf( p_dec, p_context ); if( !p_pic ) { av_frame_unref(frame); break; } /* Fill picture_t from AVFrame */ lavc_CopyPicture(p_dec, p_pic, frame); } else { if( p_sys->p_va != NULL ) vlc_va_Extract( p_sys->p_va, p_pic, frame->data[3] ); picture_Hold( p_pic ); } if( !p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den ) { /* Fetch again the aspect ratio in case it changed */ p_dec->fmt_out.video.i_sar_num = p_context->sample_aspect_ratio.num; p_dec->fmt_out.video.i_sar_den = p_context->sample_aspect_ratio.den; if( !p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den ) { p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; } } p_pic->date = i_pts; /* Hack to force display of still pictures */ p_pic->b_force = p_sys->b_first_frame; p_pic->i_nb_fields = 2 + frame->repeat_pict; p_pic->b_progressive = !frame->interlaced_frame; p_pic->b_top_field_first = frame->top_field_first; av_frame_unref(frame); /* Send decoded frame to vout */ if (i_pts > VLC_TS_INVALID) { p_sys->b_first_frame = false; return p_pic; } else picture_Release( p_pic ); } if( p_block ) block_Release( p_block ); return NULL; }