15 #define BUFFER_SIZE ( 128*(1<<10) )
20 #include <sys/types.h>
28 #if (LIBAVCODEC_VERSION_MAJOR >= 52) || (LIBAVCODEC_VERSION_INT >= ( ( 51<<16)+(49<<8)+0 ) ) || defined (__amd64__) \
29 || defined (_M_AMD64) || defined (__x86_64) || defined (__x86_64__)
30 typedef int64_t offset_t;
35 using namespace VSFileSystem;
40 AVFormatContext *pFormatCtx;
41 AVCodecContext *pCodecCtx;
45 AVFrame *pNextFrameYUV;
50 uint8_t *packetBuffer;
51 size_t packetBufferSize;
55 size_t fbDimensionLimit;
58 #ifndef DEPRECATED_IMG_CONVERT
69 #ifdef DEPRECATED_IMG_CONVERT
71 (AVPicture*) pFrameRGB, PIX_FMT_RGB24,
72 (AVPicture*) pNextFrameYUV, pCodecCtx->pix_fmt,
73 pCodecCtx->width, pCodecCtx->height );
75 sws_scale( pSWSCtx, pNextFrameYUV->data, pNextFrameYUV->linesize, 0,
76 pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize );
79 fbPTS = pNextFrameYUV->pts;
84 std::swap( pNextFrameYUV, pFrameYUV );
96 while (packetBufferSize > 0 && packet.size > 0) {
98 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
99 bytesDecoded = avcodec_decode_video2(
100 pCodecCtx, pNextFrameYUV, &frameFinished,
103 bytesDecoded = avcodec_decode_video(
104 pCodecCtx, pNextFrameYUV, &frameFinished,
105 packetBuffer, packetBufferSize );
110 (frameFinished ?
"Got frame" :
"")
115 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
116 if (bytesDecoded > packet.size)
117 bytesDecoded = packet.size;
118 packet.size -= bytesDecoded;
119 packet.data += bytesDecoded;
121 if (bytesDecoded > packetBufferSize)
122 bytesDecoded = packetBufferSize;
123 packetBufferSize -= bytesDecoded;
124 packetBuffer += bytesDecoded;
128 pNextFrameYUV->pts = packet.dts;
136 #if (LIBAVCODEC_VERSION_MAJOR >= 53)
137 packet.size = packetBufferSize;
138 packet.data = packetBuffer;
142 if (packet.data != NULL)
143 av_free_packet( &packet );
145 if (av_read_frame( pFormatCtx, &packet ) < 0)
147 }
while (packet.stream_index != videoStreamIndex);
148 packetBufferSize = packet.size;
149 packetBuffer = packet.data;
159 uint8_t *_frameBuffer;
160 uint8_t *frameBuffer;
161 offset_t frameBufferStride;
162 size_t frameBufferSize;
166 VidFileImpl(
size_t maxDimensions,
bool forcePOT ) :
176 , packetBufferSize( 0 )
177 , frameReady(
false )
178 , fbDimensionLimit( maxDimensions )
179 , fbForcePOT( forcePOT )
188 delete[] _frameBuffer;
190 av_free( pFrameRGB );
192 av_free( pFrameYUV );
194 av_free( pNextFrameYUV );
195 #ifndef DEPRECATED_IMG_CONVERT
197 sws_freeContext( pSWSCtx );
201 avcodec_close( pCodecCtx );
204 av_close_input_file( pFormatCtx );
214 std::string npath = std::string(
"vsfile:" )+path;
215 std::string errbase = std::string(
"Cannot open URL \"" )+npath+
"\"";
216 if ( ( 0 != av_open_input_file( &pFormatCtx, npath.c_str(), NULL,
BUFFER_SIZE, NULL ) )
220 dump_format( pFormatCtx, 0, npath.c_str(), false );
225 videoStreamIndex = -1;
227 for (
int i = 0;
i < pFormatCtx->nb_streams; ++
i) {
230 ( (pFormatCtx->streams[
i]->codec->codec_type == CODEC_TYPE_VIDEO) ?
"Video"
231 : ( (pFormatCtx->streams[
i]->codec->codec_type == CODEC_TYPE_AUDIO) ?
"Audio" :
"unk" ) ),
232 pFormatCtx->streams[
i]->codec->codec_type,
233 pFormatCtx->streams[
i]->start_time
235 if ((pCodecCtx == 0) && (pFormatCtx->streams[
i]->codec->codec_type == CODEC_TYPE_VIDEO))
236 pCodecCtx = (pStream = pFormatCtx->streams[videoStreamIndex =
i])->codec;
242 pCodec = avcodec_find_decoder( pCodecCtx->codec_id );
245 pFrameYUV = avcodec_alloc_frame();
246 pNextFrameYUV = avcodec_alloc_frame();
248 "Problem during YUV framebuffer initialization" );
250 frameRate =
float(pStream->r_frame_rate.num)/
float(pStream->r_frame_rate.den);
251 duration =
float(pStream->duration*pStream->time_base.num)/
float(pStream->time_base.den);
258 while (width < pCodecCtx->
width &&
width <= (fbDimensionLimit/2))
width *= 2;
261 width = pCodecCtx->width;
262 height = pCodecCtx->height;
263 while ( (
width > fbDimensionLimit) || (
height > fbDimensionLimit) ) {
271 pFrameRGB = avcodec_alloc_frame();
272 if (pFrameRGB == 0)
throw VidFile::Exception(
"Problem during RGB framebuffer initialization" );
273 frameBufferSize = avpicture_get_size( PIX_FMT_RGB24,
width,
height );
274 _frameBuffer =
new uint8_t[frameBufferSize];
275 if (_frameBuffer == 0)
throw VidFile::Exception(
"Problem during RGB framebuffer initialization" );
276 avpicture_fill( (AVPicture*) pFrameRGB, _frameBuffer, PIX_FMT_RGB24,
width,
height );
277 frameBuffer = pFrameRGB->data[0];
278 frameBufferSize = pFrameRGB->linesize[0]*
height;
279 frameBufferStride = pFrameRGB->linesize[0];
285 pNextFrameYUV->pts = 0;
287 #ifndef DEPRECATED_IMG_CONVERT
288 pSWSCtx = sws_getContext( pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
289 width,
height, PIX_FMT_RGB24, SWS_LANCZOS|SWS_PRINT_INFO, NULL, NULL, NULL );
293 bool seek(
float time )
299 int64_t targetPTS = int64_t( floor(
double(time)*pStream->time_base.den/pStream->time_base.num ) );
301 if ( (targetPTS >= prevPTS) && (targetPTS < pNextFrameYUV->pts) ) {
303 if (targetPTS >= fbPTS) {
311 sizePTS = fbPTS+1;
throw e;
316 if (targetPTS < fbPTS) {
318 int64_t backPTS = targetPTS - 1 - pStream->time_base.den/pStream->time_base.num/2;
323 av_seek_frame( pFormatCtx, videoStreamIndex, backPTS, AVSEEK_FLAG_BACKWARD );
331 if (pNextFrameYUV->pts < targetPTS) {
332 prevPTS = pNextFrameYUV->pts;
337 while (packet.dts < targetPTS) {
338 prevPTS = packet.dts;
343 while (pNextFrameYUV->pts < targetPTS) {
344 prevPTS = pNextFrameYUV->pts;
352 sizePTS = fbPTS+1;
throw e;
415 return impl ? impl->frameRate : 0;
420 return impl ? impl->duration : 0;
425 return impl ? impl->width : 0;
430 return impl ? impl->height : 0;
435 return impl ? impl->frameBuffer : 0;
440 return impl ? impl->frameBufferStride : 0;
445 return (impl != 0) && impl->seek( time );