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:
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
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
00144 if (pix_fmt_in != PIX_FMT_NB && pix_fmt_out != PIX_FMT_NB) {
00145
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
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
00170 cmodel_transfer
00171 (
00172 frame_out->get_rows(),
00173
00174 frame_in->get_rows(),
00175
00176
00177 frame_out->get_y(), frame_out->get_u(), frame_out->get_v(),
00178
00179 frame_in->get_y(), frame_in->get_u(), frame_in->get_v(),
00180
00181
00182 0, 0, frame_in->get_w(), frame_in->get_h(),
00183
00184 0, 0, frame_out->get_w(), frame_out->get_h(),
00185
00186
00187 frame_in->get_color_model(), frame_out->get_color_model(),
00188
00189
00190 0,
00191
00192
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
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
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
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
00229 printf("FFMPEG::convert_cmodel pix_fmt_in broken!\n");
00230 return 1;
00231 }
00232
00233
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;
00240 }
00241
00242 int result = convert_cmodel(temp_frame, frame_out);
00243 delete temp_frame;
00244 return result;
00245 }
00246
00247
00248
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
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
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 (
00278 frame_out->get_rows(),
00279
00280 row_pointers_in,
00281
00282
00283 frame_out->get_y(), frame_out->get_u(), frame_out->get_v(),
00284
00285 yuv_in[0], yuv_in[1], yuv_in[2],
00286
00287
00288 0, 0, width_in, height_in,
00289
00290 0, 0, width_in, height_in,
00291
00292
00293 cmodel_in, cmodel_out,
00294
00295
00296 0,
00297
00298
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
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
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 }