/* * split.c * * Copyright (C) Thomas Oestreich - January 2002 * * 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. * */ #include "transcode.h" #include "split.h" #define PMAX_BUF 1024 char split_cmd_buf[PMAX_BUF]; static int entries; typedef struct seq_s { int unit; long frame; int seq; int pseq; long offset; int foffset; } seq_t; static seq_t **seq=NULL; #define MAX_UNITS 128 static long uframe[MAX_UNITS]; static long unit_offset[MAX_UNITS]; #define debug_return {return(-1);} static int split_stream_core(const char *file, const char *source) { FILE *fd; FILE *tmp; char buffer[256]; int n=-1; if(file == NULL) { if(tc_snprintf(split_cmd_buf, PMAX_BUF, "tccat -i %s | tcdemux -W 2>/dev/null", source)<0) debug_return; // popen if((fd = popen(split_cmd_buf, "r"))== NULL) debug_return; tc_log_info(__FILE__, "generating auto-split information from file \"%s\"", source); // open temp. file tmp = tmpfile(); while ( fgets (buffer, 256, fd) ) { ++n; if ( fputs (buffer, tmp) < 0 ) debug_return; } pclose(fd); fd = tmp; } else { if((fd = fopen(file, "r"))==NULL) debug_return; tc_log_info(__FILE__, "reading auto-split information from file \"%s\"", file); // determine number of lines while (fgets (buffer, 256, fd)) { ++n; } } // need n+2 pointers???? seq = (seq_t **) malloc( (n+2) * sizeof(seq_t*)); if ( seq == NULL ) debug_return; n=-1; fseek (fd, 0, SEEK_SET); do { ++n; if((seq[n] = (seq_t *) malloc(sizeof(seq_t))) == NULL) debug_return; } while((fscanf(fd, "%d %ld %d %d %ld %d", &seq[n]->unit, &seq[n]->frame, &seq[n]->seq, &seq[n]->pseq, &seq[n]->offset, &seq[n]->foffset)!=EOF)); entries=n; if(seq[n]!=NULL) seq[n] = (seq_t *) malloc(sizeof(seq_t)); //add fake closing entry seq[n]->unit=seq[n-1]->unit+1; seq[n]->frame=seq[n-1]->frame=0; seq[n]->seq=seq[n-1]->seq+1; fclose(fd); return(0); } static long get_frame_index(int unit, long frame_inc) { //first entry is unique long n; int m; if(frame_inc==0) return(unit_offset[unit]); n=unit_offset[unit] + frame_inc; m=seq[n]->seq; while(seq[n]->unit == unit && n < entries && seq[n]->seq == m ) ++n; return(n); } //---------------------------------------------- // // main routine // //---------------------------------------------- int split_stream(vob_t *vob, const char *file, int this_unit, int *fa, int *fb, int opt_flag) { int n, unit_ctr=-1, last_unit=-1; int s1, s2, video=1; long max_frames=-1; int unit=0, foff=0; long _fa, _fb; long _n, frame_inc=0, poff=0; int startc, chunks; if(split_stream_core(file, ((vob->vob_chunk == vob->vob_chunk_max) ? vob->audio_in_file:vob->video_in_file))<0) { tc_log_error(__FILE__, "failed to read VOB navigation file %s", file); return(-1); } tc_log_info(__FILE__, "done reading %d entries", entries); //analyze data: for(n=0; nunit) { last_unit=seq[n]->unit; ++unit_ctr; unit_offset[unit_ctr]=n; } ++uframe[unit_ctr]; } for(n=0; n<=unit_ctr; ++n) { if(max_frames<=uframe[n]) { unit = n; max_frames = uframe[n]; } if(this_unit > unit_ctr) { if(verbose &TC_DEBUG) tc_log_msg(__FILE__, "invalid PSU %s", file); return(-1); } if(-1 < this_unit) unit = this_unit; if(verbose &TC_DEBUG) tc_log_msg(__FILE__, "unit=%d, frames=%ld, offset=%ld (%d)", n, uframe[n], unit_offset[n], vob->ps_unit); } // (II) determine largest (main) presentation unit if(verbose &TC_DEBUG) tc_log_msg(__FILE__, "selecting unit %d, frames=%ld, offset=%ld", unit, uframe[unit], unit_offset[unit]); // video or audio mode ? if((vob->vob_percentage) ? (vob->vob_chunk==vob->vob_chunk_max && vob->vob_chunk_max==100 ) : (vob->vob_chunk == vob->vob_chunk_max)) video=0; //check user error if(vob->vob_chunk_num2>vob->vob_chunk_max) vob->vob_chunk_num2=vob->vob_chunk_max; if(vob->vob_chunk_num1>vob->vob_chunk_max) vob->vob_chunk_num1=0; // determine number of chunks to process: (0.6.0pre5) if(video) { chunks = (vob->vob_percentage || vob->vob_chunk_num2==0) ? 1:vob->vob_chunk_num2-vob->vob_chunk_num1; startc = (vob->vob_percentage || vob->vob_chunk_num2==0) ? vob->vob_chunk:vob->vob_chunk_num1; } else { chunks = (vob->vob_percentage || vob->vob_chunk_num2==0) ? vob->vob_chunk_max:vob->vob_chunk_num2-vob->vob_chunk_num1; startc = (vob->vob_percentage || vob->vob_chunk_num2==0) ? 0:vob->vob_chunk_num1; } //--------------------------------------------------------------------- // (III) determine pack offset for given number of VOB chunks // Modified by CARON Dominique to optimize the // cluster mode // vob->vob_chunk = percentage of frames to skip before frames to encode // vob->vob_chunk_max = percentage of frames to encode frame_inc = (vob->vob_percentage) ? (long) ((startc * uframe[unit])/100) : (long) ((startc * uframe[unit])/vob->vob_chunk_max); if(verbose &TC_DEBUG) tc_log_msg(__FILE__, "estimated chunk offset = %ld", frame_inc); _n = get_frame_index(unit, frame_inc); poff = seq[_n]->offset; foff = seq[_n]->foffset; _fa = seq[_n]->frame; // parameter for option "-c" *fa = foff; *fb = foff - seq[_n]->frame; s1 = seq[_n]->seq; if(verbose &TC_DEBUG) tc_log_msg(__FILE__, "chunk %d starts at frame %ld, pack offset %ld, finc=%d", startc, _n, poff, foff); // (IV) determine end of chunk(s) // Modified by CARON Dominique to optimize the // cluster mode frame_inc = (vob->vob_percentage) ? (long) (((vob->vob_chunk+vob->vob_chunk_max) * uframe[unit])/100) : (long) (((startc+chunks) * uframe[unit])/vob->vob_chunk_max); _n = get_frame_index(unit, frame_inc); _fb = seq[_n]->frame; s2 = seq[_n]->seq; if(_fb==0) { _fb = uframe[unit]; *fb += uframe[unit]; } else { *fb += seq[_n]->frame; } // (V) set vob parameter vob->vob_offset = poff; vob->ps_unit = 0; vob->ps_seq1 = 0; vob->ps_seq2 = (s2==0 && _n) ? seq[_n-1]->seq-s1+3 : s2-s1+2; tc_log_msg(__FILE__, "chunk %d/%d PU=%d (-L 0 -c %ld-%ld) mapped onto (-L %ld -c %d-%d)", vob->vob_chunk, vob->vob_chunk_max-1, unit, _fa, _fb, poff, *fa, *fb); //--------------------------------------------------------------------- if(opt_flag==1) { //cluster mode if(video) { // no sound vob->amod_probed="null"; vob->has_audio=0; tc_log_info(__FILE__, "video mode"); } else { // no video vob->vmod_probed="null"; vob->has_video=0; vob->vob_offset = poff; vob->ps_unit = 0; tc_log_info(__FILE__, "audio mode"); } } //--------------------------------------------------------------------- if(seq != NULL) { // seq array not needed anymore for (n=0; n < entries+1; ++n) { free(seq[n]); } free(seq); } return(0); }