mirror of https://code.videolan.org/videolan/vlc
173 lines
5.5 KiB
C
173 lines
5.5 KiB
C
/*****************************************************************************
|
|
* uleaddvaudio.c
|
|
*****************************************************************************
|
|
* Copyright (C) 2012 Laurent Aimar
|
|
*
|
|
* Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <vlc_common.h>
|
|
#include <vlc_plugin.h>
|
|
#include <vlc_codec.h>
|
|
|
|
#include "../demux/rawdv.h"
|
|
|
|
/*****************************************************************************
|
|
* Module descriptor
|
|
*****************************************************************************/
|
|
static int Open(vlc_object_t *);
|
|
|
|
vlc_module_begin()
|
|
set_description(N_("Ulead DV audio decoder"))
|
|
set_capability("audio decoder", 50)
|
|
set_subcategory(SUBCAT_INPUT_ACODEC)
|
|
set_callback(Open)
|
|
vlc_module_end()
|
|
|
|
typedef struct
|
|
{
|
|
date_t end_date;
|
|
|
|
bool is_pal;
|
|
bool is_12bit;
|
|
uint16_t shuffle[2000];
|
|
} decoder_sys_t;
|
|
|
|
static void Flush(decoder_t *dec)
|
|
{
|
|
decoder_sys_t *sys = dec->p_sys;
|
|
|
|
date_Set(&sys->end_date, VLC_TICK_INVALID);
|
|
}
|
|
|
|
static block_t *DecodeBlock(decoder_t *dec, block_t **block_ptr)
|
|
{
|
|
decoder_sys_t *sys = dec->p_sys;
|
|
|
|
if (!*block_ptr)
|
|
return NULL;
|
|
|
|
block_t *block = *block_ptr;
|
|
if (block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
|
|
Flush(dec);
|
|
if (block->i_flags & BLOCK_FLAG_CORRUPTED) {
|
|
block_Release(block);
|
|
*block_ptr = NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (block->i_pts != VLC_TICK_INVALID &&
|
|
block->i_pts != date_Get(&sys->end_date))
|
|
date_Set(&sys->end_date, block->i_pts);
|
|
block->i_pts = VLC_TICK_INVALID;
|
|
if (date_Get(&sys->end_date) == VLC_TICK_INVALID) {
|
|
/* We've just started the stream, wait for the first PTS. */
|
|
block_Release(block);
|
|
return NULL;
|
|
}
|
|
|
|
const unsigned int block_size = sys->is_pal ? 8640 : 7200;
|
|
if (block->i_buffer >= block_size) {
|
|
uint8_t *src = block->p_buffer;
|
|
|
|
block->i_buffer -= block_size;
|
|
block->p_buffer += block_size;
|
|
|
|
int sample_count = dv_get_audio_sample_count(&src[244], sys->is_pal);
|
|
|
|
if( decoder_UpdateAudioFormat(dec))
|
|
return NULL;
|
|
block_t *output = decoder_NewAudioBuffer(dec, sample_count);
|
|
if (!output)
|
|
return NULL;
|
|
output->i_pts = date_Get(&sys->end_date);
|
|
output->i_length = date_Increment(&sys->end_date, sample_count) - output->i_pts;
|
|
|
|
int16_t *dst = (int16_t*)output->p_buffer;
|
|
for (int i = 0; i < sample_count; i++) {
|
|
const uint8_t *v = &src[sys->shuffle[i]];
|
|
if (sys->is_12bit) {
|
|
*dst++ = dv_audio_12to16((v[0] << 4) | ((v[2] >> 4) & 0x0f));
|
|
*dst++ = dv_audio_12to16((v[1] << 4) | ((v[2] >> 0) & 0x0f));
|
|
} else {
|
|
*dst++ = GetWBE(&v[0]);
|
|
*dst++ = GetWBE(&v[sys->is_pal ? 4320 : 3600]);
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
block_Release(block);
|
|
return NULL;
|
|
}
|
|
|
|
static int DecodeAudio(decoder_t *dec, block_t *block)
|
|
{
|
|
if (block == NULL) /* No Drain */
|
|
return VLCDEC_SUCCESS;
|
|
|
|
block_t **block_ptr = &block, *out;
|
|
while ((out = DecodeBlock(dec, block_ptr)) != NULL)
|
|
decoder_QueueAudio(dec,out);
|
|
return VLCDEC_SUCCESS;
|
|
}
|
|
|
|
static int Open(vlc_object_t *object)
|
|
{
|
|
decoder_t *dec = (decoder_t*)object;
|
|
|
|
if (dec->fmt_in->i_codec != VLC_CODEC_ULEAD_DV_AUDIO_NTSC &&
|
|
dec->fmt_in->i_codec != VLC_CODEC_ULEAD_DV_AUDIO_PAL)
|
|
return VLC_EGENERIC;
|
|
if (dec->fmt_in->audio.i_bitspersample != 12 && dec->fmt_in->audio.i_bitspersample != 16)
|
|
return VLC_EGENERIC;
|
|
if (dec->fmt_in->audio.i_channels != 2)
|
|
return VLC_EGENERIC;
|
|
if (dec->fmt_in->audio.i_rate <= 0)
|
|
return VLC_EGENERIC;
|
|
|
|
decoder_sys_t *sys = dec->p_sys = vlc_obj_malloc(object, sizeof(*sys));
|
|
if (!sys)
|
|
return VLC_ENOMEM;
|
|
|
|
sys->is_pal = dec->fmt_in->i_codec == VLC_CODEC_ULEAD_DV_AUDIO_PAL;
|
|
sys->is_12bit = dec->fmt_in->audio.i_bitspersample == 12;
|
|
|
|
date_Init(&sys->end_date, dec->fmt_in->audio.i_rate, 1);
|
|
|
|
for (unsigned i = 0; i < sizeof(sys->shuffle) / sizeof(*sys->shuffle); i++) {
|
|
const unsigned a = sys->is_pal ? 18 : 15;
|
|
const unsigned b = 3 * a;
|
|
sys->shuffle[i] = 80 * ((21 * (i % 3) + 9 * (i / 3) + ((i / a) % 3)) % b) +
|
|
(2 + sys->is_12bit) * (i / b) + 8;
|
|
}
|
|
|
|
dec->fmt_out.i_codec = VLC_CODEC_S16N;
|
|
dec->fmt_out.audio.i_rate = dec->fmt_in->audio.i_rate;
|
|
dec->fmt_out.audio.i_channels = 2;
|
|
dec->fmt_out.audio.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
|
|
|
|
dec->pf_decode = DecodeAudio;
|
|
dec->pf_flush = Flush;
|
|
|
|
return VLC_SUCCESS;
|
|
}
|