1 /* 2 * export_pcm.c 3 * 4 * Copyright (C) Thomas Oestreich - May 2001 5 * 6 * This file is part of transcode, a video stream processing tool 7 * 8 * transcode is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2, or (at your option) 11 * any later version. 12 * 13 * transcode is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with GNU Make; see the file COPYING. If not, write to 20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 21 * 22 */ 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <errno.h> 28 29 #include "transcode.h" 30 #include "avilib/avilib.h" 31 #include "libtc/libtc.h" 32 33 #define MOD_NAME "export_pcm.so" 34 #define MOD_VERSION "v0.1.0 (2007-08-25)" 35 #define MOD_CODEC "(audio) PCM (non-interleaved)" 36 37 38 static int verbose_flag=TC_QUIET; 39 static int capability_flag=TC_CAP_PCM|TC_CAP_RGB|TC_CAP_YUV|TC_CAP_VID; 40 41 #define MOD_PRE tc_pcm 42 #include "export_def.h" 43 44 static struct wave_header rtf; 45 static int fd_r = -1, fd_l = -1, fd_c = -1; 46 static int fd_ls = -1, fd_rs = -1, fd_lfe = -1; 47 48 typedef enum { 49 CHANNEL_CENTER = 1, 50 CHANNEL_STEREO = 2, 51 CHANNEL_FRONT = 4, 52 CHANNEL_LFE = 8 53 } PCMChannels; 54 55 static PCMChannels chan_settings[8] = { 56 0, /* 0: nothing */ 57 CHANNEL_CENTER, /* 1: mono */ 58 CHANNEL_STEREO, /* 2: stereo */ 59 CHANNEL_STEREO|CHANNEL_CENTER, /* 3: 2.1 */ 60 CHANNEL_STEREO|CHANNEL_FRONT, /* 4: 2+2 */ 61 CHANNEL_STEREO|CHANNEL_FRONT|CHANNEL_CENTER, /* 5: 2+2+1 */ 62 CHANNEL_STEREO|CHANNEL_FRONT|CHANNEL_CENTER|CHANNEL_LFE, /* 6: 5.1 */ 63 0, /* nothing */ 64 }; 65 66 /* ------------------------------------------------------------ 67 * 68 * init codec 69 * 70 * ------------------------------------------------------------*/ 71 72 MOD_init 73 { 74 int rate; 75 76 if (param->flag == TC_VIDEO) { 77 return TC_EXPORT_OK; 78 } 79 if (param->flag == TC_AUDIO) { 80 memset(&rtf, 0, sizeof(rtf)); 81 82 strlcpy(rtf.riff.id, "RIFF", 4); 83 strlcpy(rtf.riff.wave_id, "WAVE", 4); 84 strlcpy(rtf.format.id, "fmt ", 4); 85 86 rtf.format.len = sizeof(struct common_struct); 87 rtf.common.wFormatTag = CODEC_PCM; 88 89 rate = (vob->mp3frequency != 0) ?vob->mp3frequency :vob->a_rate; 90 91 rtf.common.dwSamplesPerSec = rate; 92 rtf.common.dwAvgBytesPerSec = vob->dm_chan * rate * vob->dm_bits/8; 93 rtf.common.wBitsPerSample = vob->dm_bits; 94 rtf.common.wBlockAlign = vob->dm_chan*vob->dm_bits/8; 95 96 if(vob->dm_chan >= 1 && vob->dm_chan <= 6) { /* sanity check */ 97 rtf.common.wChannels=vob->dm_chan; 98 } else { 99 tc_log_error(MOD_NAME, "bad PCM channel number: %i", 100 vob->dm_chan); 101 return TC_EXPORT_ERROR; 102 } 103 if (!vob->a_codec_flag 104 || !rtf.common.dwSamplesPerSec 105 || !rtf.common.wBitsPerSample 106 || !rtf.common.wBlockAlign) { 107 tc_log_error(MOD_NAME, "cannot export PCM, invalid format " 108 "(no audio track at all?)"); 109 return TC_EXPORT_ERROR; 110 } 111 112 rtf.riff.len = 0x7FFFFFFF; 113 rtf.data.len = 0x7FFFFFFF; 114 115 strlcpy(rtf.data.id, "data",4); 116 117 return TC_EXPORT_OK; 118 } 119 // invalid flag 120 return TC_EXPORT_ERROR; 121 } 122 123 /* ------------------------------------------------------------ 124 * 125 * open outputfile 126 * 127 * ------------------------------------------------------------*/ 128 129 /* XXX */ 130 #define FD_OPEN(fd) do { \ 131 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, \ 132 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); \ 133 if (fd < 0) { \ 134 tc_log_error(MOD_NAME, "opening file: %s", strerror(errno)); \ 135 return TC_EXPORT_ERROR; \ 136 } \ 137 } while (0) 138 139 MOD_open 140 { 141 char fname[TC_BUF_LINE]; 142 int chan_flags = chan_settings[rtf.common.wChannels]; 143 144 if (param->flag == TC_AUDIO) { 145 if (chan_flags & CHANNEL_LFE) { 146 tc_snprintf(fname, sizeof(fname), "%s_lfe.pcm", 147 vob->audio_out_file); 148 FD_OPEN(fd_lfe); 149 } 150 151 if (chan_flags & CHANNEL_FRONT) { 152 tc_snprintf(fname, sizeof(fname), "%s_ls.pcm", 153 vob->audio_out_file); 154 FD_OPEN(fd_ls); 155 156 tc_snprintf(fname, sizeof(fname), "%s_rs.pcm", 157 vob->audio_out_file); 158 FD_OPEN(fd_rs); 159 } 160 161 if (chan_flags & CHANNEL_STEREO) { 162 tc_snprintf(fname, sizeof(fname), "%s_l.pcm", 163 vob->audio_out_file); 164 FD_OPEN(fd_l); 165 166 tc_snprintf(fname, sizeof(fname), "%s_r.pcm", 167 vob->audio_out_file); 168 FD_OPEN(fd_r); 169 } 170 171 if (chan_flags & CHANNEL_CENTER) { 172 tc_snprintf(fname, sizeof(fname), "%s_c.pcm", 173 vob->audio_out_file); 174 FD_OPEN(fd_c); 175 } 176 177 return TC_EXPORT_OK; 178 } 179 180 if (param->flag == TC_VIDEO) { 181 return TC_EXPORT_OK; 182 } 183 184 // invalid flag 185 return TC_EXPORT_ERROR; 186 } 187 188 /* ------------------------------------------------------------ 189 * 190 * encode and export 191 * 192 * ------------------------------------------------------------*/ 193 194 #define FD_WRITE(fd, buf, size) do { \ 195 if(fd != -1 && tc_pwrite(fd, buf, size) != size) { \ 196 tc_log_error(MOD_NAME, "writing audio frame: %s", \ 197 strerror(errno)); \ 198 return TC_EXPORT_ERROR; \ 199 } \ 200 } while (0) 201 202 MOD_encode 203 { 204 if (param->flag == TC_VIDEO) { 205 return TC_EXPORT_OK; 206 } 207 if (param->flag == TC_AUDIO) { 208 int size = (int)(param->size/rtf.common.wChannels); 209 210 switch (rtf.common.wChannels) { 211 case 6: 212 FD_WRITE(fd_rs, param->buffer + 5 * size, size); 213 FD_WRITE(fd_ls, param->buffer + 4 * size, size); 214 FD_WRITE(fd_r, param->buffer + 3 * size, size); 215 FD_WRITE(fd_c, param->buffer + 2 * size, size); 216 FD_WRITE(fd_l, param->buffer + size, size); 217 FD_WRITE(fd_lfe, param->buffer, size); 218 break; 219 220 case 2: 221 FD_WRITE(fd_r, param->buffer + size, size); 222 FD_WRITE(fd_l, param->buffer, size); 223 break; 224 225 case 1: 226 FD_WRITE(fd_c, param->buffer, size); 227 break; 228 } 229 230 return TC_EXPORT_OK; 231 } 232 233 // invalid flag 234 return TC_EXPORT_ERROR; 235 } 236 237 /* ------------------------------------------------------------ 238 * 239 * close outputfiles 240 * 241 * ------------------------------------------------------------*/ 242 243 #define FD_CLOSE(fd) do { \ 244 if (fd != -1) { \ 245 close(fd);\ 246 } \ 247 } while (0) 248 249 MOD_close 250 { 251 if (param->flag == TC_VIDEO) { 252 return TC_EXPORT_OK; 253 } 254 if (param->flag == TC_AUDIO) { 255 FD_CLOSE(fd_l); 256 FD_CLOSE(fd_c); 257 FD_CLOSE(fd_r); 258 FD_CLOSE(fd_ls); 259 FD_CLOSE(fd_rs); 260 FD_CLOSE(fd_lfe); 261 return TC_EXPORT_OK; 262 } 263 return TC_EXPORT_ERROR; 264 } 265 266 /* ------------------------------------------------------------ 267 * 268 * stop encoder 269 * 270 * ------------------------------------------------------------*/ 271 272 MOD_stop 273 { 274 if (param->flag == TC_VIDEO) { 275 return TC_EXPORT_OK; 276 } 277 if (param->flag == TC_AUDIO) { 278 return TC_EXPORT_OK; 279 } 280 return TC_EXPORT_ERROR; 281 } 282 283 /*************************************************************************/ 284 285 /* 286 * Local variables: 287 * c-file-style: "stroustrup" 288 * c-file-offsets: ((case-label . *) (statement-case-intro . *)) 289 * indent-tabs-mode: nil 290 * End: 291 * 292 * vim: expandtab shiftwidth=4: 293 */ 294