22 #ifndef KJB_CPP_I_VIDEO_H
23 #define KJB_CPP_I_VIDEO_H
31 #ifdef KJB_HAVE_FFMPEG
35 #ifndef __STDC_CONSTANT_MACROS
36 #define __STDC_CONSTANT_MACROS
40 #include <libavcodec/avcodec.h>
41 #include <libswscale/swscale.h>
42 #include <libavformat/avformat.h>
45 #define AVFORMAT_IS_RECENT (defined(LIBAVFORMAT_VERSION_MAJOR ) && LIBAVFORMAT_VERSION_MAJOR >= 53 && LIBAVFORMAT_VERSION_MINOR >= 4)
49 #include <boost/shared_array.hpp>
64 boost::shared_array<unsigned char> data_;
74 virtual size_t size()
const = 0;
87 Video(
const std::vector<std::string>& fnames,
float frame_rate = 30.0)
92 Video(
const std::string& fnames)
99 #if defined(KJB_HAVE_FFMPEG) && AVFORMAT_IS_RECENT
100 AVFormatContext *pFormatCtx = NULL;
102 AVCodecContext *pCodecCtx = NULL;
103 AVCodec *pCodec = NULL;
104 AVFrame *pFrame = NULL;
105 AVFrame *pFrameRGB = NULL;
109 uint8_t *buffer = NULL;
112 if(!ffmpeg_registered_)
120 if(avformat_open_input(&pFormatCtx, fname.c_str(), NULL, NULL)!=0)
124 if(avformat_find_stream_info(pFormatCtx, NULL)<0)
132 for(i=0; i< (int) pFormatCtx->nb_streams; i++)
134 if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
145 pCodecCtx=pFormatCtx->streams[videoStream]->codec;
146 size_t num_frames = pFormatCtx->streams[videoStream]->nb_frames;
149 frames_.reserve(num_frames);
150 AVRational fps = pFormatCtx->streams[videoStream]->r_frame_rate;
151 frame_rate_ = (float) fps.num / fps.den;
155 fps = pFormatCtx->streams[videoStream]->avg_frame_rate;
156 frame_rate_ = (float) fps.num / fps.den;
160 assert(frame_rate_ > 0);
163 pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
168 if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
172 if(pCodecCtx->time_base.num>1000 && pCodecCtx->time_base.den==1)
173 pCodecCtx->time_base.den=1000;
176 pFrame=avcodec_alloc_frame();
179 pFrameRGB=avcodec_alloc_frame();
184 numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
187 width_ = pCodecCtx->width;
188 height_ = pCodecCtx->height;
190 buffer=(uint8_t*)malloc(numBytes);
193 avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
194 pCodecCtx->width, pCodecCtx->height);
198 while(av_read_frame(pFormatCtx, &packet)>=0)
201 if(packet.stream_index==videoStream)
204 avcodec_decode_video2(pCodecCtx,
205 pFrame, &frameFinished, &packet);
210 static struct SwsContext *img_convert_ctx;
213 if(img_convert_ctx == NULL) {
214 int w = pCodecCtx->width;
215 int h = pCodecCtx->height;
217 img_convert_ctx = sws_getContext(w, h,
219 w, h, PIX_FMT_RGB24, SWS_BICUBIC,
221 if(img_convert_ctx == NULL) {
222 fprintf(stderr,
"Cannot initialize the conversion context!\n");
226 sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0,
227 pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
230 const size_t& width = pCodecCtx->width;
231 const size_t&
height = pCodecCtx->height;
233 boost::shared_array<unsigned char> buffer(
new unsigned char[width * height * 3]);
235 for(
size_t row = 0; row <
height; row++)
237 const uint8_t* source_begin = pFrameRGB->data[0] + row * pFrameRGB->linesize[0];
238 unsigned char* dest_begin = buffer.get() + (height - row - 1) * width * 3;
239 size_t row_length = width * 3;
241 std::copy(source_begin,
242 source_begin + row_length,
246 frames_.push_back(buffer);
251 av_free_packet(&packet);
264 avcodec_close(pCodecCtx);
267 avformat_close_input(&pFormatCtx);
276 frames_.resize(images.size());
280 template<
class Iterator>
281 void load_images(Iterator first, Iterator last,
float frame_rate = 30.0)
283 size_t nfrms = std::distance(first, last);
285 frames_.resize(nfrms);
286 frame_rate_ = frame_rate;
289 for(; first != last; first++, i++)
311 void load_images(
const std::vector<std::string>& fnames,
float frame_rate = 30.0)
313 load_images(fnames.begin(), fnames.end(), frame_rate);
318 return frames_.size();
348 return frames_[
i].get();
351 template <
class Output_iterator>
355 size_t num_cols = width_;
356 size_t num_rows = height_;
357 img =
Image(num_cols, num_rows);
359 size_t stride = 3 * num_cols;
360 for(
size_t f = 0; f < frames_.size(); f++)
363 int out_row = num_rows - 1;
366 for(
size_t row = 0; row < num_rows; row++)
368 for(
size_t col = 0; col < 3*num_cols; col += 3)
370 img(out_row, out_col,
Image::RED) = (float) frames_[f][offset + col + 0 ];
371 img(out_row, out_col,
Image::GREEN) = (float) frames_[f][offset + col + 1];
372 img(out_row, out_col,
Image::BLUE) = (float) frames_[f][offset + col + 2];
389 boost::shared_array<unsigned char> buffer(
new unsigned char[3 * num_rows * num_cols]);
391 for(
size_t row = 0; row < num_rows; row++)
393 for(
size_t col = 0; col < 3*num_cols; col += 3)
395 size_t r = num_rows - row - 1;
397 buffer[col + 0 + row*3*num_cols] = (
unsigned char) img(r, col/3,
Image::RED);
398 buffer[col + 1 + row*3*num_cols] = (
unsigned char) img(r, col/3,
Image::GREEN);
399 buffer[col + 2 + row*3*num_cols] = (
unsigned char) img(r, col/3,
Image::BLUE);
406 std::vector<boost::shared_array<unsigned char> > frames_;
411 static bool ffmpeg_registered_;
Video()
Definition: video.h:85
virtual size_t get_height() const =0
Object thrown when an index argument exceeds the size of a container.
Definition: l_exception.h:399
void load_images(const std::vector< std::string > &fnames, float frame_rate=30.0)
Definition: video.h:311
Definition: i_image.h:140
Definition: i_image.h:140
height
Definition: APPgetLargeConnectedEdges.m:33
r
Definition: APPgetLargeConnectedEdges.m:127
#define KJB_THROW(ex)
Definition: l_exception.h:46
void load_images(const std::vector< Image > &images, float)
Definition: video.h:274
virtual Video_frame operator[](size_t i) const
Definition: video.h:321
const unsigned char * get_buffer(size_t i) const
Definition: video.h:346
virtual size_t size() const =0
void load_images(Iterator first, Iterator last, float frame_rate=30.0)
Definition: video.h:281
static boost::shared_array< unsigned char > image_to_frame_(const Image &img)
Definition: video.h:384
Video(const std::vector< std::string > &fnames, float frame_rate=30.0)
Definition: video.h:87
Video(const std::string &fnames)
Definition: video.h:92
size_t get_height() const
Definition: video.h:336
int get_num_rows() const
Return the number of rows in the image.
Definition: i_image.h:256
Video_frame(boost::shared_array< unsigned char > data, size_t width, size_t height)
Definition: video.h:58
virtual size_t get_width() const =0
Definition: i_image.h:140
#define KJB_THROW_2(ex, msg)
Definition: l_exception.h:48
#define KJB_THROW_3(ex, fmt, params)
Definition: l_exception.h:56
virtual Video_frame operator[](size_t i) const =0
void to_images(Output_iterator frame_it)
Definition: video.h:352
size_t get_width() const
Definition: video.h:331
int get_num_cols() const
Return the number of columns in the image.
Definition: i_image.h:262
Object thrown when an argument to a function is not acceptable.
Definition: l_exception.h:377
Object thrown when attempting to use unimplemented functionality.
Definition: l_exception.h:281
void decode_video(const std::string &fname)
Definition: video.h:97
get the indices of edges in each direction for i
Definition: APPgetLargeConnectedEdges.m:48
float get_frame_rate() const
Definition: video.h:341
Object thrown when input or output fails.
Definition: l_exception.h:496
Code for a wrapper class around the C struct KJB_Image.
virtual float get_frame_rate() const =0
Wrapped version of the C struct KJB_image.
Definition: i_image.h:76
Object thrown when a program lacks required resources or libraries.
Definition: l_exception.h:539
virtual size_t size() const
Definition: video.h:316
Object thrown when computation fails somehow during execution.
Definition: l_exception.h:321