AVbin  Version 10
Cross-platform audio/video media decoding library with long-term ABI support.
src/avbin.c
Go to the documentation of this file.
00001 /* avbin.c
00002  * Copyright 2012 AVbin Team
00003  *
00004  * This file is part of AVbin.
00005  *
00006  * AVbin is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 3 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * AVbin is distributed in the hope that it will be useful, but
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this program.  If not, see
00018  * <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 #include <stdarg.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 #include <avbin.h>
00026 
00027 /* libav */
00028 #include <libavformat/avformat.h>
00029 #include <libavcodec/avcodec.h>
00030 #include <libavutil/avutil.h>
00031 #include <libavutil/dict.h>
00032 #include <libavutil/mathematics.h>
00033 #include <libswscale/swscale.h>
00034 
00035 static int32_t avbin_thread_count = 1;
00036 
00037 struct _AVbinFile {
00038     AVFormatContext *context;
00039     AVPacket *packet;
00040 };
00041 
00042 struct _AVbinStream {
00043     int32_t type;
00044     AVFormatContext *format_context;
00045     AVCodecContext *codec_context;
00046     AVFrame *frame;
00047 };
00048 
00049 static AVbinLogCallback user_log_callback = NULL;
00050 
00055 static void avbin_log_callback(void *ptr,
00056                                int level,
00057                                const char *fmt,
00058                                va_list vl)
00059 {
00060     static char message[8192];
00061     const char *module = NULL;
00062 
00063 //    if (level > av_log_level || !user_log_callback)
00064     if (level > av_log_get_level() || !user_log_callback)
00065         return;
00066 
00067     if (ptr)
00068     {
00069         AVClass *avc = *(AVClass**) ptr;
00070         module = avc->item_name(ptr);
00071     }
00072 
00073     vsnprintf(message, sizeof message, fmt, vl);
00074     user_log_callback(module, (AVbinLogLevel) level, message);
00075 }
00076 
00077 int32_t avbin_get_version()
00078 {
00079     return AVBIN_VERSION;
00080 }
00081 
00082 AVbinInfo *avbin_get_info()
00083 {
00084     AVbinInfo *info = malloc(sizeof(*info));
00085 
00086     info->structure_size         = sizeof(*info);
00087     info->version                = avbin_get_version();
00088     info->version_string         = AVBIN_VERSION_STRING;
00089     info->build_date             = AVBIN_BUILD_DATE;
00090     info->repo                   = AVBIN_REPO;
00091     info->commit                 = AVBIN_COMMIT;
00092     info->backend                = AVBIN_BACKEND;
00093     info->backend_version_string = AVBIN_BACKEND_VERSION_STRING;
00094     info->backend_repo           = AVBIN_BACKEND_REPO;
00095     info->backend_commit         = AVBIN_BACKEND_COMMIT;
00096     return info;
00097 }
00098 
00099 // Deprecated - use avbin_get_info() instead.  Will be removed in version 12.
00100 int32_t avbin_get_ffmpeg_revision()
00101 {
00102     return 0;
00103 }
00104 
00105 // Deprecated - useless.  Will be removed in version 13.
00106 size_t avbin_get_audio_buffer_size()
00107 {
00108     return 192000;
00109 }
00110 
00111 int32_t avbin_have_feature(const char *feature)
00112 {
00113     if (strcmp(feature, "frame_rate") == 0)
00114     {
00115         // See note on avbin_have_feature() in avbin.h
00116         return 0;
00117     }
00118     if (strcmp(feature, "options") == 0)
00119         return 1;
00120     if (strcmp(feature, "info") == 0)
00121         return 1;
00122     return 0;
00123 }
00124 
00125 AVbinResult avbin_init()
00126 {
00127     return avbin_init_options(NULL);
00128 }
00129 
00130 AVbinResult avbin_init_options(AVbinOptions * options_ptr)
00131 {
00132     if (options_ptr == NULL)
00133     {
00134         options_ptr = malloc(sizeof(options_ptr));
00135         if (options_ptr == NULL)
00136             return AVBIN_RESULT_ERROR;
00137 
00138         // Set defaults...
00139         options_ptr->structure_size = sizeof(AVbinOptions);
00140         options_ptr->thread_count = 1;
00141     }
00142 
00143     // What version did we get?
00144     AVbinOptions * options = NULL;
00145     if (options_ptr->structure_size == sizeof(AVbinOptions))
00146     {
00147         options = options_ptr;
00148     } else {
00149         return AVBIN_RESULT_ERROR;
00150     }
00151 
00152     // Stupid choices deserve single-threading
00153     if (options->thread_count < 0)
00154         options->thread_count = 1;
00155 
00156     avbin_thread_count = options->thread_count;
00157 
00158     av_register_all();
00159     avcodec_register_all();
00160 
00161     return AVBIN_RESULT_OK;
00162 }
00163 
00164 AVbinResult avbin_set_log_level(AVbinLogLevel level)
00165 {
00166     av_log_set_level(level);
00167     return AVBIN_RESULT_OK;
00168 }
00169 
00170 AVbinResult avbin_set_log_callback(AVbinLogCallback callback)
00171 {
00172     user_log_callback = callback;
00173 
00174     /* Note av_log_set_callback looks set to disappear at
00175      * LIBAVUTIL_VERSION >= 50; at which point av_vlog must be
00176      * set directly.
00177      */
00178     if (callback)
00179         av_log_set_callback(avbin_log_callback);
00180     else
00181         av_log_set_callback(av_log_default_callback);
00182     return AVBIN_RESULT_OK;
00183 }
00184 
00185 AVbinFile *avbin_open_filename(const char *filename) { return avbin_open_filename_with_format(filename, NULL); }
00186 
00187 AVbinFile *avbin_open_filename_with_format(const char *filename, char* format)
00188 {
00189     AVbinFile *file = malloc(sizeof *file);
00190     AVInputFormat *avformat = NULL;
00191     if (format) avformat = av_find_input_format(format);
00192 
00193     file->context = NULL;    // Zero-initialize
00194     if (avformat_open_input(&file->context, filename, avformat, NULL) != 0)
00195         goto error;
00196 
00197     if (avformat_find_stream_info(file->context, NULL) < 0)
00198       goto error;
00199 
00200     file->packet = NULL;
00201     return file;
00202 
00203 error:
00204     free(file);
00205     return NULL;
00206 }
00207 
00208 void avbin_close_file(AVbinFile *file)
00209 {
00210     if (file->packet)
00211     {
00212         av_free_packet(file->packet);
00213         free(file->packet);
00214     }
00215 
00216     avformat_close_input(&file->context);
00217     free(file);
00218 }
00219 
00220 AVbinResult avbin_seek_file(AVbinFile *file, AVbinTimestamp timestamp)
00221 {
00222     int i;
00223     AVCodecContext *codec_context;
00224     int flags = 0;
00225 
00226     if (!timestamp)
00227     {
00228         flags = AVSEEK_FLAG_ANY | AVSEEK_FLAG_BYTE;
00229         if (av_seek_frame(file->context, -1, 0, flags) < 0)
00230             return AVBIN_RESULT_ERROR;
00231     }
00232     else
00233     {
00234         flags = AVSEEK_FLAG_BACKWARD;
00235         if (av_seek_frame(file->context, -1, timestamp, flags) < 0)
00236             return AVBIN_RESULT_ERROR;
00237     }
00238 
00239     for (i = 0; i < file->context->nb_streams; i++)
00240     {
00241         codec_context = file->context->streams[i]->codec;
00242         if (codec_context && codec_context->codec)
00243             avcodec_flush_buffers(codec_context);
00244     }
00245     return AVBIN_RESULT_OK;
00246 }
00247 
00248 AVbinResult avbin_file_info(AVbinFile *file, AVbinFileInfo *info)
00249 {
00250     if (info->structure_size < sizeof *info)
00251         return AVBIN_RESULT_ERROR;
00252 
00253     info->n_streams = file->context->nb_streams;
00254     info->start_time = file->context->start_time;
00255     info->duration = file->context->duration;
00256 
00257     // Zero-initialize fields first
00258     memset(info->title, 0, sizeof(info->title));
00259     memset(info->author, 0, sizeof(info->author));
00260     memset(info->copyright, 0, sizeof(info->copyright));
00261     memset(info->comment, 0, sizeof(info->comment));
00262     memset(info->album, 0, sizeof(info->album));
00263     memset(info->genre, 0, sizeof(info->genre));
00264     info->year = 0;
00265     info->track = 0;
00266 
00267     AVDictionaryEntry* entry;
00268     if ((entry = av_dict_get(file->context->metadata, "title", NULL, 0)) != NULL)  {
00269       strncpy(info->title, entry->value, sizeof(info->title));
00270     }
00271 
00272     if (((entry = av_dict_get(file->context->metadata, "artist", NULL, 0)) != NULL) ||
00273        (entry = av_dict_get(file->context->metadata, "album_artist", NULL, 0)) != NULL) {
00274       strncpy(info->author, entry->value, sizeof(info->author));
00275     }
00276     if ((entry = av_dict_get(file->context->metadata, "copyright", NULL, 0)) != NULL)  {
00277       strncpy(info->copyright, entry->value, sizeof(info->copyright));
00278     }
00279     if ((entry = av_dict_get(file->context->metadata, "comment", NULL, 0)) != NULL)  {
00280       strncpy(info->comment, entry->value, sizeof(info->comment));
00281     }
00282     if ((entry = av_dict_get(file->context->metadata, "album", NULL, 0)) != NULL)  {
00283       strncpy(info->album, entry->value, sizeof(info->album));
00284     }
00285     if ((entry = av_dict_get(file->context->metadata, "date", NULL, 0)) != NULL)  {
00286       info->year = atoi(entry->value);
00287     }
00288     if ((entry = av_dict_get(file->context->metadata, "track", NULL, 0)) != NULL)  {
00289       info->track = atoi(entry->value);
00290     }
00291     if ((entry = av_dict_get(file->context->metadata, "genre", NULL, 0)) != NULL)  {
00292       strncpy(info->genre, entry->value, sizeof(info->genre));
00293     }
00294 
00295     return AVBIN_RESULT_OK;
00296 }
00297 
00298 AVbinResult avbin_stream_info(AVbinFile *file, int32_t stream_index,
00299                       AVbinStreamInfo *info)
00300 {
00301     AVCodecContext *context = file->context->streams[stream_index]->codec;
00302     AVbinStreamInfo8 *info_8 = NULL;
00303 
00304     /* Error if not large enough for version 1 */
00305     if (info->structure_size < sizeof *info)
00306         return AVBIN_RESULT_ERROR;
00307 
00308     /* Version 8 adds frame_rate feature, Version 11 removes it, see note on
00309        avbin_have_feature() in avbin.h */
00310     if (info->structure_size >= sizeof(AVbinStreamInfo8))
00311         info_8 = (AVbinStreamInfo8 *) info;
00312 
00313     switch (context->codec_type)
00314     {
00315         case AVMEDIA_TYPE_VIDEO:
00316             info->type = AVBIN_STREAM_TYPE_VIDEO;
00317             info->video.width = context->width;
00318             info->video.height = context->height;
00319             info->video.sample_aspect_num = context->sample_aspect_ratio.num;
00320             info->video.sample_aspect_den = context->sample_aspect_ratio.den;
00321 
00322 /* See note on avbin_have_feature() in avbin.h
00323             if (info_8)
00324             {
00325                 AVRational frame_rate = \
00326                     file->context->streams[stream_index]->r_frame_rate;
00327                 info_8->video.frame_rate_num = frame_rate.num;
00328                 info_8->video.frame_rate_den = frame_rate.den;
00329 
00330                 // Work around bug in Libav: if frame rate over 1000, divide
00331                 // by 1000.
00332                 if (info_8->video.frame_rate_num /
00333                         info_8->video.frame_rate_den > 1000)
00334                     info_8->video.frame_rate_den *= 1000;
00335             }
00336 */
00337             if (info_8)
00338             {
00339                 info_8->video.frame_rate_num = 0;
00340                 info_8->video.frame_rate_den = 0;
00341             }
00342             break;
00343         case AVMEDIA_TYPE_AUDIO:
00344             info->type = AVBIN_STREAM_TYPE_AUDIO;
00345             info->audio.sample_rate = context->sample_rate;
00346             info->audio.channels = context->channels;
00347             switch (context->sample_fmt)
00348             {
00349                 case AV_SAMPLE_FMT_U8:
00350                     info->audio.sample_format = AVBIN_SAMPLE_FORMAT_U8;
00351                     info->audio.sample_bits = 8;
00352                     break;
00353                 case AV_SAMPLE_FMT_S16:
00354                     info->audio.sample_format = AVBIN_SAMPLE_FORMAT_S16;
00355                     info->audio.sample_bits = 16;
00356                     break;
00357                 case AV_SAMPLE_FMT_S32:
00358                     info->audio.sample_format = AVBIN_SAMPLE_FORMAT_S32;
00359                     info->audio.sample_bits = 32;
00360                     break;
00361                 case AV_SAMPLE_FMT_FLT:
00362                     info->audio.sample_format = AVBIN_SAMPLE_FORMAT_FLOAT;
00363                     info->audio.sample_bits = 32;
00364                     break;
00365                 default:
00366                   // Unknown sample format
00367                   info->audio.sample_format = -1;
00368                   info->audio.sample_bits = -1;
00369                   break;
00370 
00371                 // TODO: support planar formats
00372             }
00373             break;
00374 
00375         default:
00376             info->type = AVBIN_STREAM_TYPE_UNKNOWN;
00377             break;
00378     }
00379 
00380     return AVBIN_RESULT_OK;
00381 }
00382 
00383 AVbinStream *avbin_open_stream(AVbinFile *file, int32_t index)
00384 {
00385     AVCodecContext *codec_context;
00386     AVCodec *codec;
00387 
00388     if (index < 0 || index >= file->context->nb_streams)
00389         return NULL;
00390 
00391     codec_context = file->context->streams[index]->codec;
00392     codec = avcodec_find_decoder(codec_context->codec_id);
00393     if (!codec)
00394         return NULL;
00395 
00396     /* The Libav api example does this (see libav/libavcodec-api-example.c).
00397      * The only explanation is "we do not send complete frames".  I tried
00398      * adding it, and there seemed to be no effect either way.  I'm going to
00399      * leave it here commented out just in case we find the need to enable it
00400      * in the future.
00401      */
00402 /*    if (codec->capabilities & CODEC_CAP_TRUNCATED)
00403  *       codec_context->flags |= CODEC_FLAG_TRUNCATED;
00404  */
00405     if (avbin_thread_count != 1)
00406         codec_context->thread_count = avbin_thread_count;
00407 
00408     if (avcodec_open2(codec_context, codec, NULL) < 0)
00409         return NULL;
00410 
00411     AVbinStream *stream = malloc(sizeof *stream);
00412     stream->format_context = file->context;
00413     stream->codec_context = codec_context;
00414     stream->type = codec_context->codec_type;
00415     stream->frame = avcodec_alloc_frame();
00416 
00417     return stream;
00418 }
00419 
00420 void avbin_close_stream(AVbinStream *stream)
00421 {
00422     if (stream->frame)
00423         avcodec_free_frame(&stream->frame);
00424     avcodec_close(stream->codec_context);
00425     free(stream);
00426 }
00427 
00428 int32_t avbin_read(AVbinFile *file, AVbinPacket *packet)
00429 {
00430     if (packet->structure_size < sizeof *packet)
00431         return AVBIN_RESULT_ERROR;
00432 
00433     if (file->packet)
00434         av_free_packet(file->packet);
00435     else
00436         file->packet = malloc(sizeof *file->packet);
00437 
00438     if (av_read_frame(file->context, file->packet) < 0)
00439         return AVBIN_RESULT_ERROR;
00440 
00441     packet->timestamp = av_rescale_q(file->packet->dts,
00442         file->context->streams[file->packet->stream_index]->time_base,
00443         AV_TIME_BASE_Q);
00444     packet->stream_index = file->packet->stream_index;
00445     packet->data = file->packet->data;
00446     packet->size = file->packet->size;
00447 
00448     return AVBIN_RESULT_OK;
00449 }
00450 
00451 int32_t avbin_decode_audio(AVbinStream *stream,
00452                        uint8_t *data_in, size_t size_in,
00453                        uint8_t *data_out, int *size_out)
00454 {
00455     int bytes_used;
00456     if (stream->type != AVMEDIA_TYPE_AUDIO)
00457         return AVBIN_RESULT_ERROR;
00458 
00459     // Some decoders read big chunks at a time, so you have to make a bigger buffer
00460     uint8_t inbuf[size_in + FF_INPUT_BUFFER_PADDING_SIZE];
00461     // Set the padding portion of the buffer to all zeros
00462     memset(inbuf + size_in, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00463     // Copy the data into the padded buffer
00464     memcpy(inbuf, data_in, size_in);
00465 
00466     AVPacket packet;
00467     av_init_packet(&packet);
00468     packet.data = inbuf;
00469     packet.size = size_in;
00470 
00471     int got_frame = 0;
00472     bytes_used = avcodec_decode_audio4(stream->codec_context, stream->frame, &got_frame, &packet);
00473 
00474     if (bytes_used < 0)
00475         return AVBIN_RESULT_ERROR;
00476 
00477     // TODO: support planar formats
00478     if (got_frame) {
00479       int plane_size;
00480       int data_size = av_samples_get_buffer_size(&plane_size,
00481                                        stream->codec_context->channels,
00482                                        stream->frame->nb_samples,
00483                                        stream->codec_context->sample_fmt, 1);
00484       if (*size_out < data_size) {
00485          av_log(stream->codec_context, AV_LOG_ERROR, "Output audio buffer is too small for current audio frame!");
00486          return AVBIN_RESULT_ERROR;
00487       }
00488 
00489       memcpy(data_out, stream->frame->extended_data[0], data_size);
00490       *size_out = data_size;
00491     } else {
00492       *size_out = 0;
00493     }
00494 
00495     return bytes_used;
00496 }
00497 
00498 int32_t avbin_decode_video(AVbinStream *stream,
00499                        uint8_t *data_in, size_t size_in,
00500                        uint8_t *data_out)
00501 {
00502     AVPicture picture_rgb;
00503     int got_picture;
00504     int width = stream->codec_context->width;
00505     int height = stream->codec_context->height;
00506     int bytes_used;
00507 
00508     if (stream->type != AVMEDIA_TYPE_VIDEO)
00509         return AVBIN_RESULT_ERROR;
00510 
00511     // Some decoders read big chunks at a time, so you have to make a bigger buffer
00512     uint8_t inbuf[size_in + FF_INPUT_BUFFER_PADDING_SIZE];
00513     // Set the padding portion of the buffer to all zeros
00514     memset(inbuf + size_in, 0, FF_INPUT_BUFFER_PADDING_SIZE);
00515     // Copy the data into the padded buffer
00516     memcpy(inbuf, data_in, size_in);
00517 
00518     AVPacket packet;
00519     av_init_packet(&packet);
00520     packet.data = inbuf;
00521     packet.size = size_in;
00522 
00523     bytes_used = avcodec_decode_video2(stream->codec_context,
00524                                 stream->frame, &got_picture,
00525                                 &packet);
00526 
00527     if (!got_picture)
00528         return AVBIN_RESULT_ERROR;
00529 
00530 
00531     avpicture_fill(&picture_rgb, data_out, PIX_FMT_RGB24, width, height);
00532     static struct SwsContext *img_convert_ctx = NULL;
00533     img_convert_ctx = sws_getCachedContext(img_convert_ctx,width, height,stream->codec_context->pix_fmt,width, height,PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
00534     sws_scale(img_convert_ctx, (const uint8_t* const*)stream->frame->data, stream->frame->linesize,0, height, picture_rgb.data, picture_rgb.linesize);
00535 
00536     return bytes_used;
00537 }
 All Data Structures Files Functions Variables