1 /******************************************************************************
2 * FOBS C++ wrapper code
3 * Copyright (c) 2004 Omnividea Multimedia S.L
4 * Coded by Jose San Pedro Wandelmer
6 * This file is part of FOBS.
8 * FOBS is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as
10 * published by the Free Software Foundation; either version 2.1
11 * of the License, or (at your option) any later version.
13 * FOBS 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 Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FOBS; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ******************************************************************************/
26 #include "libavformat/avformat.h"
27 #include "libavcodec/avcodec.h"
28 #include "libswscale/swscale.h"
31 #include "Transcoder.h"
32 #include "PacketBuffer.h"
34 #include <cstring> // strdup
35 #include <cstdlib> // free
39 using namespace omnividea::fobs
;
41 static Decoder
iDecoder("");
43 Transcoder::Transcoder(char *fIn
, char *fOut
)
46 this->fIn
= strdup(fIn
);
47 this->fOut
= strdup(fOut
);
48 vWidth
= -1; //from Input
49 vHeight
= -1; //from Input
50 vBitRate
= 0.0; //from Input
51 vFrameRate
= 0.0; //from Input
53 aSamplesPerSec
= -1; //from Input
54 aChannels
= -1; //from Input
55 aBitRate
= 0.0; //from Input
57 vCodec
= NULL
; //from Input
58 aCodec
= NULL
; //from Input
59 mFormat
= NULL
; //from Input
61 customVideoSettings
= false;
62 customAudioSettings
= false;
66 e
= new Encoder(fOut
);
70 Transcoder::~Transcoder()
74 if(vCodec
) free(vCodec
);
75 if(aCodec
) free(aCodec
);
76 if(mFormat
) free(mFormat
);
84 ReturnCode
Transcoder::chooseVideoCodec(int width
, int height
, double bitRate
, double frameRate
, char *fcc
)
89 vFrameRate
= frameRate
;
90 if(vCodec
) free(vCodec
);
91 if(fcc
) vCodec
= strdup(fcc
);
93 customVideoSettings
= true;
96 ReturnCode
Transcoder::chooseAudioCodec(int samplesPerSec
, int channels
, double bitRate
, char *fcc
)
98 aSamplesPerSec
= samplesPerSec
;
101 if(aCodec
) free(aCodec
);
102 if(fcc
) aCodec
= strdup(fcc
);
104 customAudioSettings
= true;
108 ReturnCode
Transcoder::chooseFormat(char *fcc
)
110 if(mFormat
) free(mFormat
);
111 if(fcc
)mFormat
= strdup(fcc
);
113 e
->chooseFormat(fcc
);
117 ReturnCode
Transcoder::transcode()
119 ReturnCode error
= OkCode
;
123 d
->setAudioResampleFlag(true);
128 if(customVideoSettings
)
130 error
= e
->setVideoParameters(vWidth
, vHeight
, vBitRate
, vFrameRate
, vCodec
);
134 error
= e
->setVideoParameters(d
);
139 if(customAudioSettings
)
141 error
= e
->setAudioParameters(aSamplesPerSec
, aChannels
, aBitRate
, aCodec
);
145 error
= e
->setAudioParameters(d
);
152 duration
= d
->getDurationMilliseconds();
162 while(isOk(error
) && abortSignal
== false)
164 AVFrame avframe
; //FIXME/XXX remove this
167 av_init_packet(&opkt
);
169 avcodec_get_frame_defaults(&avframe
);
172 error
= d
->readNextFrame();
175 while(d
->videoBuffer
->count() > 0)
177 error
= d
->placeAtNextFrame(true);
178 if(customVideoSettings
)
180 error
= d
->decodeFrame();
181 if(error
== NoFrameError
)
188 byte
*rgb
= d
->getRGB();
189 if(rgb
== NULL
) error
= GenericError
;
192 log(Packets
, "Adding video frame: %u\n", ++vCounter
);
193 e
->addFrame((char *)rgb
, d
->getWidth(), d
->getHeight());
199 pkt
= d
->videoBuffer
->extractNext();
200 e
->videoStream
->codec
->coded_frame
= &avframe
;
201 opkt
.stream_index
= e
->videoStreamIndex
;
202 e
->videoStream
->codec
->frame_number
++;
205 AVRational iTimebase
= d
->inputFile
->streams
[d
->videoStreamIndex
]->time_base
;
206 AVRational oTimebase
= e
->videoStream
->time_base
;
208 //opkt.pts = (int64_t)(pkt->dts*iTimebase.num/(double)iTimebase.den * (double)oTimebase.den/oTimebase.num);
209 //opkt.dts = (int64_t)(pkt->dts*iTimebase.num/(double)iTimebase.den * (double)oTimebase.den/oTimebase.num);
210 if(pkt
->pts
!= AV_NOPTS_VALUE
) {
211 opkt
.pts
= av_rescale_q(av_rescale_q(pkt
->pts
, iTimebase
, AV_TIME_BASE_Q
) - e
->start_time
, AV_TIME_BASE_Q
, oTimebase
);
212 //opkt.pts = av_rescale_q(pkt->pts, iTimebase, oTimebase);
214 opkt
.pts
= AV_NOPTS_VALUE
;
218 if (pkt
->dts
== AV_NOPTS_VALUE
)
219 dts
= AV_NOPTS_VALUE
;//ist->next_pts;
221 dts
= av_rescale_q(pkt
->dts
, iTimebase
, AV_TIME_BASE_Q
);
222 opkt
.dts
= av_rescale_q(dts
- e
->start_time
, AV_TIME_BASE_Q
, oTimebase
);
224 //opkt.dts = av_rescale_q(pkt->dts, iTimebase, oTimebase);
227 //cout << "Video Pkt " << pkt->dts << " - Converted into= " << opkt.dts << endl;
232 while(d
->audioBuffer
->count() > 0)
234 error
= d
->placeAtNextFrame(false);
236 log(Packets
, "Error while placing at next audio frame %d\n", error
);
239 if(customAudioSettings
)
241 error
= d
->decodeAudioFrame();
242 if(isOk(error
) && d
->getAudioSamplesSize()>0)
244 log(Packets
, "Adding audio frame: %u\n", ++aCounter
);
245 if(d
->getAudioSamplesSize() <= 0)
247 log(Packets
, "Audio frame was empty!\n");
250 e
->addAudioFrame(d
->getAudioSamples(), d
->getAudioSamplesSize(), d
->getAudioChannelNumber(), d
->getAudioSampleRate());
256 //error = d->placeAtNextFrame(false);
257 pkt
= d
->audioBuffer
->extractNext();
258 e
->audioStream
->codec
->coded_frame
= &avframe
;
259 opkt
.stream_index
= e
->audioStreamIndex
;
260 e
->audioStream
->codec
->frame_number
++;
263 AVRational iTimebase
= d
->inputFile
->streams
[d
->audioStreamIndex
]->time_base
;
264 AVRational oTimebase
= e
->audioStream
->time_base
;
265 //opkt.pts = (int64_t)(pkt->dts*iTimebase.num/(double)iTimebase.den * (double)oTimebase.den/oTimebase.num);
266 //opkt.dts = (int64_t)(pkt->dts*iTimebase.num/(double)iTimebase.den * (double)oTimebase.den/oTimebase.num);
267 if(pkt
->pts
!= AV_NOPTS_VALUE
) {
268 opkt
.pts
= av_rescale_q(av_rescale_q(pkt
->pts
, iTimebase
, AV_TIME_BASE_Q
) - e
->start_time
, AV_TIME_BASE_Q
, oTimebase
);
269 //opkt.pts = av_rescale_q(pkt->pts, iTimebase, oTimebase);
271 opkt
.pts
= AV_NOPTS_VALUE
;
275 if (pkt
->dts
== AV_NOPTS_VALUE
)
276 dts
= AV_NOPTS_VALUE
;//ist->next_pts;
278 dts
= av_rescale_q(pkt
->dts
, iTimebase
, AV_TIME_BASE_Q
);
279 opkt
.dts
= av_rescale_q(dts
- e
->start_time
, AV_TIME_BASE_Q
, oTimebase
);
281 //opkt.dts = av_rescale_q(pkt->dts, iTimebase, oTimebase);
284 //cout << "Audio Pkt " << pkt->dts << endl;
290 avframe
.key_frame
= pkt
->flags
& PKT_FLAG_KEY
;
291 //opkt.data= pkt->data;
292 //opkt.size= pkt->size;
294 //opkt.pts= pkt->pts; //FIXME ist->pts?
295 //opkt.dts= pkt->dts;
297 opkt
.flags
= pkt
->flags
;
300 if(av_parser_change(d
->inputFile
->streams
[pkt
->stream_index
]->parser
,
301 opkt
.stream_index
==e
->videoStreamIndex
?e
->videoStream
->codec
:e
->audioStream
->codec
,
302 &opkt
.data
, &opkt
.size
, pkt
->data
, pkt
->size
, pkt
->flags
& PKT_FLAG_KEY
))
304 opkt
.destruct
= av_destruct_packet
;
308 av_free_packet(&opkt
);
312 double p
= d
->getNextFrameTime()*100000.0/duration
;
313 if(p
> 100.0) p
= 100.0;
320 double Transcoder::getCompletion() const
325 void Transcoder::abort()