#include "platform.h"
#include "extractor.h"
#include <avformat.h>
#include <avcodec.h>
#include <swscale.h>
Go to the source code of this file.
Data Structures | |
| struct | StreamDescriptor |
| struct | MimeToDecoderMapping |
Defines | |
| #define | DEBUG 0 |
| #define | PROBE_MAX (1<<20) |
| #define | BIOBUF_SIZE (64*1024) |
| #define | THUMBSIZE 128 |
| #define | MAX_THUMB_SIZE (100*1024) |
Functions | |
| void | __attribute__ ((constructor)) |
| static int | stream_read (void *opaque, uint8_t *buf, int buf_size) |
| static offset_t | stream_seek (void *opaque, offset_t offset, int whence) |
| static EXTRACTOR_KeywordList * | addKeyword (EXTRACTOR_KeywordType type, char *keyword, EXTRACTOR_KeywordList *next) |
| EXTRACTOR_Keywords * | libextractor_thumbnailffmpeg_extract (const char *filename, const unsigned char *data, size_t size, struct EXTRACTOR_Keywords *prev) |
| EXTRACTOR_Keywords * | libextractor_thumbnail_extract (const char *filename, const unsigned char *data, size_t size, struct EXTRACTOR_Keywords *prev, const char *options) |
Variables | |
| static struct MimeToDecoderMapping | m2d_map [] |
Definition in file thumbnailextractorffmpeg.c.
| #define BIOBUF_SIZE (64*1024) |
Definition at line 147 of file thumbnailextractorffmpeg.c.
Referenced by libextractor_thumbnailffmpeg_extract().
| #define DEBUG 0 |
Definition at line 35 of file thumbnailextractorffmpeg.c.
| #define MAX_THUMB_SIZE (100*1024) |
Definition at line 149 of file thumbnailextractorffmpeg.c.
| #define PROBE_MAX (1<<20) |
Definition at line 146 of file thumbnailextractorffmpeg.c.
Referenced by libextractor_thumbnailffmpeg_extract().
| #define THUMBSIZE 128 |
Definition at line 148 of file thumbnailextractorffmpeg.c.
| void __attribute__ | ( | (constructor) | ) |
Definition at line 45 of file thumbnailextractorffmpeg.c.
References av_register_all(), and printf.
00046 { 00047 #if DEBUG 00048 printf ("av_register_all()\n"); 00049 #endif 00050 av_register_all (); 00051 }
| static EXTRACTOR_KeywordList* addKeyword | ( | EXTRACTOR_KeywordType | type, | |
| char * | keyword, | |||
| EXTRACTOR_KeywordList * | next | |||
| ) | [static] |
Definition at line 115 of file thumbnailextractorffmpeg.c.
References EXTRACTOR_Keywords::keyword, EXTRACTOR_Keywords::keywordType, malloc, EXTRACTOR_Keywords::next, and NULL.
00117 { 00118 EXTRACTOR_KeywordList *result; 00119 00120 if (keyword == NULL) 00121 return next; 00122 result = malloc (sizeof (EXTRACTOR_KeywordList)); 00123 result->next = next; 00124 result->keyword = keyword; 00125 result->keywordType = type; 00126 return result; 00127 }
| struct EXTRACTOR_Keywords* libextractor_thumbnail_extract | ( | const char * | filename, | |
| const unsigned char * | data, | |||
| size_t | size, | |||
| struct EXTRACTOR_Keywords * | prev, | |||
| const char * | options | |||
| ) |
Definition at line 519 of file thumbnailextractorffmpeg.c.
References libextractor_thumbnailffmpeg_extract().
00524 { 00525 return libextractor_thumbnailffmpeg_extract (filename, data, size, prev); 00526 }
| struct EXTRACTOR_Keywords* libextractor_thumbnailffmpeg_extract | ( | const char * | filename, | |
| const unsigned char * | data, | |||
| size_t | size, | |||
| struct EXTRACTOR_Keywords * | prev | |||
| ) |
Definition at line 152 of file thumbnailextractorffmpeg.c.
References av_find_stream_info(), av_open_input_stream(), av_probe_input_format(), avcodec_alloc_context(), avcodec_find_decoder(), avcodec_open(), AVFMT_NOFILE, BIOBUF_SIZE, AVProbeData::buf, AVProbeData::buf_size, AVCodecContext::codec, AVCodecContext::codec_id, MimeToDecoderMapping::codec_id, AVCodecContext::codec_type, CODEC_TYPE_VIDEO, StreamDescriptor::data, DEBUG, EXTRACTOR_extractLast(), EXTRACTOR_MIMETYPE, AVProbeData::filename, AVInputFormat::flags, init_put_byte(), AVInputFormat::long_name, m2d_map, malloc, AVInputFormat::name, NULL, StreamDescriptor::offset, printf, PROBE_MAX, AVInputFormat::read_probe, StreamDescriptor::size, stream_read(), stream_seek(), SWS_BILINEAR, and sws_flags.
Referenced by libextractor_thumbnail_extract().
00156 { 00157 int score; 00158 00159 AVInputFormat *fmt; 00160 AVProbeData pdat; 00161 00162 ByteIOContext *bio_ctx = NULL; 00163 uint8_t *bio_buffer; 00164 struct StreamDescriptor reader_state; 00165 00166 AVFormatContext *format_ctx = NULL; 00167 AVCodecContext *codec_ctx = NULL; 00168 AVPacket packet; 00169 int video_stream_index; 00170 AVCodec *codec; 00171 AVFrame *frame = NULL; 00172 AVFrame *thumb_frame = NULL; 00173 int64_t ts; 00174 00175 struct SwsContext *scaler_ctx; 00176 int sws_flags = SWS_BILINEAR; 00177 uint8_t *thumb_buffer; 00178 int thumb_width, thumb_height; 00179 int sar_num, sar_den; 00180 00181 uint8_t *encoder_output_buffer; 00182 size_t encoder_output_buffer_size; 00183 AVCodecContext *enc_codec_ctx; 00184 AVCodec *enc_codec; 00185 00186 int i; 00187 int err; 00188 int frame_finished; 00189 00190 char *binary; 00191 const char *mime; 00192 int is_image; 00193 enum CodecID image_codec_id; 00194 00195 bio_ctx = NULL; 00196 bio_buffer = NULL; 00197 format_ctx = NULL; 00198 codec = NULL; 00199 frame = NULL; 00200 thumb_frame = NULL; 00201 thumb_buffer = NULL; 00202 scaler_ctx = NULL; 00203 encoder_output_buffer = NULL; 00204 enc_codec = NULL; 00205 enc_codec_ctx = NULL; 00206 00207 is_image = 0; 00208 00209 mime = EXTRACTOR_extractLast (EXTRACTOR_MIMETYPE, prev); 00210 if (mime != NULL) 00211 { 00212 i = 0; 00213 while (m2d_map[i].mime_type != NULL) 00214 { 00215 if (!strcmp (m2d_map[i].mime_type, mime)) 00216 { 00217 is_image = 1; 00218 image_codec_id = m2d_map[i].codec_id; 00219 break; 00220 } 00221 i++; 00222 } 00223 } 00224 00225 #if DEBUG 00226 printf ("is_image: %d codec:%d\n", is_image, image_codec_id); 00227 #endif 00228 if (!is_image) 00229 { 00230 pdat.filename = filename; 00231 pdat.buf = (unsigned char *) data; 00232 pdat.buf_size = (size > PROBE_MAX) ? PROBE_MAX : size; 00233 00234 fmt = av_probe_input_format (&pdat, 1); 00235 if (fmt == NULL) 00236 return prev; 00237 #if DEBUG 00238 printf ("format %p [%s] [%s]\n", fmt, fmt->name, fmt->long_name); 00239 #endif 00240 pdat.buf = (unsigned char *) data; 00241 pdat.buf_size = size > PROBE_MAX ? PROBE_MAX : size; 00242 score = fmt->read_probe (&pdat); 00243 #if DEBUG 00244 printf ("score: %d\n", score); 00245 #endif 00246 /*if (score < 50) return prev; */ 00247 } 00248 00249 if (is_image) 00250 { 00251 codec_ctx = avcodec_alloc_context (); 00252 codec = avcodec_find_decoder (image_codec_id); 00253 if (codec != NULL) 00254 { 00255 if (avcodec_open (codec_ctx, codec) != 0) 00256 { 00257 #if DEBUG 00258 printf ("open codec failed\n"); 00259 #endif 00260 codec = NULL; 00261 } 00262 } 00263 } 00264 else 00265 { 00266 bio_ctx = malloc (sizeof (ByteIOContext)); 00267 bio_buffer = malloc (BIOBUF_SIZE); 00268 00269 reader_state.data = data; 00270 reader_state.offset = 0; 00271 reader_state.size = size; 00272 00273 init_put_byte (bio_ctx, bio_buffer, 00274 BIOBUF_SIZE, 0, &reader_state, 00275 stream_read, NULL, stream_seek); 00276 00277 fmt->flags |= AVFMT_NOFILE; 00278 err = av_open_input_stream (&format_ctx, bio_ctx, "", fmt, NULL); 00279 if (err < 0) 00280 { 00281 #if DEBUG 00282 printf ("couldn't open input stream\n"); 00283 #endif 00284 goto out; 00285 } 00286 00287 err = av_find_stream_info (format_ctx); 00288 if (err < 0) 00289 { 00290 #if DEBUG 00291 printf ("couldn't find codec params\n"); 00292 #endif 00293 goto out; 00294 } 00295 00296 for (i = 0; i < format_ctx->nb_streams; i++) 00297 { 00298 codec_ctx = format_ctx->streams[i]->codec; 00299 if (codec_ctx->codec_type == CODEC_TYPE_VIDEO) 00300 { 00301 video_stream_index = i; 00302 codec = avcodec_find_decoder (codec_ctx->codec_id); 00303 if (codec == NULL) 00304 { 00305 #if DEBUG 00306 printf ("find_decoder failed\n"); 00307 #endif 00308 break; 00309 } 00310 err = avcodec_open (codec_ctx, codec); 00311 if (err != 0) 00312 { 00313 #if DEBUG 00314 printf ("failed to open codec\n"); 00315 #endif 00316 codec = NULL; 00317 } 00318 break; 00319 } 00320 } 00321 } 00322 00323 if (codec_ctx == NULL || codec == NULL) 00324 { 00325 #if DEBUG 00326 printf ("failed to open codec"); 00327 #endif 00328 goto out; 00329 } 00330 frame = avcodec_alloc_frame (); 00331 if (frame == NULL) 00332 { 00333 #if DEBUG 00334 printf ("failed to alloc frame"); 00335 #endif 00336 goto out; 00337 } 00338 00339 if (!is_image) 00340 { 00341 #if DEBUG 00342 printf ("duration: %lld\n", format_ctx->duration); 00343 if (format_ctx->duration == AV_NOPTS_VALUE) 00344 printf ("duration unknown\n"); 00345 #endif 00346 /* TODO: if duration is known seek to to some better place(?) */ 00347 ts = 10; // s 00348 ts = ts * AV_TIME_BASE; 00349 err = av_seek_frame (format_ctx, -1, ts, 0); 00350 if (err >= 0) 00351 { 00352 avcodec_flush_buffers (codec_ctx); 00353 } 00354 #if DEBUG 00355 else 00356 printf ("seeking failed %d\n", err); 00357 #endif 00358 } 00359 00360 frame_finished = 0; 00361 if (is_image) 00362 { 00363 avcodec_decode_video (codec_ctx, frame, &frame_finished, data, size); 00364 } 00365 else 00366 { 00367 while (1) 00368 { 00369 err = av_read_frame (format_ctx, &packet); 00370 if (err < 0) 00371 break; 00372 if (packet.stream_index == video_stream_index) 00373 { 00374 avcodec_decode_video (codec_ctx, 00375 frame, 00376 &frame_finished, 00377 packet.data, packet.size); 00378 if (frame_finished && frame->key_frame) 00379 { 00380 av_free_packet (&packet); 00381 break; 00382 } 00383 } 00384 av_free_packet (&packet); 00385 } 00386 } 00387 00388 if (!frame_finished || codec_ctx->width == 0 || codec_ctx->height == 0) 00389 goto out; 00390 00391 sar_num = codec_ctx->sample_aspect_ratio.num; 00392 sar_den = codec_ctx->sample_aspect_ratio.den; 00393 if (sar_num <= 0 || sar_den <= 0) 00394 { 00395 sar_num = 1; 00396 sar_den = 1; 00397 } 00398 if ((codec_ctx->width * sar_num) / sar_den > codec_ctx->height) 00399 { 00400 thumb_width = THUMBSIZE; 00401 thumb_height = (thumb_width * codec_ctx->height) / 00402 ((codec_ctx->width * sar_num) / sar_den); 00403 } 00404 else 00405 { 00406 thumb_height = THUMBSIZE; 00407 thumb_width = (thumb_height * 00408 ((codec_ctx->width * sar_num) / sar_den)) / 00409 codec_ctx->height; 00410 } 00411 if (thumb_width < 8) 00412 thumb_width = 8; 00413 if (thumb_height < 1) 00414 thumb_height = 1; 00415 #if DEBUG 00416 printf ("thumb dim: %d %d\n", thumb_width, thumb_height); 00417 #endif 00418 00419 scaler_ctx = 00420 sws_getContext (codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, 00421 thumb_width, thumb_height, PIX_FMT_RGB24, sws_flags, NULL, 00422 NULL, NULL); 00423 if (scaler_ctx == NULL) 00424 { 00425 #if DEBUG 00426 printf ("failed to alloc scaler\n"); 00427 #endif 00428 goto out; 00429 } 00430 thumb_frame = avcodec_alloc_frame (); 00431 thumb_buffer = 00432 av_malloc (avpicture_get_size (PIX_FMT_RGB24, thumb_width, thumb_height)); 00433 if (thumb_frame == NULL || thumb_buffer == NULL) 00434 { 00435 #if DEBUG 00436 printf ("failed to alloc thumb frame\n"); 00437 #endif 00438 goto out; 00439 } 00440 avpicture_fill ((AVPicture *) thumb_frame, thumb_buffer, 00441 PIX_FMT_RGB24, thumb_width, thumb_height); 00442 00443 sws_scale (scaler_ctx, 00444 frame->data, frame->linesize, 00445 0, codec_ctx->height, thumb_frame->data, thumb_frame->linesize); 00446 00447 encoder_output_buffer_size = MAX_THUMB_SIZE; 00448 encoder_output_buffer = av_malloc (encoder_output_buffer_size); 00449 if (encoder_output_buffer == NULL) 00450 { 00451 #if DEBUG 00452 printf ("couldn't alloc encoder output buf\n"); 00453 #endif 00454 goto out; 00455 } 00456 00457 enc_codec = avcodec_find_encoder_by_name ("png"); 00458 if (enc_codec == NULL) 00459 { 00460 #if DEBUG 00461 printf ("couldn't find encoder\n"); 00462 #endif 00463 goto out; 00464 } 00465 enc_codec_ctx = avcodec_alloc_context (); 00466 enc_codec_ctx->width = thumb_width; 00467 enc_codec_ctx->height = thumb_height; 00468 enc_codec_ctx->pix_fmt = PIX_FMT_RGB24; 00469 00470 if (avcodec_open (enc_codec_ctx, enc_codec) < 0) 00471 { 00472 #if DEBUG 00473 printf ("couldn't open encoder\n"); 00474 #endif 00475 enc_codec = NULL; 00476 goto out; 00477 } 00478 00479 err = avcodec_encode_video (enc_codec_ctx, 00480 encoder_output_buffer, 00481 encoder_output_buffer_size, thumb_frame); 00482 if (err <= 0) 00483 goto out; 00484 00485 binary = 00486 EXTRACTOR_binaryEncode ((const unsigned char *) encoder_output_buffer, 00487 err); 00488 if (binary != NULL) 00489 prev = addKeyword (EXTRACTOR_THUMBNAIL_DATA, binary, prev); 00490 00491 out: 00492 if (enc_codec != NULL) 00493 avcodec_close (enc_codec_ctx); 00494 if (enc_codec_ctx != NULL) 00495 av_free (enc_codec_ctx); 00496 if (encoder_output_buffer != NULL) 00497 av_free (encoder_output_buffer); 00498 if (scaler_ctx != NULL) 00499 sws_freeContext(scaler_ctx); 00500 if (codec != NULL) 00501 avcodec_close (codec_ctx); 00502 if (format_ctx != NULL) 00503 av_close_input_file (format_ctx); 00504 if (frame != NULL) 00505 av_free (frame); 00506 if (thumb_buffer != NULL) 00507 av_free (thumb_buffer); 00508 if (thumb_frame != NULL) 00509 av_free (thumb_frame); 00510 if (bio_ctx != NULL) 00511 free (bio_ctx); 00512 if (bio_buffer != NULL) 00513 free (bio_buffer); 00514 00515 return prev; 00516 }
| static int stream_read | ( | void * | opaque, | |
| uint8_t * | buf, | |||
| int | buf_size | |||
| ) | [static] |
Definition at line 54 of file thumbnailextractorffmpeg.c.
References StreamDescriptor::data, len, NULL, StreamDescriptor::offset, printf, and StreamDescriptor::size.
Referenced by libextractor_thumbnailffmpeg_extract().
00055 { 00056 struct StreamDescriptor *rs = (struct StreamDescriptor *) opaque; 00057 size_t len; 00058 #if DEBUG 00059 printf ("read_packet: %zu\n", buf_size); 00060 #endif 00061 if (rs) 00062 { 00063 if (rs->data == NULL) 00064 return -1; 00065 if (rs->offset >= rs->size) 00066 return 0; 00067 len = buf_size; 00068 if (rs->offset + len > rs->size) 00069 len = rs->size - rs->offset; 00070 00071 memcpy (buf, rs->data + rs->offset, len); 00072 rs->offset += len; 00073 #if DEBUG 00074 printf ("read_packet: len: %zu\n", len); 00075 #endif 00076 return len; 00077 } 00078 return -1; 00079 }
Definition at line 82 of file thumbnailextractorffmpeg.c.
References AVERROR, AVSEEK_SIZE, StreamDescriptor::offset, printf, and StreamDescriptor::size.
00083 { 00084 struct StreamDescriptor *rs = (struct StreamDescriptor *) opaque; 00085 offset_t off_abs; 00086 #if DEBUG 00087 printf ("my_seek: %lld %d\n", offset, whence); 00088 #endif 00089 if (rs) 00090 { 00091 if (whence == AVSEEK_SIZE) 00092 return (offset_t) rs->size; 00093 else if (whence == SEEK_CUR) 00094 off_abs = (offset_t) rs->offset + offset; 00095 else if (whence == SEEK_SET) 00096 off_abs = offset; 00097 else if (whence == SEEK_END) 00098 off_abs = (offset_t) rs->size + offset; 00099 else 00100 { 00101 printf ("whence error %d\n", whence); 00102 abort (); 00103 return AVERROR (EINVAL); 00104 } 00105 if (off_abs >= 0 && off_abs < (offset_t) rs->size) 00106 rs->offset = (size_t) off_abs; 00107 else 00108 off_abs = AVERROR (EINVAL); 00109 return off_abs; 00110 } 00111 return -1; 00112 }
struct MimeToDecoderMapping m2d_map[] [static] |
Initial value:
{
{"image/x-bmp", CODEC_ID_BMP},
{"image/gif", CODEC_ID_GIF},
{"image/jpeg", CODEC_ID_MJPEG},
{"image/png", CODEC_ID_PNG},
{"image/x-portable-pixmap", CODEC_ID_PPM},
{NULL, CODEC_ID_NONE}
}
Definition at line 137 of file thumbnailextractorffmpeg.c.
Referenced by libextractor_thumbnailffmpeg_extract().
1.5.1