/*
* enc_output_filters
*
* Copyright (C) Peter Schlaile - Feb 2001
*
* This file is part of libdv, a free DV (IEC 61834/SMPTE 314M)
* codec.
*
* libdv is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser Public License as published by
* the Free Software Foundation; either version 2.1, or (at your
* option) any later version.
*
* libdv 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 Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with libdv; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The libdv homepage is http://libdv.sourceforge.net/.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "enc_audio_input.h"
#include "enc_output.h"
#include "headers.h"
FILE* out_fp = NULL;
static int raw_init(FILE* fp)
{
out_fp = fp;
return (fp == NULL) ? -1 : 0;
}
static void raw_finish()
{
}
static int dv_audio_unshuffle_60[5][9] = {
{ 0, 15, 30, 10, 25, 40, 5, 20, 35 },
{ 3, 18, 33, 13, 28, 43, 8, 23, 38 },
{ 6, 21, 36, 1, 16, 31, 11, 26, 41 },
{ 9, 24, 39, 4, 19, 34, 14, 29, 44 },
{12, 27, 42, 7, 22, 37, 2, 17, 32 },
};
static int dv_audio_unshuffle_50[6][9] = {
{ 0, 18, 36, 13, 31, 49, 8, 26, 44 },
{ 3, 21, 39, 16, 34, 52, 11, 29, 47 },
{ 6, 24, 42, 1, 19, 37, 14, 32, 50 },
{ 9, 27, 45, 4, 22, 40, 17, 35, 53 },
{ 12, 30, 48, 7, 25, 43, 2, 20, 38 },
{ 15, 33, 51, 10, 28, 46, 5, 23, 41 },
};
static void put_16_bit(unsigned char * target, unsigned char* wave_buf,
dv_enc_audio_info_t * audio, int dif_seg, int isPAL,
int channel)
{
int bp;
int audio_dif;
unsigned char* p = target;
if (isPAL) {
for (audio_dif = 0; audio_dif < 9; audio_dif++) {
for (bp = 8; bp < 80; bp += 2) {
int i = dv_audio_unshuffle_50[dif_seg]
[audio_dif] + (bp - 8)/2 * 54;
p[bp] = wave_buf[
audio->bytealignment * i
+ 2*channel];
p[bp + 1] = wave_buf[
audio->bytealignment * i + 1
+ 2*channel];
if (p[bp] == 0x80 && p[bp+1] == 0x00) {
p[bp+1] = 0x01;
}
}
p += 16 * 80;
}
} else {
for (audio_dif = 0; audio_dif < 9; audio_dif++) {
for (bp = 8; bp < 80; bp += 2) {
int i = dv_audio_unshuffle_60[dif_seg]
[audio_dif] + (bp - 8)/2 * 45;
p[bp] = wave_buf[
audio->bytealignment * i
+ 2*channel];
p[bp + 1] = wave_buf[
audio->bytealignment * i + 1
+ 2*channel];
if (p[bp] == 0x80 && p[bp+1] == 0x00) {
p[bp+1] = 0x01;
}
}
p += 16 * 80;
}
}
}
int _dv_raw_insert_audio(unsigned char * frame_buf,
dv_enc_audio_info_t * audio, int isPAL)
{
int dif_seg;
int dif_seg_max = isPAL ? 12 : 10;
int samplesperframe = audio->bytesperframe/(2*audio->channels);
int bits_per_sample = 16;
unsigned char* wave_buf = audio->data;
unsigned char head_50[5];
unsigned char head_51[5];
unsigned char head_52[5];
unsigned char head_53[5];
head_50[0] = 0x50;
if (isPAL) {
head_50[3] = /* stype = */ 0 | (/* isPAL */ 1 << 5)
| (/* ml */ 1 << 6) | (/* res */ 1 << 7);
switch(audio->frequency) {
case 32000:
if (audio->channels == 2) {
head_50[1] = (samplesperframe - 1264)
| (1 << 6) | (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0
| (/* pa = */ 0 << 4)
| (/* chn = */ 0 << 5)
| (/* sm = */ 0 << 7);
head_50[4] = /* 16 Bits */0
| (/* 32000 kHz */ 2 << 3)
| (/* tc = */ 1 << 6)
| (/* ef = */ 1 << 7);
} else {
head_50[1] = (samplesperframe - 1264)
| (1 << 6) | (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0
| (/* pa = */ 1 << 4)
| (/* chn = */ 1 << 5)
| (/* sm = */ 0 << 7);
head_50[4] = /* 12 Bits */1
| (/* 32000 kHz */ 2 << 3)
| (/* tc = */ 1 << 6)
| (/* ef = */ 1 << 7);
bits_per_sample = 12;
}
break;
case 44100:
head_50[1] = (samplesperframe - 1742) | (1 << 6)
| (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0 | (/* pa = */ 0 << 4)
| (/* chn = */ 0 << 5)
| (/* sm = */ 0 << 7);
head_50[4] = /* 16 Bits */0 | (/* 44100 kHz */ 1 << 3)
| (/* tc = */ 1 << 6) | (/* ef = */ 1 << 7);
break;
case 48000:
head_50[1] = (samplesperframe - 1896) | (1 << 6)
| (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0 | (/* pa = */ 0 << 4)
| (/* chn = */ 0 << 5);
head_50[4] = /* 16 Bits */0 | (/* 48000 kHz */ 0 << 3)
| (/* tc = */ 1 << 6) | (/* ef = */ 1 << 7);
break;
default:
fprintf(stderr, "Impossible frequency??\n");
return(-1);
}
} else {
head_50[3] = /* stype = */ 0 | (/* isPAL */ 0 << 5)
| (/* ml */ 1 << 6) | (/* res */ 1 << 7);
switch(audio->frequency) {
case 32000:
if (audio->channels == 2) {
head_50[1] = (samplesperframe - 1053)
| (1 << 6) | (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0
| (/* pa = */ 0 << 4)
| (/* chn = */ 0 << 5)
| (/* sm = */ 0 << 7);
head_50[4] = /* 16 Bits */0
| (/* 32000 kHz */ 2 << 3)
| (/* tc = */ 1 << 6)
| (/* ef = */ 1 << 7);
} else {
head_50[1] = (samplesperframe - 1053)
| (1 << 6) | (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0
| (/* pa = */ 1 << 4)
| (/* chn = */ 1 << 5)
| (/* sm = */ 0 << 7);
head_50[4] = /* 12 Bits */1
| (/* 32000 kHz */ 2 << 3)
| (/* tc = */ 1 << 6)
| (/* ef = */ 1 << 7);
bits_per_sample = 12;
}
break;
case 44100:
head_50[1] = (samplesperframe - 1452) | (1 << 6)
| (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0 | (/* pa = */ 0 << 4)
| (/* chn = */ 0 << 5)
| (/* sm = */ 0 << 7);
head_50[4] = /* 16 Bits */0 | (/* 44100 kHz */ 1 << 3)
| (/* tc = */ 1 << 6) | (/* ef = */ 1 << 7);
break;
case 48000:
head_50[1] = (samplesperframe - 1580) | (1 << 6)
| (/* unlocked = */ 1 << 7);
head_50[2] = /* audio_mode= */ 0 | (/* pa = */ 0 << 4)
| (/* chn = */ 0 << 5);
head_50[4] = /* 16 Bits */0 | (/* 48000 kHz */ 0 << 3)
| (/* tc = */ 1 << 6) | (/* ef = */ 1 << 7);
break;
default:
fprintf(stderr, "Impossible frequency??\n");
return(-1);
}
}
head_51[0] = 0x51; /* FIXME: What's this? */
head_51[1] = 0x33;
head_51[2] = 0xcf;
if ((frame_buf[4] & 0x7) == 0) /* IEC 61834? */
head_51[3] = 0xa0; /* forward, normal speed */
else if (isPAL) /* SMPTE 314M */
head_51[3] = 0x80 /* forward */ | 0x64 /* normal speed */;
else
head_51[3] = 0x80 /* forward */ | 0x78 /* normal speed */;
head_51[4] = 0xff;
head_52[0] = 0x52;
head_52[1] = frame_buf[5 * 80 + 48 + 2 * 5 + 1]; /* steal video */
head_52[2] = frame_buf[5 * 80 + 48 + 2 * 5 + 2]; /* timestamp */
head_52[3] = frame_buf[5 * 80 + 48 + 2 * 5 + 3]; /* this gets us an */
head_52[4] = frame_buf[5 * 80 + 48 + 2 * 5 + 4]; /* off by one error!*/
head_53[0] = 0x53;
head_53[1] = frame_buf[5 * 80 + 48 + 3 * 5 + 1];
head_53[2] = frame_buf[5 * 80 + 48 + 3 * 5 + 2];
head_53[3] = frame_buf[5 * 80 + 48 + 3 * 5 + 3];
head_53[4] = frame_buf[5 * 80 + 48 + 3 * 5 + 4];
for (dif_seg = 0; dif_seg < dif_seg_max; dif_seg++) {
int audio_dif;
unsigned char* target= frame_buf + dif_seg * 150 * 80 + 6 * 80;
int channel;
int ds;
unsigned char* p = target + 3;
for (audio_dif = 0; audio_dif < 9; audio_dif++) {
memset(p, 0xff, 5);
p += 16 * 80;
}
if ((dif_seg & 1) == 0) {
p = target + 3 * 16 * 80 + 3;
} else {
p = target + 3;
}
/* Timestamp it! */
memcpy(p + 0*16*80, head_50, 5);
memcpy(p + 1*16*80, head_51, 5);
memcpy(p + 2*16*80, head_52, 5);
memcpy(p + 3*16*80, head_53, 5);
if (dif_seg >= dif_seg_max/2) {
p[2] |= 1;
}
switch(bits_per_sample) {
case 12:
fprintf(stderr, "Unsupported bits: 12\n FIXME!\n");
return(-1);
case 16:
ds = dif_seg;
if(ds < dif_seg_max/2) {
channel = 0;
} else {
channel = 1;
ds -= dif_seg_max / 2;
}
put_16_bit(target, wave_buf,
audio, ds, isPAL, channel);
break;
}
}
return 0;
}
static int frame_counter = 0;
static int raw_store(unsigned char* encoded_data,
dv_enc_audio_info_t* audio_data,
int keep_meta_headers,
int isPAL, int is16x9, time_t now)
{
if (!keep_meta_headers) {
_dv_write_meta_data(encoded_data, frame_counter,
isPAL, is16x9, &now);
}
if (audio_data) {
int rval = _dv_raw_insert_audio(encoded_data, audio_data, isPAL);
if (rval) {
return rval;
}
}
fwrite(encoded_data, 1, isPAL ? 144000 : 120000, out_fp);
frame_counter++;
return 0;
}
static dv_enc_output_filter_t filters[DV_ENC_MAX_OUTPUT_FILTERS] = {
{ raw_init, raw_finish, raw_store, "raw" },
{ NULL, NULL, NULL, NULL }};
void dv_enc_register_output_filter(dv_enc_output_filter_t filter)
{
dv_enc_output_filter_t * p = filters;
while (p->filter_name) p++;
*p = filter;
}
int dv_enc_get_output_filters(dv_enc_output_filter_t ** filters_,
int * count)
{
dv_enc_output_filter_t * p = filters;
*count = 0;
while (p->filter_name) p++, (*count)++;
*filters_ = filters;
return 0;
}