Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

ffmpeg.C

Go to the documentation of this file.
00001 #include <string.h>
00002 
00003 #include "filebase.h"
00004 #include "quicktime.h"
00005 #include "ffmpeg.h"
00006 #include "guicast.h"
00007 
00008 FFMPEG::FFMPEG(Asset *asset) {
00009         this->asset = asset;
00010         codec = 0;
00011         context = 0;
00012         picture = 0;
00013         got_picture = 0;
00014 }
00015 
00016 int FFMPEG::init(char *codec_string) {
00017 
00018         avcodec_init();
00019         avcodec_register_all();
00020 
00021         CodecID id = codec_id(codec_string);
00022         codec = avcodec_find_decoder(id);
00023         if (codec == NULL) {
00024                 printf("FFMPEG::init no decoder for '%s'", codec_string);
00025                 return 1;
00026         }
00027 
00028         context = avcodec_alloc_context();
00029 
00030         if (avcodec_open(context, codec)) {
00031                 printf("FFMPEG::init avcodec_open() failed\n");
00032         }
00033 
00034         picture = avcodec_alloc_frame();
00035 
00036 
00037         return 0;
00038 }
00039 
00040 FFMPEG::~FFMPEG() {
00041         avcodec_close(context);
00042         free(context);
00043         free(picture);
00044 }
00045 
00046 
00047 CodecID FFMPEG::codec_id(char *codec_string) {
00048 #define CODEC_IS(x) (! strncmp(codec_string, x, 4))
00049 
00050         if (CODEC_IS(QUICKTIME_DV) ||
00051             CODEC_IS(QUICKTIME_DVSD)) return CODEC_ID_DVVIDEO;
00052         
00053         if (CODEC_IS(QUICKTIME_MP4V) ||
00054             CODEC_IS(QUICKTIME_DIVX)) return CODEC_ID_MPEG4;
00055 
00056         return CODEC_ID_NONE;
00057 
00058 #undef CODEC_IS
00059 }
00060 
00061 PixelFormat FFMPEG::color_model_to_pix_fmt(int color_model) {
00062         switch (color_model) 
00063                 { 
00064                 case BC_YUV422: 
00065                           return PIX_FMT_YUV422;
00066                 case BC_RGB888:
00067                         return PIX_FMT_RGB24;
00068                 case BC_BGR8888:  // NOTE: order flipped
00069                         return PIX_FMT_RGBA32;
00070                 case BC_BGR888:
00071                         return PIX_FMT_BGR24;
00072                 case BC_YUV420P: 
00073                         return PIX_FMT_YUV420P;
00074                 case BC_YUV422P:
00075                         return PIX_FMT_YUV422P;
00076                 case BC_YUV444P:
00077                         return PIX_FMT_YUV444P;
00078                 case BC_YUV411P:
00079                         return PIX_FMT_YUV411P;
00080                 case BC_RGB565:
00081                         return PIX_FMT_RGB565;
00082                 };
00083 
00084         return PIX_FMT_NB;
00085 }
00086 
00087 int FFMPEG::pix_fmt_to_color_model(PixelFormat pix_fmt) {
00088         switch (pix_fmt) 
00089                 { 
00090                 case PIX_FMT_YUV422:
00091                         return BC_YUV422;
00092                 case PIX_FMT_RGB24:
00093                         return BC_RGB888;
00094                 case PIX_FMT_RGBA32:
00095                         return BC_BGR8888;
00096                 case PIX_FMT_BGR24:
00097                         return BC_BGR888;
00098                 case PIX_FMT_YUV420P:
00099                         return BC_YUV420P;
00100                 case PIX_FMT_YUV422P:
00101                         return BC_YUV422P;
00102                 case PIX_FMT_YUV444P:
00103                         return BC_YUV444P;
00104                 case PIX_FMT_YUV411P:
00105                         return BC_YUV411P;
00106                 case PIX_FMT_RGB565:
00107                         return BC_RGB565;
00108                 };
00109 
00110         return BC_TRANSPARENCY;
00111 }
00112 
00113 int FFMPEG::init_picture_from_frame(AVPicture *picture, VFrame *frame) {
00114         int cmodel = frame->get_color_model();
00115         PixelFormat pix_fmt = color_model_to_pix_fmt(cmodel);
00116 
00117         int size = avpicture_fill(picture, frame->get_data(), pix_fmt, 
00118                                   frame->get_w(), frame->get_h());
00119 
00120         if (size < 0) {
00121                 printf("FFMPEG::init_picture failed\n");
00122                 return 1;
00123         }
00124 
00125         if (cmodel_is_planar(frame->get_color_model())) {
00126                 // override avpicture_fill() for planar types
00127                 picture->data[0] = frame->get_y();
00128                 picture->data[1] = frame->get_u();
00129                 picture->data[2] = frame->get_v();
00130         }
00131 
00132         return size;
00133 }
00134 
00135 
00136 int FFMPEG::convert_cmodel(VFrame *frame_in,  VFrame *frame_out) {
00137   
00138         PixelFormat pix_fmt_in = 
00139                 color_model_to_pix_fmt(frame_in->get_color_model());
00140         PixelFormat pix_fmt_out = 
00141                 color_model_to_pix_fmt(frame_out->get_color_model());
00142 
00143         // do conversion within libavcodec if possible
00144         if (pix_fmt_in != PIX_FMT_NB && pix_fmt_out != PIX_FMT_NB) {
00145                 // set up a temporary pictures from frame_in and frame_out
00146                 AVPicture picture_in, picture_out;
00147                 init_picture_from_frame(&picture_in, frame_in);
00148                 init_picture_from_frame(&picture_out, frame_out);
00149 
00150                 int result = img_convert(&picture_out,
00151                                          pix_fmt_out,
00152                                          &picture_in,
00153                                          pix_fmt_in,
00154                                          frame_in->get_w(),
00155                                          frame_out->get_h());
00156                 if (result) {
00157                         printf("FFMPEG::convert_cmodel img_convert() failed\n");
00158                 }
00159                 return result;
00160         }
00161 
00162 
00163         // failing the fast method, use the failsafe cmodel_transfer()
00164         return convert_cmodel_transfer(frame_in, frame_out);
00165 }  
00166 
00167 int FFMPEG::convert_cmodel_transfer(VFrame *frame_in, VFrame *frame_out) {
00168         
00169         // WARNING: cmodel_transfer is said to be broken with BC_YUV411P
00170         cmodel_transfer
00171                 (// Packed data out 
00172                  frame_out->get_rows(), 
00173                  // Packed data in
00174                  frame_in->get_rows(),
00175 
00176                  // Planar data out
00177                  frame_out->get_y(), frame_out->get_u(), frame_out->get_v(),
00178                  // Planar data in
00179                  frame_in->get_y(), frame_in->get_u(), frame_in->get_v(),
00180 
00181                  // Dimensions in
00182                  0, 0, frame_in->get_w(), frame_in->get_h(),
00183                  // Dimensions out
00184                  0, 0, frame_out->get_w(), frame_out->get_h(),
00185 
00186                  // Color models
00187                  frame_in->get_color_model(), frame_out->get_color_model(),
00188 
00189                  // Background color
00190                  0,
00191                  
00192                  // Rowspans (of luma for YUV)
00193                  frame_in->get_w(), frame_out->get_w()
00194                  
00195                  );
00196 
00197         return 0;
00198 }
00199 
00200 
00201 int FFMPEG::convert_cmodel(AVPicture *picture_in, PixelFormat pix_fmt_in,
00202                           int width_in, int height_in, VFrame *frame_out) {
00203 
00204         // set up a temporary picture_out from frame_out
00205         AVPicture picture_out;
00206         init_picture_from_frame(&picture_out, frame_out);
00207         int cmodel_out = frame_out->get_color_model();
00208         PixelFormat pix_fmt_out = color_model_to_pix_fmt(cmodel_out);
00209 
00210         // do conversion within libavcodec if possible
00211         if (pix_fmt_out != PIX_FMT_NB) {
00212                 int result = img_convert(&picture_out,
00213                                          pix_fmt_out,
00214                                          picture_in,
00215                                          pix_fmt_in,
00216                                          width_in,
00217                                          height_in);
00218                 if (result) {
00219                         printf("FFMPEG::convert_cmodel img_convert() failed\n");
00220                 }
00221                 return result;
00222         }
00223         
00224         // make an intermediate temp frame only if necessary
00225         int cmodel_in = pix_fmt_to_color_model(pix_fmt_in);
00226         if (cmodel_in == BC_TRANSPARENCY) {
00227                 if (pix_fmt_in == PIX_FMT_RGBA32) {
00228                         // avoid infinite recursion if things are broken
00229                         printf("FFMPEG::convert_cmodel pix_fmt_in broken!\n");
00230                         return 1;
00231                 }
00232 
00233                 // NOTE: choose RGBA8888 as a hopefully non-lossy colormodel
00234                 VFrame *temp_frame = new VFrame(0, width_in, height_in, 
00235                                                 BC_RGBA8888);
00236                 if (convert_cmodel(picture_in, pix_fmt_in,
00237                                   width_in, height_in, temp_frame)) {
00238                         delete temp_frame;
00239                         return 1;  // recursed call will print error message
00240                 }
00241                 
00242                 int result = convert_cmodel(temp_frame, frame_out);
00243                 delete temp_frame;
00244                 return result;
00245         }
00246 
00247         
00248         // NOTE: no scaling possible in img_convert() so none possible here
00249         if (frame_out->get_w() != width_in ||
00250             frame_out->get_h() != height_in) {
00251                 printf("scaling from %sx%s to %sx%x not allowed\n",
00252                        width_in, height_in, 
00253                        frame_out->get_w(), frame_out->get_h());
00254                 return 1;
00255         }
00256 
00257 
00258         // if we reach here we know that cmodel_transfer() will work
00259         uint8_t *yuv_in[3] = {0,0,0};
00260         uint8_t *row_pointers_in[height_in];
00261         if (cmodel_is_planar(cmodel_in)) {
00262                 yuv_in[0] = picture_in->data[0];
00263                 yuv_in[1] = picture_in->data[1];
00264                 yuv_in[2] = picture_in->data[2];
00265         }
00266         else {
00267                 // set row pointers for picture_in 
00268                 uint8_t *data = picture_in->data[0];
00269                 int bytes_per_line = 
00270                         cmodel_calculate_pixelsize(cmodel_in) * height_in;
00271                 for (int i = 0; i < height_in; i++) {
00272                         row_pointers_in[i] = data + i * bytes_per_line;
00273                 }
00274         }
00275 
00276         cmodel_transfer
00277                 (// Packed data out 
00278                  frame_out->get_rows(), 
00279                  // Packed data in
00280                  row_pointers_in,
00281 
00282                  // Planar data out
00283                  frame_out->get_y(), frame_out->get_u(), frame_out->get_v(),
00284                  // Planar data in
00285                  yuv_in[0], yuv_in[1], yuv_in[2],
00286 
00287                  // Dimensions in
00288                  0, 0, width_in, height_in,  // NOTE: dimensions are same
00289                  // Dimensions out
00290                  0, 0, width_in, height_in,
00291 
00292                  // Color model in, color model out
00293                  cmodel_in, cmodel_out,
00294 
00295                  // Background color
00296                  0,
00297                  
00298                  // Rowspans in, out (of luma for YUV)
00299                  width_in, width_in
00300                  
00301                  );
00302 
00303         return 0;
00304 }
00305 
00306 int FFMPEG::decode(uint8_t *data, long data_size, VFrame *frame_out) { 
00307 
00308         // NOTE: frame must already have data space allocated
00309         
00310         got_picture = 0;
00311         int length = avcodec_decode_video(context,
00312                                           picture,
00313                                           &got_picture,
00314                                           data,
00315                                           data_size);
00316         
00317         if (length < 0) {
00318                 printf("FFMPEG::decode error decoding frame\n");
00319                 return 1;
00320         }
00321 
00322         if (! got_picture) {
00323                 // signal the caller there is no picture yet
00324                 return FFMPEG_LATENCY;
00325         }
00326         
00327         int result = convert_cmodel((AVPicture *)picture, 
00328                                     context->pix_fmt,
00329                                     asset->width, 
00330                                     asset->height, 
00331                                     frame_out);
00332         
00333         return result;
00334 }

Generated on Sun Jan 8 13:38:54 2006 for Cinelerra-svn by  doxygen 1.4.4