20 #define BUFFER_SIZE 4096
23 #ifndef BUFFER_ALIGNMENT
24 #define BUFFER_ALIGNMENT 0x20
29 #if (defined(AVCODEC_MAX_AUDIO_FRAME_SIZE) && ((AVCODEC_MAX_AUDIO_FRAME_SIZE) > (BUFFER_SIZE)))
32 #define BUFFER_SIZE ((AVCODEC_MAX_AUDIO_FRAME_SIZE*3)/2)
45 class PacketDecodeException :
public Exception {
47 PacketDecodeException() {}
48 PacketDecodeException(
const CodecNotFoundException &other) :
Exception(other) {}
54 AVFormatContext *pFormatCtx;
55 AVCodecContext *pCodecCtx;
60 uint8_t *packetBuffer;
61 size_t packetBufferSize;
67 void *sampleBufferBase;
68 void *sampleBufferAligned;
70 size_t sampleBufferSize;
71 size_t sampleBufferAlloc;
72 uint64_t sampleBufferStart;
88 audioStreamIndex(streamIdx)
92 char buf[(
sizeof(type)+1)/2+1];
93 sprintf(buf,
"%d", type);
99 std::string npath = std::string(
"vsfile:") + path +
"|" + buf;
100 std::string errbase = std::string(
"Cannot open URL \"") + npath +
"\"";
102 if ( (0 != av_open_input_file(&pFormatCtx, npath.c_str(), NULL,
BUFFER_SIZE, NULL))
103 ||(0 > av_find_stream_info(pFormatCtx)) )
104 throw FileOpenException(errbase +
" (wrong format or file not found)");
108 dump_format(pFormatCtx, 0, npath.c_str(),
false);
114 for (
unsigned int i=0; (pCodecCtx==0) && (i < pFormatCtx->nb_streams); ++
i)
115 if ((pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) && (streamIdx-- == 0))
116 pCodecCtx = (pStream = pFormatCtx->streams[streamIndex =
i])->codec;
118 throw FileOpenException(errbase +
" (wrong or no audio stream)");
121 pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
123 throw CodecNotFoundException(errbase +
" (unsupported codec)");
125 if(avcodec_open(pCodecCtx, pCodec) < 0)
126 throw CodecNotFoundException(errbase +
" (unsupported codec)");
129 fmt.sampleFrequency = pCodecCtx->sample_rate;
130 fmt.channels = pCodecCtx->channels;
132 switch (pCodecCtx->sample_fmt) {
133 case SAMPLE_FMT_U8: fmt.bitsPerSample = 8;
134 fmt.signedSamples = 0;
136 case SAMPLE_FMT_S16: fmt.bitsPerSample = 16;
137 fmt.signedSamples = 1;
139 #ifdef SAMPLE_FMT_S24
140 case SAMPLE_FMT_S24: fmt.bitsPerSample = 24;
141 fmt.signedSamples = 1;
144 #ifdef SAMPLE_FMT_S32
145 case SAMPLE_FMT_S32: fmt.bitsPerSample = 32;
146 fmt.signedSamples = 1;
149 default:
throw CodecNotFoundException(errbase +
" (unsupported audio format)");
151 sampleSize = (fmt.bitsPerSample + 7) / 8 * fmt.channels;
152 assert(sampleSize > 0);
155 sampleBufferStart = 0;
159 sampleBufferBase = malloc(sampleSize * BUFFER_SIZE + BUFFER_ALIGNMENT);
160 ptrdiff_t offs = ((
reinterpret_cast<ptrdiff_t
>(sampleBufferBase)) & (BUFFER_ALIGNMENT-1));
161 sampleBufferAligned = ((
char*)sampleBufferBase) + BUFFER_ALIGNMENT - offs;
164 sampleBufferSize = 0;
170 if (sampleBufferBase)
171 free(sampleBufferBase);
175 avcodec_close(pCodecCtx);
179 av_close_input_file(pFormatCtx);
182 bool saneTimeStamps()
const throw()
184 return pStream->time_base.num != 0;
187 int64_t timeToPts(
double time)
const throw()
189 return int64_t(floor(time * pStream->time_base.den / pStream->time_base.num));
192 double ptsToTime(int64_t pts)
const throw()
194 return double(pts) * pStream->time_base.num / pStream->time_base.den;
197 bool hasFrame()
const throw()
199 return sampleBuffer && sampleBufferSize;
202 bool hasPacket()
const throw()
204 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
205 return packetBuffer && packetBufferSize
206 && packet.data && packet.size;
208 return packetBuffer && packetBufferSize;
212 void readPacket() throw(EndOfStreamException)
215 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
216 packet.size = packetBufferSize;
217 packet.data = packetBuffer;
221 if (packet.data != NULL)
222 av_free_packet( &packet );
225 if(av_read_frame(pFormatCtx, &packet) < 0)
226 throw EndOfStreamException();
227 }
while(packet.stream_index != streamIndex);
229 packetBufferSize = packet.size;
230 packetBuffer = packet.data;
232 sampleBufferStart = int64_t(floor(ptsToTime(packet.dts) * pCodecCtx->sample_rate));
235 void syncPts() throw(EndOfStreamException)
238 throw EndOfStreamException();
239 sampleBufferSize = 0;
240 sampleBufferStart = int64_t(floor(ptsToTime(packet.dts) * pCodecCtx->sample_rate));
242 if (sampleBufferStart > streamSize)
243 streamSize = sampleBufferStart;
246 void decodeFrame() throw(PacketDecodeException)
249 throw PacketDecodeException();
251 int dataSize = sampleBufferAlloc;
253 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
254 avcodec_decode_audio3(
256 (int16_t*)sampleBufferAligned, &dataSize,
259 avcodec_decode_audio2(
261 (int16_t*)sampleBufferAligned, &dataSize,
262 packetBuffer, packetBufferSize);
266 throw PacketDecodeException();
268 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
270 if ((
size_t)used > packet.size)
273 (
char*&)(packet.data) += used;
278 if ((
size_t)used > packetBufferSize)
279 used = packetBufferSize;
281 (
char*&)packetBuffer += used;
282 packetBufferSize -= used;
289 sampleBuffer = sampleBufferAligned;
290 sampleBufferStart += sampleBufferSize;
291 sampleBufferSize = dataSize / sampleSize;
293 if (sampleBufferStart + sampleBufferSize > streamSize)
294 streamSize = sampleBufferStart + sampleBufferSize;
302 ffData =
new __impl::FFData(path, type, getFormatInternal(), streamIndex);
305 FFStream::~FFStream()
311 double FFStream::getLengthImpl()
const throw(
Exception)
313 return double(ffData->streamSize) / getFormat().sampleFrequency;
316 double FFStream::getPositionImpl()
const throw()
318 return double(ffData->sampleBufferStart) / getFormat().sampleFrequency;
321 void FFStream::seekImpl(
double position)
throw(
Exception)
327 uint64_t targetSample = uint64_t(position * getFormat().sampleFrequency);
329 if ( (targetSample >= ffData->sampleBufferStart)
330 && (targetSample < ffData->sampleBufferStart + ffData->sampleBufferSize) )
333 int advance =
int(targetSample - ffData->sampleBufferStart);
334 (
char*&)ffData->sampleBuffer += ffData->sampleSize * advance;
335 ffData->sampleBufferStart += advance;
336 ffData->sampleBufferSize -= advance;
338 if (ffData->saneTimeStamps()) {
340 avcodec_flush_buffers(ffData->pCodecCtx);
341 av_seek_frame(ffData->pFormatCtx, ffData->streamIndex, ffData->timeToPts(position),
342 (targetSample < ffData->sampleBufferStart + ffData->sampleBufferSize) ? AVSEEK_FLAG_BACKWARD : 0);
344 }
else if (targetSample < ffData->sampleBufferStart) {
347 std::string path = ffData->filepath;
349 int streamIndex = ffData->audioStreamIndex;
352 ffData =
new __impl::FFData(path, type, getFormatInternal(), streamIndex);
358 }
while (targetSample >= ffData->sampleBufferStart + ffData->sampleBufferSize);
361 int advance =
int(targetSample - ffData->sampleBufferStart);
362 (
char*&)ffData->sampleBuffer += ffData->sampleSize * advance;
363 ffData->sampleBufferStart += advance;
364 ffData->sampleBufferSize -= advance;
368 void FFStream::getBufferImpl(
void *&
buffer,
unsigned int &bufferSize)
throw(
Exception)
370 if (!ffData->hasFrame())
371 throw NoBufferException();
373 buffer = ffData->sampleBuffer;
374 bufferSize = ffData->sampleSize * ffData->sampleBufferSize;
377 void FFStream::nextBufferImpl() throw(
Exception)
379 if (!ffData->hasPacket())
380 ffData->readPacket();
381 ffData->decodeFrame();
387 #endif // HAVE_FFMPEG