Video4LinuxContainerFile.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: Video4LinuxContainerFile.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include <string.h> 00045 00046 #include "Video4LinuxContainerFile.hpp" 00047 #include "ContainerInfo.hpp" 00048 #include "VideoESInfo.hpp" 00049 #include "AudioESInfo.hpp" 00050 #include "DataChannel.hpp" 00051 #include "DataSink.hpp" 00052 #include "Adaptor.hpp" 00053 #include "AdaptorChain.hpp" 00054 #include "MP3Parser.hpp" 00055 00056 #include "../adaptors/MP4Decoder.hpp" 00057 00058 #include "../io/DevNull.hpp" 00059 #include "../io/MPGStreamIO.hpp" 00060 00061 #include "../net/Url.hpp" 00062 #include "../net/SDP.hpp" 00063 #include <malloc.h> 00064 00065 /* This structure is there temporarily .... I know it looks ugly. 00066 will be removed when FFmpeg becomes consistent in providing 00067 all required parameters 00068 */ 00069 struct stInfo { 00070 CodecID codec_id; //eg. CODEC_ID_MPEG4==15,... 00071 float rate; //frame_rate for Video; sample_rate for audio 00072 long size; //size of Elementary Stream 00073 u32 packet_size; 00074 int totalSamples; //total samples in ES 00075 long avgBitRate; 00076 u32 bits_per_sample; //bits per sample of uncompressed wave frame (eg. 16) 00077 u32 channels; //audio only (eg. 2...stereo) 00078 u32 packetDuration; 00079 float duration; //duration of ES in ticks 00080 float test_duration; //used internally for calculation 00081 bool done; // -do- 00082 }; 00083 static stInfo strm[MAX_STREAMS]; 00084 00085 static AVFormatContext *input_files[MAX_STREAMS]; 00086 static int nb_input_files = 0; 00087 00088 //Some default values need to be declared here; 00089 static int frame_width = 720; 00090 static int frame_height = 576; 00091 static int frame_rate = 25; /*@ * FRAME_RATE_BASE;*/ 00092 static int frame_rate_base = 1; 00093 static int audio_sample_rate = 44100; 00094 static int audio_channels = 2; 00095 00096 static char *video_grab_format = "video4linux"; 00097 static char *video_device = NULL; 00098 static int video_channel = 0; 00099 static char *video_standard = "ntsc"; 00100 00101 static char *audio_grab_format = "audio_device"; 00102 static char *audio_device = NULL; 00103 00104 /**********************************************************/ 00108 ContainerInfo *Video4LinuxContainerFile::loadContainerInfo() { 00109 int streamcnt; 00110 00111 ContainerInfo * result = new ContainerInfo(NULL,"", ContainerInfo::MP4); 00112 00113 00114 dprintf_full("Video4LinuxContainerFile::loadContainerInfo\n"); 00115 00116 00117 AVInputFormat *viformat = NULL; 00118 AVInputFormat *aiformat = NULL; 00119 AVFormatContext **ic = (AVFormatContext**)malloc(2*sizeof(AVFormatContext**)); 00120 00121 AVFormatParameters vp1, *vp = &vp1; 00122 AVFormatParameters ap1, *ap = &ap1; 00123 00124 00125 // set some default parameters if required 00126 00127 memset(ap, 0, sizeof(*ap)); 00128 memset(vp, 0, sizeof(*vp)); 00129 00130 00131 ap->sample_rate = audio_sample_rate; 00132 ap->channels = audio_channels; 00133 // vp->frame_rate = frame_rate; 00134 vp->width = frame_width; 00135 vp->height = frame_height; 00136 vp->time_base = AV_TIME_BASE_Q; 00137 00138 00139 viformat = av_find_input_format(video_grab_format); 00140 00141 vp->device = video_device; 00142 vp->channel = video_channel; 00143 vp->standard = video_standard; 00144 00145 00146 //get video information 00147 00148 int ret; 00149 ret = av_open_input_file(&ic[0], "", viformat, 0, vp); 00150 00151 if(ret < 0) 00152 { 00153 //print_error(fileName, ret); 00154 dprintf_full("Video4LinuxContainerFile::loadContainerInfo : Error in opening file!!\n"); 00155 delete result; 00156 return NULL; 00157 } 00158 dprintf_full("Video4LinuxContainerFile::loadContainerInfo : av_open_input_file is ok\r\n"); 00159 00160 00161 // If not enough info to get the stream parameters, we decode the first frames to get it 00162 if ((ic[0]->ctx_flags & AVFMTCTX_NOHEADER) && av_find_stream_info(ic[0]) < 0) { 00163 dprintf("Could not find video grab parameters\n"); 00164 exit(1); 00165 } 00166 00167 00168 //ic[0]->streams[0]->r_frame_rate = vp->frame_rate; 00169 //ic[0]->streams[0]->r_frame_rate_base = vp->frame_rate_base; 00170 00171 00172 00173 input_files[nb_input_files] = ic[0]; 00174 dump_format(ic[0], nb_input_files, "", 0); 00175 nb_input_files++; 00176 00177 00178 00179 // get aufio information 00180 00181 /*aiformat = av_find_input_format(audio_grab_format); 00182 ap->device = audio_device; 00183 00184 if (av_open_input_file(&ic[1], "", aiformat, 0, ap) < 0) { 00185 dprintf("Could not find audio grab device\n"); 00186 exit(1); 00187 } 00188 input_files[nb_input_files] = ic[1]; 00189 //dump_format(ic[1], nb_input_files, "", 0); 00190 // 00191 00192 00193 ic[1]->streams[0]->r_frame_rate = ap->frame_rate; 00194 ic[1]->streams[0]->r_frame_rate_base = ap->frame_rate_base; 00195 input_files[nb_input_files] = ic[1]; 00196 dump_format(ic[1], nb_input_files, "", 0); 00197 00198 nb_input_files++; 00199 00200 dprintf("Ok upt to here\n"); 00201 */ 00202 00203 if (nb_input_files == 0) { 00204 dprintf_err("Video4LinuxContainerFile::loadFromffMP4ContainerFile couldn't find any ElemStreams in container!\n"); 00205 ::exit(1); 00206 } 00207 00208 unsigned int size = 0; 00209 for (int streamIndex = 0; streamIndex < nb_input_files; streamIndex++) 00210 { dprintf_full(">>>>>>>>ESINFOVCREATE: %d\n", streamIndex); 00211 ESInfo *es = Video4LinuxContainerFile::loadESInfo(ic[streamIndex], result,0); 00212 if (!es) { 00213 delete es; 00214 delete result; 00215 av_close_input_file(ic[streamIndex]); 00216 return NULL; 00217 } 00218 00219 dprintf_full("Video4LinuxContainerFile::loadFromffMP4ContainerFile creating ES %i\r\n", streamIndex); 00220 result->addESInfo(es); 00221 size += es->getOrigMediaSize(); 00222 dprintf_full("Video4LinuxContainerFile::loadFromffMP4ContainerFile creating ES %i done \n", streamIndex); 00223 00224 } 00225 00226 00227 00228 av_close_input_file(ic[0]); 00229 //av_close_input_file(ic[1]); 00230 dprintf_full("Video4LinuxContainerFile::loadFromffMP4ContainerFile all done \n"); 00231 return result; 00232 }; 00233 00234 00235 /**********************************************************/ 00236 ESInfo *Video4LinuxContainerFile::loadESInfo(AVFormatContext *ic, ContainerInfo *vob, int streamIndex) 00237 { 00238 //XXX currently some parameters for audio are set in MP4audioDecoder::initialize() 00239 //this is becaue ffmpeg fails to deliver the necessary information for audio. 00240 AVStream *st; 00241 st = ic->streams[streamIndex]; 00242 00243 00244 unsigned int streamId, handlerType, width, height, mediaTimeScale, totalSamples, mediaSize; 00245 unsigned int objectType=0, streamType=0, bufferSize=0, avgbit = 0, maxbit = 0; 00246 u64 duration = 0; 00247 float aspect_ratio = -1; 00248 00249 streamId = st->id; 00250 dprintf_full("ES Steamdek OK, %d %d\n",streamIndex, streamId); 00251 width = st->codec->width; 00252 height = st->codec->height; 00253 streamType = st->codec->codec_type; 00254 00255 00256 streamType = 0; 00257 strm[streamIndex].codec_id = CODEC_ID_RAWVIDEO; 00258 00259 printf("Streamtype: %d Codec ID: %d\n",streamType, /*strm[streamIndex].codec_id*/ st->codec->codec_type); 00260 00261 if(st->codec->sample_aspect_ratio.num == 0) 00262 aspect_ratio = (float)width / (float)height; 00263 else if (height != 0) 00264 aspect_ratio = aspect_ratio = av_q2d(st->codec->sample_aspect_ratio) * (float)width / (float)height; 00265 if (aspect_ratio <= 0) 00266 aspect_ratio = (float)width / (float)height; 00267 00268 handlerType = st->codec->codec_type; //video = 0; audio = 1; others = -1 00269 if(handlerType == 0) //FIXME set the #defines in global.hpp for ffmpeg and replace these lines 00270 handlerType = MP4VisualHandlerType; 00271 if(handlerType == 1) 00272 handlerType = MP4AudioHandlerType; 00273 00274 00275 mediaTimeScale = 90000; //FIXME: quickhack for divx 00276 00277 00278 strm[streamIndex].duration = 99999999; 00279 duration = strm[streamIndex].duration; 00280 strm[streamIndex].size = 99999999; 00281 totalSamples = 50000; 00282 00283 00284 mediaSize = strm[streamIndex].size; 00285 dprintf_full("Video4LinuxContainerFile: Ticks/sec %i Duration: %6.2f secs (ticks %li, samples %u) \n", 00286 mediaTimeScale, 00287 (float) ((float)(duration) / (float)(mediaTimeScale)), 00288 (long)duration, totalSamples ); 00289 int dcsize = 0; 00290 u8 *dptr = NULL; 00291 00292 u8 *encodedDecoderConfig = NULL; 00293 00294 00295 00296 //XXX some of these things are not set before passing 00297 if(handlerType == MP4VisualHandlerType) { 00298 avgbit = frame_width * frame_height * frame_rate * 12; 00299 maxbit = avgbit; 00300 dprintf_full("Video4LinuxContainerFile: VideoESInfo CodecID %i, ticks: %u\n", st->codec->codec_id, (unsigned)(duration/totalSamples)); 00301 return new VideoESInfo(streamId, streamType, vob, duration/totalSamples, encodedDecoderConfig, objectType, bufferSize, avgbit, maxbit, mediaTimeScale, duration, mediaSize, width, height, 00302 00303 true, true, strm[streamIndex].codec_id, st->quality, aspect_ratio); 00304 } 00305 else if(handlerType == MP4AudioHandlerType) { 00306 u32 channels = st->codec->channels; 00307 streamType = st->codec->codec_type; 00308 strm[streamIndex].codec_id = st->codec->codec_id; 00309 strm[streamIndex].bits_per_sample = st->codec->channels * st->codec->sample_rate * 16; 00310 avgbit = strm[streamIndex].bits_per_sample; 00311 dprintf_full("Video4LinuxContainerFile: AudioESInfo CodecID %i, %i Hz Channels: %i, ticks: %u, bitsPerSec %d:\n", 00312 st->codec->codec_id, st->codec->sample_rate, channels, (unsigned)(duration/totalSamples),strm[streamIndex].bits_per_sample ); 00313 return new AudioESInfo(streamId, streamType, vob, duration/totalSamples, 00314 encodedDecoderConfig, 00315 objectType, bufferSize, 00316 avgbit, maxbit, mediaTimeScale, duration, mediaSize, 00317 st->codec->sample_rate, channels, true, 00318 st->codec->codec_id, st->quality, strm[streamIndex].bits_per_sample); 00319 } 00320 return NULL; 00321 } 00322 00323