summaryrefslogtreecommitdiffstats
path: root/libmpcodecs/ad_ra1428.c
blob: 56dbdda39472adcb5614caaff68cffe42abc4158 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SAMPLE audio decoder - you can use this file as template when creating new codec!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "config.h"
#include "ad_internal.h"

static ad_info_t info =  {
	"RealAudio 1.0 and 2.0 native decoder",
	"ra1428",
	"Roberto Togni",
	"http://www.honeypot.net/audio",
	"Decoders taken from a public domain Amiga player"
};

LIBAD_EXTERN(ra1428)

#include "native/common1428.h"



static int preinit(sh_audio_t *sh) {
  sh->samplerate=sh->wf->nSamplesPerSec;
  sh->samplesize=sh->wf->wBitsPerSample/8;
  sh->channels=sh->wf->nChannels;
  sh->sample_format=AFMT_S16_LE;

	switch (sh->format) {
		case mmioFOURCC('1','4','_','4'):
			mp_msg(MSGT_DECAUDIO,MSGL_INFO,"[ra1428] RealAudio 1.0 (14_4)\n");
		  sh->i_bps=1800;
		  break;
		case mmioFOURCC('2','8','_','8'):
			mp_msg(MSGT_DECAUDIO,MSGL_INFO,"[ra1428] RealAudio 2.0 (28_8)\n");
	  	sh->i_bps=1200;
	  	break;
		default:
			mp_msg(MSGT_DECAUDIO,MSGL_ERR,"[ra1428] Unhandled format in preinit: %x\n", sh->format);
			return 0;
	}
  
  sh->audio_out_minsize=128000; // no idea how to get... :(
  sh->audio_in_minsize=((short*)(sh->wf+1))[1]*sh->wf->nBlockAlign;

  return 1; // return values: 1=OK 0=ERROR
}



static int init(sh_audio_t *sh) {
	switch (sh->format) {
		case mmioFOURCC('1','4','_','4'):
			sh->context = init_144();
		  break;
		case mmioFOURCC('2','8','_','8'):
			sh->context = init_288();
	  	break;
		default:
			mp_msg(MSGT_DECAUDIO,MSGL_ERR,"[ra1428] Unhandled format in init: %x\n", sh->format);
			return 0;
	}

  return 1; // return values: 1=OK 0=ERROR
}



static void uninit(sh_audio_t *sh) {
	switch (sh->format) {
		case mmioFOURCC('1','4','_','4'):
			free_144((Real_144*)sh->context);
		  break;
		case mmioFOURCC('2','8','_','8'):
			free_288((Real_288*)sh->context);
	  	break;
		default:
			mp_msg(MSGT_DECAUDIO,MSGL_ERR,"[ra1428] Unhandled format in uninit: %x\n", sh->format);
			return;
	}
}



static int decode_audio(sh_audio_t *sh,unsigned char *buf,int minlen,int maxlen) {
  int w=sh->wf->nBlockAlign;
  int h=((short*)(sh->wf+1))[1];
  int cfs=((short*)(sh->wf+1))[3];
	int i,j;

  if(sh->a_in_buffer_len<=0){
		switch (sh->format) {
			case mmioFOURCC('1','4','_','4'):
				demux_read_data(sh->ds, sh->a_in_buffer, sh->wf->nBlockAlign);
				sh->a_in_buffer_size=
				sh->a_in_buffer_len=sh->wf->nBlockAlign;
		 	 break;
			case mmioFOURCC('2','8','_','8'):
				for (j = 0; j < h; j++)
					for (i = 0; i < h/2; i++)
						demux_read_data(sh->ds, sh->a_in_buffer+i*2*w+j*cfs, cfs);
				sh->a_in_buffer_size=
				sh->a_in_buffer_len=sh->wf->nBlockAlign*h;
	 	 	break;
			default:
				mp_msg(MSGT_DECAUDIO,MSGL_ERR,"[ra1428] Unhandled format in decode_audio: %x\n", sh->format);
				return 0;
		}
	}
	
	switch (sh->format) {
		case mmioFOURCC('1','4','_','4'):
			decode_144((Real_144*)sh->context,sh->a_in_buffer+sh->a_in_buffer_size-sh->a_in_buffer_len,(signed short*)buf);
		  break;
		case mmioFOURCC('2','8','_','8'):
			decode_288((Real_288*)sh->context,sh->a_in_buffer+sh->a_in_buffer_size-sh->a_in_buffer_len,(signed short*)buf);
	  	break;
		default:
			mp_msg(MSGT_DECAUDIO,MSGL_ERR,"[ra1428] Unhandled format in init: %x\n", sh->format);
			return 0;
	}

  sh->a_in_buffer_len-=cfs;

  return AUDIOBLOCK*2; // return value: number of _bytes_ written to output buffer,
              // or -1 for EOF (or uncorrectable error)
}

static int control(sh_audio_t *sh,int cmd,void* arg, ...){
    // various optional functions you MAY implement:
    switch(cmd){
      case ADCTRL_RESYNC_STREAM:
        // it is called once after seeking, to resync.
	// Note: sh_audio->a_in_buffer_len=0; is done _before_ this call!
//	...
	return CONTROL_TRUE;
      case ADCTRL_SKIP_FRAME:
        // it is called to skip (jump over) small amount (1/10 sec or 1 frame)
	// of audio data - used to sync audio to video after seeking
	// if you don't return CONTROL_TRUE, it will defaults to:
	//      ds_fill_buffer(sh_audio->ds);  // skip 1 demux packet
//	...
	return CONTROL_TRUE;
    }
  return CONTROL_UNKNOWN;
}