17 #include <libswscale/swscale.h>
18 #include <libavformat/avformat.h>
19 #include <libavcodec/avcodec.h>
20 #include <libavutil/pixfmt.h>
48 template<
class V
ideoContainer,
typename T, std::
size_t Nb_components, std::
size_t Nb_block>
64 :
base(),pFormatCtx(NULL),pCodecCtx(NULL),pCodec(NULL),pFrame(NULL),pFrameScaled(NULL),numBytes(0),buffer(NULL),packet(),
65 next_frame_loaded(0),videoStream(-1),colorspace(PIX_FMT_GRAY8),remained_frames(0),read_frames(0),nbframes_is_approximated(0),
66 block_ind(1),block_size(0),last_block_size(0),last_it(0),finished(0),initialized(0)
75 :
base(data_filename),pFormatCtx(NULL),pCodecCtx(NULL),pCodec(NULL),pFrame(NULL),pFrameScaled(NULL),
76 numBytes(0),buffer(NULL),packet(),next_frame_loaded(0),videoStream(-1), colorspace(PIX_FMT_GRAY8),remained_frames(0),read_frames(0),
77 nbframes_is_approximated(0),block_ind(1),block_size(0),last_block_size(0),last_it(0),finished(0),initialized(0)
112 int read(VideoContainer & in);
139 return CODEC_ID_NONE;
153 return (read_frames + remained_frames);
161 if(pCodecCtx != NULL)
162 return pCodecCtx->bit_rate;
172 if(pCodecCtx != NULL)
173 return static_cast<std::size_t
>(pCodecCtx->width);
183 if(pCodecCtx != NULL)
184 return static_cast<std::size_t
>(pCodecCtx->height);
194 if(pCodecCtx != NULL)
195 return pCodecCtx->time_base;
197 return (AVRational){0,1};
205 if(pFormatCtx != NULL)
206 return pFormatCtx->duration;
214 AVFormatContext *pFormatCtx;
215 AVCodecContext *pCodecCtx;
218 AVFrame *pFrameScaled;
223 bool next_frame_loaded;
226 PixelFormat colorspace;
229 std::size_t remained_frames;
230 std::size_t read_frames;
231 bool nbframes_is_approximated;
251 template<
class V
ideoContainer,
typename T, std::
size_t Nb_components, std::
size_t Nb_block>
255 if (Nb_components != 1 && Nb_components != 3){
256 std::ostringstream err;
257 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Nb_components should be 1 or 3.";
258 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
261 if (Nb_components == 3)
262 colorspace = PIX_FMT_RGB24;
269 if(avformat_open_input(&pFormatCtx, this->data_filename_.c_str(), NULL, NULL)!=0) {
270 std::ostringstream err;
272 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
277 if(avformat_find_stream_info(pFormatCtx,NULL) < 0){
278 std::ostringstream err;
279 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Couldn't find stream information.";
280 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
285 av_dump_format(pFormatCtx, 0, this->data_filename_.c_str(),
false);
288 for(
unsigned int i=0; i<pFormatCtx->nb_streams; i++)
289 if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
295 std::ostringstream err;
296 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Didn't find a video stream.";
297 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
302 pCodecCtx=pFormatCtx->streams[videoStream]->codec;
305 pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
307 std::ostringstream err;
308 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Codec not found.";
309 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
315 if(avcodec_open2(pCodecCtx, pCodec, NULL)<0){
316 std::ostringstream err;
317 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Could not open codec.";
318 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
328 pFrame=avcodec_alloc_frame();
331 pFrameScaled=avcodec_alloc_frame();
332 if(pFrameScaled==NULL){
333 std::ostringstream err;
334 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Could not allocate AVFrame structure.";
335 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
341 numBytes=avpicture_get_size(colorspace, pCodecCtx->width,
343 buffer=
new uint8_t[numBytes];
345 avpicture_fill((AVPicture *)pFrameScaled, buffer, colorspace,
346 pCodecCtx->width, pCodecCtx->height);
348 remained_frames = pFormatCtx->streams[videoStream]->nb_frames;
349 if (remained_frames == 0){
350 nbframes_is_approximated =
true;
351 remained_frames = pFormatCtx->streams[videoStream]->codec_info_nb_frames;
355 block_size = remained_frames / Nb_block;
356 long int one_frame_size = pCodecCtx->width * pCodecCtx->height * Nb_components;
357 double container_size =
static_cast<double>(block_size) * static_cast<double>(one_frame_size);
358 double limit_1_go = 1073741824.0;
359 if ( container_size > limit_1_go)
361 std::ostringstream err;
362 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Containers size ";
363 err << container_size <<
" is greater than 1Go = " << limit_1_go;
364 slip::slip_exception exc(std::string(
"slip"), std::string(
"AvReader::initialize()"), err.str());
368 last_block_size = remained_frames % Nb_block;
369 last_block_size = (last_block_size == 0 ? block_size : block_size+last_block_size);
370 last_it = (Nb_block == 1);
371 finished = (last_it && last_block_size == 0);
377 template<
class V
ideoContainer,
typename T, std::
size_t Nb_components, std::
size_t Nb_block>
381 std::ostringstream err;
382 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | The reader needs to be initialized before reading.";
390 in.resize(last_block_size,pCodecCtx->height,pCodecCtx->width,T());
392 in.resize(block_size,pCodecCtx->height,pCodecCtx->width,T());
395 if((!nbframes_is_approximated) && (remained_frames < in.slices())){
396 std::ostringstream err;
397 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | Bad image dimensions.";
403 std::size_t filled_frames=0;
404 int frameFinished = 0;
405 std::size_t height =
static_cast<std::size_t
>(pCodecCtx->height);
406 std::size_t width =
static_cast<std::size_t
>(pCodecCtx->width);
407 std::size_t row_stride =
static_cast<std::size_t
>(pCodecCtx->width * Nb_components);
408 std::size_t in_slices = in.slices();
409 if (!next_frame_loaded)
410 next_frame_loaded = (av_read_frame(pFormatCtx, &packet)>=0);
411 while(next_frame_loaded && (filled_frames < in_slices))
414 if(packet.stream_index==videoStream)
417 if(avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,&packet) < 0){
418 std::ostringstream err;
419 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | The frame can not be decompressed.";
426 static struct SwsContext *img_convert_ctx = NULL;
427 img_convert_ctx = sws_getCachedContext(img_convert_ctx,width, height,pCodecCtx->pix_fmt,
428 width, height, colorspace, SWS_FAST_BILINEAR, NULL, NULL, NULL);
429 std::size_t h = sws_scale(img_convert_ctx, (
const uint8_t*
const*)pFrame->data, pFrame->linesize,0, height,
430 pFrameScaled->data, pFrameScaled->linesize);
432 std::ostringstream err;
433 err <<
FILE_READ_ERROR << this->data_filename_ <<
" | The frame size is too large.";
438 for(std::size_t y=0; y<height; y++){
439 T * ptr_i =
reinterpret_cast<T *
>(in[filled_frames][y]);
440 std::copy(pFrameScaled->data[0]+y*pFrameScaled->linesize[0],
441 pFrameScaled->data[0]+y*pFrameScaled->linesize[0] + row_stride,ptr_i);
447 av_free_packet(&packet);
449 next_frame_loaded = (av_read_frame(pFormatCtx, &packet)>=0);
451 read_frames += filled_frames;
452 remained_frames -= filled_frames;
456 if (nbframes_is_approximated){
457 if (in.slices() > (filled_frames + 1)){
458 std::size_t rs = in.slices() - filled_frames - 1;
459 std::cerr <<
"slip::AvReader::read | Warning the last container has not been fully filled, the "
460 << rs <<
" last frames remain unchanged." << std::endl;
461 }
else if(next_frame_loaded){
462 std::cerr <<
"slip::AvReader::read | Warning some end frames of the video could have not been read." << std::endl;
467 last_it = (block_ind == Nb_block);
472 template<
class V
ideoContainer,
typename T, std::
size_t Nb_components, std::
size_t Nb_block>
479 av_free(pFrameScaled);
485 avcodec_close(pCodecCtx);
488 avformat_close_input(&pFormatCtx);
497 next_frame_loaded =
false;
499 colorspace = PIX_FMT_GRAY8;
502 nbframes_is_approximated =
false;
AVCodec * get_codec() const
get the codec pointer
int64_t get_duration() const
get the duration of the video stream
void initialize()
initialized the reading process.
AvReader(std::string data_filename)
Contains the container reader base class.
void release()
release the reading process.
standard exception extension name have been changed to eliminate conflicts with QT ...
ContainerReader< VideoContainer, T, Nb_block > base
std::size_t get_frame_width() const
get the width of a decoded frame picture
int get_nb_frames() const
get the total number of frames
int get_bit_rate() const
get the the average bit rate of the codec
const std::string FILE_OPEN_ERROR
ContainerReader is the base class of the readers classes. All readers are working the same way: ...
std::size_t get_frame_height() const
get the height of a decoded frame picture
void copy(_II first, _II last, _OI output_first)
Copy algorithm optimized for slip iterators.
AvReader, inherited from ContainerReader, is a reader for videos.
AVRational get_time_base() const
get the time base of the video stream (1/framerate)
int get_read_frames() const
get the number of read frames
Provides SLIP error messages.
CodecID get_codec_id() const
get the codec id (see avcodec.h : enum AVCodecID)
VideoContainer container_type
int read(VideoContainer &in)
virtual read function. If Nb_block is more than one, it reads only one container, and returns 0...
const std::string FILE_READ_ERROR