void xiph_decode (demux_t *demux, void *data, block_t *block) { rtp_xiph_t *self = (rtp_xiph_t *)data; // sunqueen modify if (!data || block->i_buffer < 4) goto drop; /* 32-bits RTP header (§2.2) */ uint32_t ident = GetDWBE (block->p_buffer); block->i_buffer -= 4; block->p_buffer += 4; unsigned fragtype = (ident >> 6) & 3; unsigned datatype = (ident >> 4) & 3; unsigned pkts = (ident) & 15; ident >>= 8; /* RTP defragmentation */ if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY)) { /* Screwed! discontinuity within a fragmented packet */ msg_Warn (demux, self->vorbis ? "discontinuity in fragmented Vorbis packet" : "discontinuity in fragmented Theora packet"); block_Release (self->block); self->block = NULL; } if (fragtype <= 1) { if (self->block) /* Invalid first fragment */ { block_Release (self->block); self->block = NULL; } } else { if (!self->block) goto drop; /* Invalid non-first fragment */ } if (fragtype > 0) { /* Fragment */ if (pkts > 0 || block->i_buffer < 2) goto drop; size_t fraglen = GetWBE (block->p_buffer); if (block->i_buffer < (fraglen + 2)) goto drop; /* Invalid payload length */ block->i_buffer = fraglen; if (fragtype == 1)/* Keep first fragment */ { block->i_buffer += 2; self->block = block; } else { /* Append non-first fragment */ size_t len = self->block->i_buffer; self->block = block_Realloc (self->block, 0, len + fraglen); if (!self->block) { block_Release (block); return; } memcpy (self->block->p_buffer + len, block->p_buffer + 2, fraglen); block_Release (block); } if (fragtype < 3) return; /* Non-last fragment */ /* Last fragment reached, process it */ block = self->block; self->block = NULL; SetWBE (block->p_buffer, block->i_buffer - 2); pkts = 1; } /* RTP payload packets processing */ while (pkts > 0) { if (block->i_buffer < 2) goto drop; size_t len = GetWBE (block->p_buffer); block->i_buffer -= 2; block->p_buffer += 2; if (block->i_buffer < len) goto drop; switch (datatype) { case 0: /* Raw payload */ { if (self->ident != ident) { msg_Warn (demux, self->vorbis ? "ignoring raw Vorbis payload without configuration" : "ignoring raw Theora payload without configuration"); break; } block_t *raw = block_Alloc (len); memcpy (raw->p_buffer, block->p_buffer, len); raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */ codec_decode (demux, self->id, raw); break; } case 1: /* Packed configuration frame (§3.1.1) */ { if (self->ident == ident) break; /* Ignore config retransmission */ void *extv; ssize_t extc = xiph_header (&extv, block->p_buffer, len); if (extc < 0) break; es_format_t fmt; es_format_Init (&fmt, self->vorbis ? AUDIO_ES : VIDEO_ES, self->vorbis ? VLC_CODEC_VORBIS : VLC_CODEC_THEORA); fmt.p_extra = extv; fmt.i_extra = extc; codec_destroy (demux, self->id); msg_Dbg (demux, self->vorbis ? "Vorbis packed configuration received (%06"PRIx32")" : "Theora packed configuration received (%06"PRIx32")", ident); self->ident = ident; self->id = (es_out_id_t *)codec_init (demux, &fmt); // sunqueen modify break; } } block->i_buffer -= len; block->p_buffer += len; pkts--; } drop: block_Release (block); }
/***************************************************************************** * DecodeVideo: Called to decode one or more frames *****************************************************************************/ 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; int b_null_size = false; block_t *p_block; if( !pp_block || !*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 ) { if( ffmpeg_OpenCodec( p_dec ) ) msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec ); } } p_block = *pp_block; if( p_sys->b_delayed_open ) { block_Release( p_block ); return NULL; } 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; if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) avcodec_flush_buffers( p_context ); 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 ) { msg_Err( p_dec, "more than 5 seconds of late video -> " "dropping frame (computer too slow ?)" ); p_sys->i_pts = VLC_TS_INVALID; /* To make sure we recover properly */ } block_Release( p_block ); p_sys->i_late_frames--; 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 */ block_Release( p_block ); return NULL; } } else { if( p_sys->b_hurry_up ) p_context->skip_frame = p_sys->i_skip_frame; if( !(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; b_null_size = true; } 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 ffmpeg requires a little more bytes * that the real frame size */ if( 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->i_buffer > 0 || p_sys->b_flush ) { int i_used, b_gotpicture; picture_t *p_pic; AVPacket pkt; /* Set the PTS/DTS in the context reordered_opaque field */ if( p_block->i_pts > VLC_TS_INVALID ) p_context->reordered_opaque = (p_block->i_pts << 1) | 0; else if( p_block->i_dts > VLC_TS_INVALID ) p_context->reordered_opaque = (p_block->i_dts << 1) | 1; else p_context->reordered_opaque = INT64_MIN; p_sys->p_ff_pic->reordered_opaque = p_context->reordered_opaque; /* Make sure we don't reuse the same timestamps twice */ p_block->i_pts = p_block->i_dts = VLC_TS_INVALID; post_mt( p_sys ); av_init_packet( &pkt ); pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; i_used = avcodec_decode_video2( p_context, p_sys->p_ff_pic, &b_gotpicture, &pkt ); if( b_null_size && !p_sys->b_flush && p_context->width > 0 && p_context->height > 0 ) { /* Reparse it to not drop the I frame */ b_null_size = false; if( p_sys->b_hurry_up ) p_context->skip_frame = p_sys->i_skip_frame; i_used = avcodec_decode_video2( p_context, p_sys->p_ff_pic, &b_gotpicture, &pkt ); } wait_mt( p_sys ); if( p_sys->b_flush ) p_sys->b_first_frame = true; if( p_block->i_buffer <= 0 ) p_sys->b_flush = false; if( i_used < 0 ) { if( b_drawpicture ) msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", p_block->i_buffer ); block_Release( p_block ); return NULL; } else if( 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 ) { if( i_used == 0 ) break; continue; } /* Sanity check (seems to be needed for some streams) */ if( p_sys->p_ff_pic->pict_type == AV_PICTURE_TYPE_B) { p_sys->b_has_b_frames = true; } /* Compute the PTS */ mtime_t i_pts = VLC_TS_INVALID; if( p_sys->p_ff_pic->reordered_opaque != INT64_MIN ) { mtime_t i_ts = p_sys->p_ff_pic->reordered_opaque >> 1; bool b_dts = p_sys->p_ff_pic->reordered_opaque & 1; if( b_dts ) { if( !p_context->has_b_frames || !p_sys->b_has_b_frames || !p_sys->p_ff_pic->reference || p_sys->i_pts <= VLC_TS_INVALID ) i_pts = i_ts; /* Guess what ? The rules are different for Real Video :( */ if( (p_dec->fmt_in.i_codec == VLC_CODEC_RV30 || p_dec->fmt_in.i_codec == VLC_CODEC_RV40) && p_sys->b_has_b_frames ) { i_pts = VLC_TS_INVALID; if(p_sys->p_ff_pic->reference) i_pts = i_ts; } } else { i_pts = i_ts; } } 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 += INT64_C(1000000) * (2 + p_sys->p_ff_pic->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 += INT64_C(1000000) * (2 + p_sys->p_ff_pic->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->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 && !p_sys->p_ff_pic->linesize[0] ) ) continue; if( !p_sys->p_ff_pic->opaque ) { /* Get a new picture */ p_pic = ffmpeg_NewPictBuf( p_dec, p_context ); if( !p_pic ) { block_Release( p_block ); return NULL; } /* Fill p_picture_t from AVVideoFrame and do chroma conversion * if needed */ ffmpeg_CopyPicture( p_dec, p_pic, p_sys->p_ff_pic ); } else { p_pic = (picture_t *)p_sys->p_ff_pic->opaque; decoder_LinkPicture( p_dec, 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; } } /* Send decoded frame to vout */ if( i_pts > VLC_TS_INVALID) { p_pic->date = i_pts; if( p_sys->b_first_frame ) { /* Hack to force display of still pictures */ p_sys->b_first_frame = false; p_pic->b_force = true; } p_pic->i_nb_fields = 2 + p_sys->p_ff_pic->repeat_pict; p_pic->b_progressive = !p_sys->p_ff_pic->interlaced_frame; p_pic->b_top_field_first = p_sys->p_ff_pic->top_field_first; p_pic->i_qstride = p_sys->p_ff_pic->qstride; int i_mb_h = ( p_pic->format.i_height + 15 ) / 16; p_pic->p_q = malloc( p_pic->i_qstride * i_mb_h ); memcpy( p_pic->p_q, p_sys->p_ff_pic->qscale_table, p_pic->i_qstride * i_mb_h ); switch( p_sys->p_ff_pic->qscale_type ) { case FF_QSCALE_TYPE_MPEG1: p_pic->i_qtype = QTYPE_MPEG1; break; case FF_QSCALE_TYPE_MPEG2: p_pic->i_qtype = QTYPE_MPEG2; break; case FF_QSCALE_TYPE_H264: p_pic->i_qtype = QTYPE_H264; break; } return p_pic; } else { decoder_DeletePicture( p_dec, p_pic ); } }
/***************************************************************************** * DecodeAudio: Called to decode one frame *****************************************************************************/ aout_buffer_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; int i_used, i_output; aout_buffer_t *p_buffer; block_t *p_block; AVPacket pkt; if( !pp_block || !*pp_block ) return NULL; p_block = *pp_block; if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra && p_sys->b_delayed_open) { InitDecoderConfig( p_dec, p_sys->p_context); if( ffmpeg_OpenCodec( p_dec ) ) msg_Err( p_dec, "Cannot open decoder %s", p_sys->psz_namecodec ); } if( p_sys->b_delayed_open ) { block_Release( p_block ); return NULL; } if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { block_Release( p_block ); avcodec_flush_buffers( p_sys->p_context ); p_sys->i_samples = 0; date_Set( &p_sys->end_date, 0 ); if( p_sys->i_codec_id == CODEC_ID_MP2 || p_sys->i_codec_id == CODEC_ID_MP3 ) p_sys->i_reject_count = 3; return NULL; } if( p_sys->i_samples > 0 ) { /* More data */ p_buffer = SplitBuffer( p_dec ); if( !p_buffer ) block_Release( p_block ); return p_buffer; } if( !date_Get( &p_sys->end_date ) && !p_block->i_pts ) { /* We've just started the stream, wait for the first PTS. */ block_Release( p_block ); return NULL; } if( p_block->i_buffer <= 0 ) { block_Release( p_block ); return NULL; } if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 0 ) { *pp_block = 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; memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE ); p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED; } do { i_output = __MAX( p_block->i_buffer, p_sys->i_output_max ); if( i_output > p_sys->i_output_max ) { /* Grow output buffer if necessary (eg. for PCM data) */ p_sys->p_output = av_realloc( p_sys->p_output, i_output ); } av_init_packet( &pkt ); pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; i_used = avcodec_decode_audio3( p_sys->p_context, (int16_t*)p_sys->p_output, &i_output, &pkt ); if( i_used < 0 || i_output < 0 ) { if( i_used < 0 ) msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", p_block->i_buffer ); block_Release( p_block ); return NULL; } else if( (size_t)i_used > p_block->i_buffer ) { i_used = p_block->i_buffer; } p_block->i_buffer -= i_used; p_block->p_buffer += i_used; } while( p_block->i_buffer > 0 && i_output <= 0 ); if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 8 || p_sys->p_context->sample_rate <= 0 ) { msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d", p_sys->p_context->channels, p_sys->p_context->sample_rate ); block_Release( p_block ); return NULL; } if( p_dec->fmt_out.audio.i_rate != (unsigned int)p_sys->p_context->sample_rate ) { date_Init( &p_sys->end_date, p_sys->p_context->sample_rate, 1 ); date_Set( &p_sys->end_date, p_block->i_pts ); } /* **** Set audio output parameters **** */ SetupOutputFormat( p_dec, true ); if( p_block->i_pts != 0 && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } p_block->i_pts = 0; /* **** Now we can output these samples **** */ p_sys->i_samples = i_output / (p_dec->fmt_out.audio.i_bitspersample / 8) / p_sys->p_context->channels; p_sys->p_samples = p_sys->p_output; /* Silent unwanted samples */ if( p_sys->i_reject_count > 0 ) { memset( p_sys->p_output, 0, i_output ); p_sys->i_reject_count--; } p_buffer = SplitBuffer( p_dec ); if( !p_buffer ) block_Release( p_block ); return p_buffer; }
/***************************************************************************** * 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; }
/***************************************************************************** * ProcessPacket: processes a Speex packet. *****************************************************************************/ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block = *pp_block; if( p_block && p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) Flush( p_dec ); /* Date management */ if( p_block && p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } if( !date_Get( &p_sys->end_date ) ) { /* We've just started the stream, wait for the first PTS. */ if( p_block ) block_Release( p_block ); return NULL; } *pp_block = NULL; /* To avoid being fed the same packet again */ if( p_sys->b_packetizer ) { if ( p_sys->p_header->frames_per_packet > 1 ) { short *p_frame_holder = NULL; int i_bits_before = 0, i_bits_after = 0, i_bytes_in_speex_frame = 0, i_pcm_output_size = 0, i_bits_in_speex_frame = 0; block_t *p_new_block = NULL; i_pcm_output_size = p_sys->p_header->frame_size; p_frame_holder = (short*)xmalloc( sizeof(short)*i_pcm_output_size ); speex_bits_read_from( &p_sys->bits, (char*)p_oggpacket->packet, p_oggpacket->bytes); i_bits_before = speex_bits_remaining( &p_sys->bits ); speex_decode_int(p_sys->p_state, &p_sys->bits, p_frame_holder); i_bits_after = speex_bits_remaining( &p_sys->bits ); i_bits_in_speex_frame = i_bits_before - i_bits_after; i_bytes_in_speex_frame = ( i_bits_in_speex_frame + (8 - (i_bits_in_speex_frame % 8)) ) / 8; p_new_block = block_Alloc( i_bytes_in_speex_frame ); memset( p_new_block->p_buffer, 0xff, i_bytes_in_speex_frame ); /* * Copy the first frame in this packet to a new packet. */ speex_bits_rewind( &p_sys->bits ); speex_bits_write( &p_sys->bits, (char*)p_new_block->p_buffer, (int)i_bytes_in_speex_frame ); /* * Move the remaining part of the original packet (subsequent * frames, if there are any) into the beginning * of the original packet so * they are preserved following the realloc. * Note: Any bits that * remain in the initial packet * are "filler" if they do not constitute * an entire byte. */ if ( i_bits_after > 7 ) { /* round-down since we rounded-up earlier (to include * the speex terminator code. */ i_bytes_in_speex_frame--; speex_bits_write( &p_sys->bits, (char*)p_block->p_buffer, p_block->i_buffer - i_bytes_in_speex_frame ); p_block = block_Realloc( p_block, 0, p_block->i_buffer-i_bytes_in_speex_frame ); *pp_block = p_block; } else { speex_bits_reset( &p_sys->bits ); } free( p_frame_holder ); return SendPacket( p_dec, p_new_block); } else { return SendPacket( p_dec, p_block ); } } else { block_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket ); if( p_block ) block_Release( p_block ); return p_aout_buffer; } }
/***************************************************************************** * Resample: convert a buffer *****************************************************************************/ static block_t *Resample( filter_t * p_filter, block_t * p_in_buf ) { if( !p_in_buf || !p_in_buf->i_nb_samples ) { if( p_in_buf ) block_Release( p_in_buf ); return NULL; } filter_sys_t *p_sys = p_filter->p_sys; unsigned int i_out_rate = p_filter->fmt_out.audio.i_rate; int i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio ); /* Check if we really need to run the resampler */ if( i_out_rate == p_filter->fmt_in.audio.i_rate ) { if( !(p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) && p_sys->i_old_wing ) { /* output the whole thing with the samples from last time */ p_in_buf = block_Realloc( p_in_buf, p_sys->i_old_wing * p_filter->fmt_in.audio.i_bytes_per_frame, p_in_buf->i_buffer ); if( !p_in_buf ) return NULL; memcpy( p_in_buf->p_buffer, p_sys->p_buf + i_nb_channels * p_sys->i_old_wing, p_sys->i_old_wing * p_filter->fmt_in.audio.i_bytes_per_frame ); p_in_buf->i_nb_samples += p_sys->i_old_wing; p_in_buf->i_pts = date_Get( &p_sys->end_date ); p_in_buf->i_length = date_Increment( &p_sys->end_date, p_in_buf->i_nb_samples ) - p_in_buf->i_pts; } p_sys->i_old_wing = 0; p_sys->b_first = true; return p_in_buf; } unsigned i_bytes_per_frame = p_filter->fmt_out.audio.i_channels * p_filter->fmt_out.audio.i_bitspersample / 8; size_t i_out_size = i_bytes_per_frame * ( 1 + ( p_in_buf->i_nb_samples * p_filter->fmt_out.audio.i_rate / p_filter->fmt_in.audio.i_rate) ) + p_filter->p_sys->i_buf_size; block_t *p_out_buf = block_Alloc( i_out_size ); if( !p_out_buf ) { block_Release( p_in_buf ); return NULL; } if( (p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) || p_sys->b_first ) { /* Continuity in sound samples has been broken, we'd better reset * everything. */ p_out_buf->i_flags |= BLOCK_FLAG_DISCONTINUITY; p_sys->i_remainder = 0; date_Init( &p_sys->end_date, i_out_rate, 1 ); date_Set( &p_sys->end_date, p_in_buf->i_pts ); p_sys->d_old_factor = 1; p_sys->i_old_wing = 0; p_sys->b_first = false; } size_t i_in_nb = p_in_buf->i_nb_samples; size_t i_in, i_out = 0; double d_factor, d_scale_factor, d_old_scale_factor; size_t i_filter_wing; #if 0 msg_Err( p_filter, "old rate: %i, old factor: %f, old wing: %i, i_in: %i", p_sys->i_old_rate, p_sys->d_old_factor, p_sys->i_old_wing, i_in_nb ); #endif /* Same format in and out... */ assert( p_filter->fmt_in.audio.i_bytes_per_frame == i_bytes_per_frame ); /* Prepare the source buffer */ if( p_sys->i_old_wing ) { /* Copy all our samples in p_in_buf */ /* Normally, there should be enough room for the old wing in the * buffer head room. Otherwise, we need to copy memory anyway. */ p_in_buf = block_Realloc( p_in_buf, p_sys->i_old_wing * 2 * i_bytes_per_frame, p_in_buf->i_buffer ); if( unlikely(p_in_buf == NULL) ) return NULL; memcpy( p_in_buf->p_buffer, p_sys->p_buf, p_sys->i_old_wing * 2 * i_bytes_per_frame ); } i_in_nb += (p_sys->i_old_wing * 2); float *p_in = (float *)p_in_buf->p_buffer; const float *p_in_orig = p_in; /* Make sure the output buffer is reset */ memset( p_out_buf->p_buffer, 0, p_out_buf->i_buffer ); /* Calculate the new length of the filter wing */ d_factor = (double)i_out_rate / p_filter->fmt_in.audio.i_rate; i_filter_wing = ((SMALL_FILTER_NMULT+1)/2.0) * __MAX(1.0,1.0/d_factor) + 1; /* Account for increased filter gain when using factors less than 1 */ d_old_scale_factor = SMALL_FILTER_SCALE * p_sys->d_old_factor + 0.5; d_scale_factor = SMALL_FILTER_SCALE * d_factor + 0.5; /* Apply the old rate until we have enough samples for the new one */ i_in = p_sys->i_old_wing; p_in += p_sys->i_old_wing * i_nb_channels; size_t i_old_in_end = 0; if( p_sys->i_old_wing <= i_in_nb ) i_old_in_end = __MIN( i_filter_wing, i_in_nb - p_sys->i_old_wing ); ResampleFloat( p_filter, &p_out_buf, &i_out, &p_in, i_in, i_old_in_end, p_sys->d_old_factor, true, i_nb_channels, i_bytes_per_frame ); i_in = __MAX( i_in, i_old_in_end ); /* Apply the new rate for the rest of the samples */ if( i_in < i_in_nb - i_filter_wing ) { p_sys->d_old_factor = d_factor; p_sys->i_old_wing = i_filter_wing; } if( p_out_buf ) { ResampleFloat( p_filter, &p_out_buf, &i_out, &p_in, i_in, i_in_nb - i_filter_wing, d_factor, false, i_nb_channels, i_bytes_per_frame ); /* Finalize aout buffer */ p_out_buf->i_nb_samples = i_out; p_out_buf->i_dts = p_out_buf->i_pts = date_Get( &p_sys->end_date ); p_out_buf->i_length = date_Increment( &p_sys->end_date, p_out_buf->i_nb_samples ) - p_out_buf->i_pts; p_out_buf->i_buffer = p_out_buf->i_nb_samples * i_nb_channels * sizeof(int32_t); } /* Buffer i_filter_wing * 2 samples for next time */ if( p_sys->i_old_wing ) { size_t newsize = p_sys->i_old_wing * 2 * i_bytes_per_frame; if( newsize > p_sys->i_buf_size ) { free( p_sys->p_buf ); p_sys->p_buf = malloc( newsize ); if( p_sys->p_buf != NULL ) p_sys->i_buf_size = newsize; else { p_sys->i_buf_size = p_sys->i_old_wing = 0; /* oops! */ block_Release( p_in_buf ); return p_out_buf; } } memcpy( p_sys->p_buf, p_in_orig + (i_in_nb - 2 * p_sys->i_old_wing) * i_nb_channels, (2 * p_sys->i_old_wing) * p_filter->fmt_in.audio.i_bytes_per_frame ); } #if 0 msg_Err( p_filter, "p_out size: %i, nb bytes out: %i", p_out_buf->i_buffer, i_out * p_filter->fmt_in.audio.i_bytes_per_frame ); #endif block_Release( p_in_buf ); return p_out_buf; }
static rfbBool mallocFrameBufferHandler( rfbClient* p_client ) { vlc_fourcc_t i_chroma; demux_t *p_demux = (demux_t *) rfbClientGetClientData( p_client, DemuxThread ); demux_sys_t *p_sys = p_demux->p_sys; if ( p_sys->es ) /* Source has changed resolution */ { es_out_Del( p_demux->out, p_sys->es ); p_sys->es = NULL; } int i_width = p_client->width; int i_height = p_client->height; int i_depth = p_client->format.bitsPerPixel; switch( i_depth ) { case 8: i_chroma = VLC_CODEC_RGB8; break; default: case 16: i_chroma = VLC_CODEC_RGB16; break; case 24: i_chroma = VLC_CODEC_RGB24; break; case 32: i_chroma = VLC_CODEC_RGB32; break; } switch( i_chroma ) { case VLC_CODEC_RGB16: p_client->format.redShift = 11; p_client->format.greenShift = 5; p_client->format.blueShift = 0; p_client->format.redMax = 0x1f; p_client->format.greenMax = 0x3f; p_client->format.blueMax = 0x1f; break; case VLC_CODEC_RGB24: case VLC_CODEC_RGB32: p_client->format.redShift = 16; p_client->format.greenShift = 8; p_client->format.blueShift = 0; p_client->format.redMax = 0xff; p_client->format.greenMax = 0xff; p_client->format.blueMax = 0xff; break; } /* Set up framebuffer */ p_sys->i_framebuffersize = i_width * i_height * i_depth / 8; /* Reuse unsent block */ if ( p_sys->p_block ) p_sys->p_block = block_Realloc( p_sys->p_block, 0, p_sys->i_framebuffersize ); else p_sys->p_block = block_Alloc( p_sys->i_framebuffersize ); if ( p_sys->p_block ) p_sys->p_block->i_buffer = p_sys->i_framebuffersize; else return FALSE; /* Push our VNC config */ SetFormatAndEncodings( p_client ); /* Now init and fill es format */ es_format_t fmt; es_format_Init( &fmt, VIDEO_ES, i_chroma ); /* Fill input format */ fmt.video.i_chroma = i_chroma; fmt.video.i_visible_width = fmt.video.i_width = i_width; fmt.video.i_visible_height = fmt.video.i_height = i_height; fmt.video.i_frame_rate_base = 1000; fmt.video.i_frame_rate = 1000 * p_sys->f_fps; fmt.video.i_bits_per_pixel = i_depth; fmt.video.i_rmask = p_client->format.redMax << p_client->format.redShift; fmt.video.i_gmask = p_client->format.greenMax << p_client->format.greenShift; fmt.video.i_bmask = p_client->format.blueMax << p_client->format.blueShift; fmt.video.i_sar_num = fmt.video.i_sar_den = 1; /* declare the new es */ p_sys->es = es_out_Add( p_demux->out, &fmt ); return TRUE; }
/***************************************************************************** * DecodeAudio: Called to decode one frame *****************************************************************************/ static block_t *DecodeAudio( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; AVCodecContext *ctx = p_sys->p_context; AVFrame *frame = NULL; block_t *p_block = NULL; if( !ctx->extradata_size && p_dec->fmt_in.i_extra && p_sys->b_delayed_open) { InitDecoderConfig( p_dec, ctx ); OpenAudioCodec( p_dec ); } if( p_sys->b_delayed_open ) { if( pp_block ) p_block = *pp_block; goto drop; } /* Flushing or decoding, we return any block ready from multiple frames output */ if( p_sys->p_decoded ) return DequeueOneDecodedFrame( p_sys ); if( pp_block == NULL ) /* Drain request */ { /* we don't need to care about return val */ (void) avcodec_send_packet( ctx, NULL ); } else { p_block = *pp_block; } if( p_block ) { if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { Flush( p_dec ); goto drop; } if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) { date_Set( &p_sys->end_date, VLC_TS_INVALID ); } /* We've just started the stream, wait for the first PTS. */ if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID ) goto drop; if( p_block->i_buffer <= 0 ) goto drop; if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 0 ) { p_block = block_Realloc( p_block, 0, p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE ); if( !p_block ) return NULL; *pp_block = p_block; p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE; memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE ); p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED; } } frame = av_frame_alloc(); if (unlikely(frame == NULL)) goto end; for( int ret = 0; ret == 0; ) { /* Feed in the loop as buffer could have been full on first iterations */ if( p_block ) { AVPacket pkt; av_init_packet( &pkt ); pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; ret = avcodec_send_packet( ctx, &pkt ); if( ret == 0 ) /* Block has been consumed */ { /* Only set new pts from input block if it has been used, * otherwise let it be through interpolation */ if( p_block->i_pts > date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } block_Release( p_block ); *pp_block = p_block = NULL; } else if ( ret != AVERROR(EAGAIN) ) /* Errors other than buffer full */ { if( ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL) ) goto end; else goto drop; } } /* Try to read one or multiple frames */ ret = avcodec_receive_frame( ctx, frame ); if( ret == 0 ) { /* checks and init from first decoded frame */ if( ctx->channels <= 0 || ctx->channels > 8 || ctx->sample_rate <= 0 ) { msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d", ctx->channels, ctx->sample_rate ); goto drop; } else if( p_dec->fmt_out.audio.i_rate != (unsigned int)ctx->sample_rate ) { date_Init( &p_sys->end_date, ctx->sample_rate, 1 ); } SetupOutputFormat( p_dec, true ); if( decoder_UpdateAudioFormat( p_dec ) ) goto drop; block_t *p_converted = ConvertAVFrame( p_dec, frame ); /* Consumes frame */ if( p_converted ) { /* Silent unwanted samples */ if( p_sys->i_reject_count > 0 ) { memset( p_converted->p_buffer, 0, p_converted->i_buffer ); p_sys->i_reject_count--; } p_converted->i_buffer = p_converted->i_nb_samples * p_dec->fmt_out.audio.i_bytes_per_frame; p_converted->i_pts = date_Get( &p_sys->end_date ); p_converted->i_length = date_Increment( &p_sys->end_date, p_converted->i_nb_samples ) - p_converted->i_pts; block_ChainLastAppend( &p_sys->pp_decoded_last, p_converted ); } /* Prepare new frame */ frame = av_frame_alloc(); if (unlikely(frame == NULL)) break; } else av_frame_free( &frame ); }; return ( p_sys->p_decoded ) ? DequeueOneDecodedFrame( p_sys ) : NULL; end: p_dec->b_error = true; if( pp_block ) { assert( *pp_block == p_block ); *pp_block = NULL; } drop: if( p_block != NULL ) block_Release(p_block); if( frame != NULL ) av_frame_free( &frame ); return NULL; }
/***************************************************************************** * DecodeAudio: Called to decode one frame *****************************************************************************/ block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; AVCodecContext *ctx = p_sys->p_context; if( !pp_block || !*pp_block ) return NULL; block_t *p_block = *pp_block; if( !ctx->extradata_size && p_dec->fmt_in.i_extra && p_sys->b_delayed_open) { InitDecoderConfig( p_dec, ctx ); if( ffmpeg_OpenCodec( p_dec ) ) msg_Err( p_dec, "Cannot open decoder %s", p_sys->psz_namecodec ); } if( p_sys->b_delayed_open ) goto end; if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { avcodec_flush_buffers( ctx ); date_Set( &p_sys->end_date, 0 ); if( p_sys->i_codec_id == AV_CODEC_ID_MP2 || p_sys->i_codec_id == AV_CODEC_ID_MP3 ) p_sys->i_reject_count = 3; goto end; } /* We've just started the stream, wait for the first PTS. */ if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID ) goto end; if( p_block->i_buffer <= 0 ) goto end; if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 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; memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE ); p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED; } AVFrame frame; memset( &frame, 0, sizeof( frame ) ); for( int got_frame = 0; !got_frame; ) { if( p_block->i_buffer == 0 ) goto end; AVPacket pkt; av_init_packet( &pkt ); pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; int used = avcodec_decode_audio4( ctx, &frame, &got_frame, &pkt ); if( used < 0 ) { msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", p_block->i_buffer ); goto end; } assert( p_block->i_buffer >= (unsigned)used ); p_block->p_buffer += used; p_block->i_buffer -= used; } if( ctx->channels <= 0 || ctx->channels > 8 || ctx->sample_rate <= 0 ) { msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d", ctx->channels, ctx->sample_rate ); goto end; } if( p_dec->fmt_out.audio.i_rate != (unsigned int)ctx->sample_rate ) date_Init( &p_sys->end_date, ctx->sample_rate, 1 ); if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts > date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } if( p_block->i_buffer == 0 ) { /* Done with this buffer */ block_Release( p_block ); *pp_block = NULL; } /* NOTE WELL: Beyond this point, p_block now refers to the DECODED block */ p_block = frame.opaque; SetupOutputFormat( p_dec, true ); /* Silent unwanted samples */ if( p_sys->i_reject_count > 0 ) { memset( p_block->p_buffer, 0, p_block->i_buffer ); p_sys->i_reject_count--; } block_t *p_buffer = decoder_NewAudioBuffer( p_dec, p_block->i_nb_samples ); if (!p_buffer) return NULL; assert( p_block->i_nb_samples >= (unsigned)frame.nb_samples ); assert( p_block->i_nb_samples == p_buffer->i_nb_samples ); p_block->i_buffer = p_buffer->i_buffer; /* drop buffer padding */ /* Interleave audio if required */ if( av_sample_fmt_is_planar( ctx->sample_fmt ) ) { aout_Interleave( p_buffer->p_buffer, p_block->p_buffer, p_block->i_nb_samples, ctx->channels, p_dec->fmt_out.audio.i_format ); if( ctx->channels > AV_NUM_DATA_POINTERS ) free( frame.extended_data ); block_Release( p_block ); p_block = p_buffer; } else /* FIXME: improve decoder_NewAudioBuffer(), avoid useless buffer... */ block_Release( p_buffer ); if (p_sys->b_extract) { /* TODO: do not drop channels... at least not here */ p_buffer = block_Alloc( p_dec->fmt_out.audio.i_bytes_per_frame * frame.nb_samples ); if( unlikely(p_buffer == NULL) ) { block_Release( p_block ); return NULL; } aout_ChannelExtract( p_buffer->p_buffer, p_dec->fmt_out.audio.i_channels, p_block->p_buffer, ctx->channels, frame.nb_samples, p_sys->pi_extraction, p_dec->fmt_out.audio.i_bitspersample ); block_Release( p_block ); p_block = p_buffer; } p_block->i_nb_samples = frame.nb_samples; p_block->i_buffer = frame.nb_samples * p_dec->fmt_out.audio.i_bytes_per_frame; p_block->i_pts = date_Get( &p_sys->end_date ); p_block->i_length = date_Increment( &p_sys->end_date, frame.nb_samples ) - p_block->i_pts; return p_block; end: block_Release(p_block); *pp_block = NULL; return NULL; }
static int HandleMessage (demux_t *p_demux, mtrk_t *tr) { stream_t *s = p_demux->s; block_t *block; uint8_t first, event; unsigned datalen; if (stream_Seek (s, tr->offset) || (stream_Read (s, &first, 1) != 1)) return -1; event = (first & 0x80) ? first : tr->running_event; switch (event & 0xf0) { case 0xF0: /* System Exclusive */ switch (event) { case 0xF0: /* System Specific start */ case 0xF7: /* System Specific continuation */ { /* Variable length followed by SysEx event data */ int32_t len = ReadVarInt (s); if (len == -1) return -1; block = stream_Block (s, len); if (block == NULL) return -1; block = block_Realloc (block, 1, len); if (block == NULL) return -1; block->p_buffer[0] = event; goto send; } case 0xFF: /* SMF Meta Event */ if (HandleMeta (p_demux, tr)) return -1; /* We MUST NOT pass this event forward. It would be * confused as a MIDI Reset real-time event. */ goto skip; case 0xF1: case 0xF3: datalen = 1; break; case 0xF2: datalen = 2; break; case 0xF4: case 0xF5: /* We cannot handle undefined "common" (non-real-time) * events inside SMF, as we cannot differentiate a * one byte delta-time (< 0x80) from event data. */ default: datalen = 0; break; } break; case 0xC0: case 0xD0: datalen = 1; break; default: datalen = 2; break; } /* FIXME: one message per block is very inefficient */ block = block_New (p_demux, 1 + datalen); if (block == NULL) goto skip; block->p_buffer[0] = event; if (first & 0x80) { stream_Read (s, block->p_buffer + 1, datalen); } else { if (datalen == 0) { msg_Err (p_demux, "malformatted MIDI event"); return -1; /* can't use implicit running status with empty payload! */ } block->p_buffer[1] = first; if (datalen > 1) stream_Read (s, block->p_buffer + 2, datalen - 1); } send: block->i_dts = block->i_pts = VLC_TS_0 + date_Get (&p_demux->p_sys->pts); es_out_Send (p_demux->out, p_demux->p_sys->es, block); skip: if (event < 0xF8) /* If event is not real-time, update running status */ tr->running_event = event; tr->offset = stream_Tell (s); return 0; }
/***************************************************************************** * DecodeAudio: Called to decode one frame *****************************************************************************/ static block_t *DecodeAudio( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; AVCodecContext *ctx = p_sys->p_context; AVFrame *frame = NULL; if( !pp_block || !*pp_block ) return NULL; block_t *p_block = *pp_block; if( !ctx->extradata_size && p_dec->fmt_in.i_extra && p_sys->b_delayed_open) { InitDecoderConfig( p_dec, ctx ); OpenAudioCodec( p_dec ); } if( p_sys->b_delayed_open ) goto end; if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) { Flush( p_dec ); goto end; } if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) { date_Set( &p_sys->end_date, VLC_TS_INVALID ); } /* We've just started the stream, wait for the first PTS. */ if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID ) goto end; if( p_block->i_buffer <= 0 ) goto end; if( (p_block->i_flags & BLOCK_FLAG_PRIVATE_REALLOCATED) == 0 ) { p_block = block_Realloc( p_block, 0, p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE ); if( !p_block ) return NULL; *pp_block = p_block; p_block->i_buffer -= FF_INPUT_BUFFER_PADDING_SIZE; memset( &p_block->p_buffer[p_block->i_buffer], 0, FF_INPUT_BUFFER_PADDING_SIZE ); p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED; } frame = av_frame_alloc(); if (unlikely(frame == NULL)) goto end; for( int got_frame = 0; !got_frame; ) { if( p_block->i_buffer == 0 ) goto end; AVPacket pkt; av_init_packet( &pkt ); pkt.data = p_block->p_buffer; pkt.size = p_block->i_buffer; int ret = avcodec_send_packet( ctx, &pkt ); if( ret != 0 && ret != AVERROR(EAGAIN) ) { msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", p_block->i_buffer ); goto end; } int used = ret != AVERROR(EAGAIN) ? pkt.size : 0; ret = avcodec_receive_frame( ctx, frame ); if( ret != 0 && ret != AVERROR(EAGAIN) ) { msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", p_block->i_buffer ); goto end; } got_frame = ret == 0; p_block->p_buffer += used; p_block->i_buffer -= used; } if( ctx->channels <= 0 || ctx->channels > 8 || ctx->sample_rate <= 0 ) { msg_Warn( p_dec, "invalid audio properties channels count %d, sample rate %d", ctx->channels, ctx->sample_rate ); goto end; } if( p_dec->fmt_out.audio.i_rate != (unsigned int)ctx->sample_rate ) date_Init( &p_sys->end_date, ctx->sample_rate, 1 ); if( p_block->i_pts > date_Get( &p_sys->end_date ) ) { date_Set( &p_sys->end_date, p_block->i_pts ); } if( p_block->i_buffer == 0 ) { /* Done with this buffer */ block_Release( p_block ); p_block = NULL; *pp_block = NULL; } /* NOTE WELL: Beyond this point, p_block refers to the DECODED block! */ SetupOutputFormat( p_dec, true ); if( decoder_UpdateAudioFormat( p_dec ) ) goto drop; /* Interleave audio if required */ if( av_sample_fmt_is_planar( ctx->sample_fmt ) ) { p_block = block_Alloc(frame->linesize[0] * ctx->channels); if (unlikely(p_block == NULL)) goto drop; const void *planes[ctx->channels]; for (int i = 0; i < ctx->channels; i++) planes[i] = frame->extended_data[i]; aout_Interleave(p_block->p_buffer, planes, frame->nb_samples, ctx->channels, p_dec->fmt_out.audio.i_format); p_block->i_nb_samples = frame->nb_samples; av_frame_free(&frame); } else { p_block = vlc_av_frame_Wrap(frame); if (unlikely(p_block == NULL)) goto drop; frame = NULL; } if (p_sys->b_extract) { /* TODO: do not drop channels... at least not here */ block_t *p_buffer = block_Alloc( p_dec->fmt_out.audio.i_bytes_per_frame * p_block->i_nb_samples ); if( unlikely(p_buffer == NULL) ) goto drop; aout_ChannelExtract( p_buffer->p_buffer, p_dec->fmt_out.audio.i_channels, p_block->p_buffer, ctx->channels, p_block->i_nb_samples, p_sys->pi_extraction, p_dec->fmt_out.audio.i_bitspersample ); p_buffer->i_nb_samples = p_block->i_nb_samples; block_Release( p_block ); p_block = p_buffer; } /* Silent unwanted samples */ if( p_sys->i_reject_count > 0 ) { memset( p_block->p_buffer, 0, p_block->i_buffer ); p_sys->i_reject_count--; } p_block->i_buffer = p_block->i_nb_samples * p_dec->fmt_out.audio.i_bytes_per_frame; p_block->i_pts = date_Get( &p_sys->end_date ); p_block->i_length = date_Increment( &p_sys->end_date, p_block->i_nb_samples ) - p_block->i_pts; return p_block; end: *pp_block = NULL; drop: av_frame_free(&frame); if( p_block != NULL ) block_Release(p_block); return NULL; }
/***************************************************************************** * Resample: convert a buffer *****************************************************************************/ static block_t *Resample( filter_t * p_filter, block_t * p_in_buf ) { if( !p_in_buf || !p_in_buf->i_nb_samples ) { if( p_in_buf ) block_Release( p_in_buf ); return NULL; } filter_sys_t *p_sys = p_filter->p_sys; unsigned int i_out_rate = p_filter->fmt_out.audio.i_rate; int i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio ); /* Check if we really need to run the resampler */ if( i_out_rate == p_filter->fmt_in.audio.i_rate ) { if( !(p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) && p_sys->i_old_wing ) { /* output the whole thing with the samples from last time */ p_in_buf = block_Realloc( p_in_buf, p_sys->i_old_wing * p_filter->fmt_in.audio.i_bytes_per_frame, p_in_buf->i_buffer ); if( !p_in_buf ) return NULL; memcpy( p_in_buf->p_buffer, p_sys->p_buf + i_nb_channels * p_sys->i_old_wing, p_sys->i_old_wing * p_filter->fmt_in.audio.i_bytes_per_frame ); p_in_buf->i_nb_samples += p_sys->i_old_wing; p_in_buf->i_pts = date_Get( &p_sys->end_date ); p_in_buf->i_length = date_Increment( &p_sys->end_date, p_in_buf->i_nb_samples ) - p_in_buf->i_pts; } p_sys->i_old_wing = 0; p_sys->b_first = true; return p_in_buf; } unsigned i_bytes_per_frame = p_filter->fmt_out.audio.i_channels * p_filter->fmt_out.audio.i_bitspersample / 8; size_t i_out_size = i_bytes_per_frame * ( 1 + ( p_in_buf->i_nb_samples * p_filter->fmt_out.audio.i_rate / p_filter->fmt_in.audio.i_rate) ) + p_filter->p_sys->i_buf_size; block_t *p_out_buf = filter_NewAudioBuffer( p_filter, i_out_size ); if( !p_out_buf ) return NULL; float *p_out = (float *)p_out_buf->p_buffer; if( (p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) || p_sys->b_first ) { /* Continuity in sound samples has been broken, we'd better reset * everything. */ p_out_buf->i_flags |= BLOCK_FLAG_DISCONTINUITY; p_sys->i_remainder = 0; date_Init( &p_sys->end_date, i_out_rate, 1 ); date_Set( &p_sys->end_date, p_in_buf->i_pts ); p_sys->d_old_factor = 1; p_sys->i_old_wing = 0; p_sys->b_first = false; } int i_in_nb = p_in_buf->i_nb_samples; int i_in, i_out = 0; double d_factor, d_scale_factor, d_old_scale_factor; int i_filter_wing; #if 0 msg_Err( p_filter, "old rate: %i, old factor: %f, old wing: %i, i_in: %i", p_sys->i_old_rate, p_sys->d_old_factor, p_sys->i_old_wing, i_in_nb ); #endif /* Prepare the source buffer */ i_in_nb += (p_sys->i_old_wing * 2); float p_in_orig[i_in_nb * p_filter->fmt_in.audio.i_bytes_per_frame / 4], *p_in = p_in_orig; /* Copy all our samples in p_in */ if( p_sys->i_old_wing ) { vlc_memcpy( p_in, p_sys->p_buf, p_sys->i_old_wing * 2 * p_filter->fmt_in.audio.i_bytes_per_frame ); } /* XXX: why i_nb_channels instead of i_bytes_per_frame??? */ vlc_memcpy( p_in + p_sys->i_old_wing * 2 * i_nb_channels, p_in_buf->p_buffer, p_in_buf->i_nb_samples * p_filter->fmt_in.audio.i_bytes_per_frame ); block_Release( p_in_buf ); /* Make sure the output buffer is reset */ memset( p_out, 0, p_out_buf->i_buffer ); /* Calculate the new length of the filter wing */ d_factor = (double)i_out_rate / p_filter->fmt_in.audio.i_rate; i_filter_wing = ((SMALL_FILTER_NMULT+1)/2.0) * __MAX(1.0,1.0/d_factor) + 1; /* Account for increased filter gain when using factors less than 1 */ d_old_scale_factor = SMALL_FILTER_SCALE * p_sys->d_old_factor + 0.5; d_scale_factor = SMALL_FILTER_SCALE * d_factor + 0.5; /* Apply the old rate until we have enough samples for the new one */ i_in = p_sys->i_old_wing; p_in += p_sys->i_old_wing * i_nb_channels; for( ; i_in < i_filter_wing && (i_in + p_sys->i_old_wing) < i_in_nb; i_in++ ) { if( p_sys->d_old_factor == 1 ) { /* Just copy the samples */ memcpy( p_out, p_in, p_filter->fmt_in.audio.i_bytes_per_frame ); p_in += i_nb_channels; p_out += i_nb_channels; i_out++; continue; } while( p_sys->i_remainder < p_filter->fmt_out.audio.i_rate ) { if( p_sys->d_old_factor >= 1 ) { /* FilterFloatUP() is faster if we can use it */ /* Perform left-wing inner product */ FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in, p_out, p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, -1, i_nb_channels ); /* Perform right-wing inner product */ FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in + i_nb_channels, p_out, p_filter->fmt_out.audio.i_rate - p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, 1, i_nb_channels ); #if 0 /* Normalize for unity filter gain */ for( i = 0; i < i_nb_channels; i++ ) { *(p_out+i) *= d_old_scale_factor; } #endif /* Sanity check */ if( p_out_buf->i_buffer/p_filter->fmt_in.audio.i_bytes_per_frame <= (unsigned int)i_out+1 ) { p_out += i_nb_channels; i_out++; p_sys->i_remainder += p_filter->fmt_in.audio.i_rate; break; } } else { /* Perform left-wing inner product */ FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in, p_out, p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate, -1, i_nb_channels ); /* Perform right-wing inner product */ FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in + i_nb_channels, p_out, p_filter->fmt_out.audio.i_rate - p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate, 1, i_nb_channels ); } p_out += i_nb_channels; i_out++; p_sys->i_remainder += p_filter->fmt_in.audio.i_rate; } p_in += i_nb_channels; p_sys->i_remainder -= p_filter->fmt_out.audio.i_rate; } /* Apply the new rate for the rest of the samples */ if( i_in < i_in_nb - i_filter_wing ) { p_sys->d_old_factor = d_factor; p_sys->i_old_wing = i_filter_wing; } for( ; i_in < i_in_nb - i_filter_wing; i_in++ ) { while( p_sys->i_remainder < p_filter->fmt_out.audio.i_rate ) { if( d_factor >= 1 ) { /* FilterFloatUP() is faster if we can use it */ /* Perform left-wing inner product */ FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in, p_out, p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, -1, i_nb_channels ); /* Perform right-wing inner product */ FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in + i_nb_channels, p_out, p_filter->fmt_out.audio.i_rate - p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, 1, i_nb_channels ); #if 0 /* Normalize for unity filter gain */ for( int i = 0; i < i_nb_channels; i++ ) { *(p_out+i) *= d_old_scale_factor; } #endif /* Sanity check */ if( p_out_buf->i_buffer/p_filter->fmt_in.audio.i_bytes_per_frame <= (unsigned int)i_out+1 ) { p_out += i_nb_channels; i_out++; p_sys->i_remainder += p_filter->fmt_in.audio.i_rate; break; } } else { /* Perform left-wing inner product */ FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in, p_out, p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate, -1, i_nb_channels ); /* Perform right-wing inner product */ FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD, SMALL_FILTER_NWING, p_in + i_nb_channels, p_out, p_filter->fmt_out.audio.i_rate - p_sys->i_remainder, p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate, 1, i_nb_channels ); } p_out += i_nb_channels; i_out++; p_sys->i_remainder += p_filter->fmt_in.audio.i_rate; } p_in += i_nb_channels; p_sys->i_remainder -= p_filter->fmt_out.audio.i_rate; } /* Finalize aout buffer */ p_out_buf->i_nb_samples = i_out; p_out_buf->i_pts = date_Get( &p_sys->end_date ); p_out_buf->i_length = date_Increment( &p_sys->end_date, p_out_buf->i_nb_samples ) - p_out_buf->i_pts; p_out_buf->i_buffer = p_out_buf->i_nb_samples * i_nb_channels * sizeof(int32_t); /* Buffer i_filter_wing * 2 samples for next time */ if( p_sys->i_old_wing ) { size_t newsize = p_sys->i_old_wing * 2 * p_filter->fmt_in.audio.i_bytes_per_frame; if( newsize > p_sys->i_buf_size ) { free( p_sys->p_buf ); p_sys->p_buf = malloc( newsize ); if( p_sys->p_buf != NULL ) p_sys->i_buf_size = newsize; else { p_sys->i_buf_size = p_sys->i_old_wing = 0; /* oops! */ return p_out_buf; } } memcpy( p_sys->p_buf, p_in_orig + (i_in_nb - 2 * p_sys->i_old_wing) * i_nb_channels, (2 * p_sys->i_old_wing) * p_filter->fmt_in.audio.i_bytes_per_frame ); } #if 0 msg_Err( p_filter, "p_out size: %i, nb bytes out: %i", p_out_buf->i_buffer, i_out * p_filter->fmt_in.audio.i_bytes_per_frame ); #endif return p_out_buf; }