You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
13 KiB

/*
* import_mov.c
*
* Copyright (C) Thomas Oestreich - January 2002
* updated by Christian Vogelgsang <Vogelgsang@informatik.uni-erlangen.de>
*
* This file is part of transcode, a video stream processing tool
*
* transcode is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* transcode 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#define MOD_NAME "import_mov.so"
#define MOD_VERSION "v0.1.3 (2005-12-04)"
#define MOD_CODEC "(video) * | (audio) *"
#include "transcode.h"
#include "../src/filter.h"
static int verbose_flag = TC_QUIET;
static int capability_flag = TC_CAP_PCM | TC_CAP_RGB | TC_CAP_YUV |
TC_CAP_YUV422 | TC_CAP_VID;
#define MOD_PRE mov
#include "import_def.h"
#include <quicktime.h>
#include <colormodels.h>
#include <lqt.h>
#include "magic.h"
#include "aclib/imgconvert.h"
/* movie handles */
static quicktime_t *qt_audio=NULL;
static quicktime_t *qt_video=NULL;
/* row pointer for decode frame */
static unsigned char **row_ptr = NULL;
/* raw or decode frame */
static int rawVideoMode = 0;
/* raw or decode audio */
static int rawAudioMode = 0;
/* frame size */
static int w=0, h=0;
/* number of audio channels */
static int chan=0;
/* number of audio bits */
static int bits=0;
/* number of frames */
static int frames=0;
/* number of audio samples */
static int no_samples=0;
/* import colormodel */
static int qt_cm = 0;
/* ------------------------------------------------------------
*
* open stream
*
* ------------------------------------------------------------*/
MOD_open
{
/* audio */
if(param->flag == TC_AUDIO) {
int numTrk;
long rate;
char *codec;
param->fd = NULL;
/* open movie for audio extraction */
if(qt_audio==NULL) {
if(NULL == (qt_audio = quicktime_open((char *)vob->audio_in_file,1,0))){
tc_log_warn(MOD_NAME, "can't open quicktime!");
return(TC_IMPORT_ERROR);
}
}
/* check for audio track */
numTrk = quicktime_audio_tracks(qt_audio);
if(numTrk==0) {
tc_log_warn(MOD_NAME, "AUDIO: --no audio track in quicktime found --");
no_samples=0;
return(TC_IMPORT_OK);
}
/* extract audio parameters */
rate = quicktime_sample_rate(qt_audio, 0);
chan = quicktime_track_channels(qt_audio, 0);
bits = quicktime_audio_bits(qt_audio, 0);
codec = quicktime_audio_compressor(qt_audio, 0);
/* The total frames */
no_samples=quicktime_audio_length(qt_audio, 0);
/* verbose info */
tc_log_info(MOD_NAME, "codec=%s, rate=%ld Hz, bits=%d,"
" channels=%d, samples=%d",
codec, rate, bits, chan, no_samples);
/* check bits */
if((bits!=8)&&(bits!=16)) {
tc_log_warn(MOD_NAME, "unsupported sample bits: %d",bits);
return(TC_IMPORT_ERROR);
}
/* check channels */
if(chan>2) {
tc_log_warn(MOD_NAME, "too many audio channels: %d",chan);
return(TC_IMPORT_ERROR);
}
/* check codec string */
if(strlen(codec)==0) {
tc_log_warn(MOD_NAME, "empty codec in quicktime?");
return(TC_IMPORT_ERROR);
}
/* check if audio compressor is supported */
if(quicktime_supported_audio(qt_audio, 0)!=0) {
rawAudioMode = 0;
}
#if !defined(LIBQUICKTIME_000904)
/* RAW PCM is directly supported */
else if(strcasecmp(codec,QUICKTIME_RAW)==0) {
rawAudioMode = 1;
tc_log_warn(MOD_NAME, "using RAW audio mode!");
}
#endif
/* unsupported codec */
else {
tc_log_warn(MOD_NAME, "quicktime audio codec '%s' not supported!",
codec);
return(TC_IMPORT_ERROR);
}
return(TC_IMPORT_OK);
}
/* video */
if(param->flag == TC_VIDEO) {
double fps;
char *codec;
int numTrk;
param->fd = NULL;
/* open movie for video extraction */
if(qt_video==NULL)
if(NULL == (qt_video = quicktime_open((char *)vob->video_in_file,1,0))){
tc_log_warn(MOD_NAME,"can't open quicktime!");
return(TC_IMPORT_ERROR);
}
/* check for audio track */
numTrk = quicktime_video_tracks(qt_video);
if(numTrk==0) {
tc_log_warn(MOD_NAME,"no video track in quicktime found!");
return(TC_IMPORT_ERROR);
}
/* read all video parameter from input file */
w = quicktime_video_width(qt_video, 0);
h = quicktime_video_height(qt_video, 0);
fps = quicktime_frame_rate(qt_video, 0);
codec = quicktime_video_compressor(qt_video, 0);
//ThOe total frames
frames=quicktime_video_length(qt_video, 0);
/* verbose info */
tc_log_info(MOD_NAME, "VIDEO: codec=%s, fps=%6.3f, width=%d,"
" height=%d, frames=%d",
codec, fps, w, h, frames);
/* check codec string */
if(strlen(codec)==0) {
tc_log_warn(MOD_NAME, "empty codec in quicktime?");
return(TC_IMPORT_ERROR);
}
/* check if a suitable compressor is available */
if(quicktime_supported_video(qt_video,0)==0) {
tc_log_warn(MOD_NAME, "quicktime codec '%s'"
" not supported for RGB!",
codec);
return(TC_IMPORT_ERROR);
}
/* set color model */
switch(vob->im_v_codec) {
case CODEC_RGB:
/* use raw mode when possible */
/* not working ?*/
/*if (strcmp(qt_codec, "raw ")) rawVideo=1; */
/* allocate buffer for row pointers */
row_ptr = tc_malloc(h*sizeof(char *));
if(row_ptr==0) {
tc_log_error(MOD_NAME,"can't alloc row pointers");
return(TC_IMPORT_ERROR);
}
quicktime_set_cmodel(qt_video, BC_RGB888); qt_cm = BC_RGB888;
break;
case CODEC_YUV:
/* use raw mode when possible */
/* not working ?*/
/* if (strcmp(qt_codec, "yv12")) rawVideo=1; */
/* allocate buffer for row pointers */
row_ptr = tc_malloc(3*sizeof(char *));
if(row_ptr==0) {
tc_log_error(MOD_NAME,"can't alloc row pointers");
return(TC_IMPORT_ERROR);
}
if (!quicktime_reads_cmodel(qt_video, BC_YUV420P, 0)) {
if (quicktime_reads_cmodel(qt_video, BC_YUVJ420P, 0)) {
/* stolen from import_ffmpeg */
/* load levels filter */
if (!tc_filter_add("levels", "output=16-240:pre=1")) {
tc_log_warn(MOD_NAME, "cannot load levels filter. Try -V rgb24.");
}
quicktime_set_cmodel(qt_video, BC_YUVJ420P);
} else {
tc_log_error(MOD_NAME,"unable to handle colormodel. Try -V rgb24.");
return(TC_IMPORT_ERROR);
}
} else {
quicktime_set_cmodel(qt_video, BC_YUV420P);
}
qt_cm = BC_YUV420P;
break;
case CODEC_YUV422:
/* allocate buffer for row pointers */
row_ptr = tc_malloc(3*sizeof(char *));
if(row_ptr==0) {
tc_log_error(MOD_NAME,"can't alloc row pointers");
return(TC_IMPORT_ERROR);
}
if (!quicktime_reads_cmodel(qt_video, BC_YUV422P, 0)) {
tc_log_error(MOD_NAME,"unable to handle colormodel. Try -V rgb24.");
return(TC_IMPORT_ERROR);
}
quicktime_set_cmodel(qt_video, BC_YUV422P); qt_cm = BC_YUV422P;
break;
case CODEC_YUY2:
quicktime_set_cmodel(qt_video, BC_YUV422); qt_cm = BC_YUV422;
break;
/* passthrough */
case CODEC_RAW_RGB:
case CODEC_RAW_YUV:
case CODEC_RAW:
rawVideoMode = 1;
break;
default:
/* unsupported internal format */
tc_log_warn(MOD_NAME,"unsupported internal video format %x",
vob->ex_v_codec);
return(TC_EXPORT_ERROR);
break;
}
return(TC_IMPORT_OK);
}
return(TC_IMPORT_ERROR);
}
/* ------------------------------------------------------------
*
* decode stream
*
* ------------------------------------------------------------*/
MOD_decode
{
/* video */
if(param->flag == TC_VIDEO) {
if(rawVideoMode) {
/* read frame raw */
param->size = quicktime_read_frame(qt_video, param->buffer, 0);
if(param->size<=0) {
if(verbose & TC_DEBUG)
tc_log_warn(MOD_NAME,"quicktime read video frame");
return(TC_IMPORT_ERROR);
}
} else {
/* decode frame */
unsigned char *mem = param->buffer;
int iy,sl;
switch(qt_cm) {
case BC_RGB888:
/* setup row pointers for RGB: inverse! */
sl = w*3;
for(iy=0;iy<h;iy++){
row_ptr[iy] = mem;
mem += sl;
}
param->size = (h*w) * 3;
break;
case BC_YUV420P: {
/* setup row pointers for YUV420P */
YUV_INIT_PLANES(row_ptr, mem, IMG_YUV420P, h, w);
param->size = (h*w*3)/2;
break;
}
case BC_YUV422P: {
/* setup row pointers for YUV422P */
YUV_INIT_PLANES(row_ptr, mem, IMG_YUV422P, h, w);
param->size = (h*w)*2;
break;
}
}
/* decode the next frame */
if(lqt_decode_video(qt_video,row_ptr,0)<0) {
if(verbose & TC_DEBUG)
tc_log_warn(MOD_NAME,"can't decode frame");
return(TC_IMPORT_ERROR);
}
}
//ThOe trust file header and terminate after all frames have been processed.
if(frames--==0) return(TC_IMPORT_ERROR);
return(TC_IMPORT_OK);
}
/* audio */
if(param->flag == TC_AUDIO) {
int bytes_read;
/* Leave if audio track is empty */
if (no_samples==0){
param->size=0;
return(TC_IMPORT_OK);
}
/* raw read mode */
#if !defined(LIBQUICKTIME_000904)
if(rawAudioMode) {
bytes_read = quicktime_read_audio(qt_audio,
param->buffer, param->size, 0);
} else
#endif
{
/* decode audio mode */
long pos = quicktime_audio_position(qt_audio,0);
long samples = param->size;
if(bits==16)
samples >>= 1;
/* mono */
if(chan==1) {
/* direct copy */
bytes_read = quicktime_decode_audio(qt_audio,
(int16_t *)param->buffer,NULL,
samples,0);
/* check result */
if(bytes_read<0) {
if(verbose & TC_DEBUG)
tc_log_warn(MOD_NAME,"reading quicktime audio frame!");
return(TC_IMPORT_ERROR);
}
}
/* stereo */
else {
int16_t *tgt;
int16_t *tmp;
int s,t;
samples >>= 1;
tgt = (int16_t *)param->buffer;
tmp = tc_malloc(samples*sizeof(int16_t));
/* read first channel into target buffer */
bytes_read = quicktime_decode_audio(qt_audio,tgt,NULL,samples,0);
if(bytes_read<0) {
if(verbose & TC_DEBUG)
tc_log_warn(MOD_NAME,"reading quicktime audio frame!");
return(TC_IMPORT_ERROR);
}
/* read second channel in temp buffer */
quicktime_set_audio_position(qt_audio,pos,0);
bytes_read = quicktime_decode_audio(qt_audio,tmp,NULL,samples,1);
if(bytes_read<0) {
if(verbose & TC_DEBUG)
tc_log_warn(MOD_NAME,"reading quicktime audio frame!");
return(TC_IMPORT_ERROR);
}
/* spread first channel */
for(s=samples-1;s>=0;s--)
tgt[s<<1] = tgt[s];
/* fill in second channel from temp buffer */
t = 1;
for(s=0;s<samples;s++) {
tgt[t] = tmp[s];
t += 2;
}
free(tmp);
}
quicktime_set_audio_position(qt_audio,pos+samples,0);
}
return(TC_IMPORT_OK);
}
return(TC_IMPORT_ERROR);
}
/* ------------------------------------------------------------
*
* close stream
*
* ------------------------------------------------------------*/
MOD_close
{
/* free up audio */
if(param->flag == TC_AUDIO) {
if(qt_audio!=NULL) {
quicktime_close(qt_audio);
qt_audio=NULL;
}
return(TC_IMPORT_OK);
}
/* free up video */
if(param->flag == TC_VIDEO) {
if(qt_video!=NULL) {
quicktime_close(qt_video);
qt_video=NULL;
}
/* free row pointer */
if(row_ptr!=0)
free(row_ptr);
return(TC_IMPORT_OK);
}
return(TC_IMPORT_ERROR);
}