"Fossies" - the Fresh Open Source Software Archive

Member "libextractor-1.11/src/plugins/previewopus_extractor.c" (30 Jan 2021, 33180 Bytes) of package /linux/privat/libextractor-1.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "previewopus_extractor.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8_vs_1.9.

    1 /*
    2      This file is part of libextractor.
    3      Copyright Copyright (C) 2008, 2013 Bruno Cabral and Christian Grothoff
    4 
    5      libextractor is free software; you can redistribute it and/or modify
    6      it under the terms of the GNU General Public License as published
    7      by the Free Software Foundation; either version 3, or (at your
    8      option) any later version.
    9 
   10      libextractor is distributed in the hope that it will be useful, but
   11      WITHOUT ANY WARRANTY; without even the implied warranty of
   12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13      General Public License for more details.
   14 
   15      You should have received a copy of the GNU General Public License
   16      along with libextractor; see the file COPYING.  If not, write to the
   17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   18      Boston, MA 02110-1301, USA.
   19  */
   20 /**
   21  * @file previewopus_extractor.c
   22  * @author Bruno Cabral
   23  * @author Christian Grothoff
   24  * @brief this extractor produces a binary encoded
   25  * audio snippet of music/video files using ffmpeg libs.
   26  *
   27  * Based on ffmpeg samples.
   28  *
   29  * Note that ffmpeg has a few issues:
   30  * (1) there are no recent official releases of the ffmpeg libs
   31  * (2) ffmpeg has a history of having security issues (parser is not robust)
   32  *
   33  *  So this plugin cannot be recommended for system with high security
   34  *requirements.
   35  */
   36 #include "platform.h"
   37 #include "extractor.h"
   38 #include <magic.h>
   39 
   40 #include <libavutil/avutil.h>
   41 #include <libavutil/audio_fifo.h>
   42 #include <libavutil/opt.h>
   43 #include <libavutil/mathematics.h>
   44 #include <libavformat/avformat.h>
   45 #include <libavcodec/avcodec.h>
   46 #include <libswscale/swscale.h>
   47 #include <libavresample/avresample.h>
   48 
   49 
   50 /**
   51  * Set to 1 to enable debug output.
   52  */
   53 #define DEBUG 0
   54 
   55 /**
   56  * Set to 1 to enable a output file for testing.
   57  */
   58 #define OUTPUT_FILE 0
   59 
   60 
   61 /**
   62  * Maximum size in bytes for the preview.
   63  */
   64 #define MAX_SIZE (28 * 1024)
   65 
   66 /**
   67  * HardLimit for file
   68  */
   69 #define HARD_LIMIT_SIZE (50 * 1024)
   70 
   71 
   72 /** The output bit rate in kbit/s */
   73 #define OUTPUT_BIT_RATE 28000
   74 /** The number of output channels */
   75 #define OUTPUT_CHANNELS 2
   76 /** The audio sample output format */
   77 #define OUTPUT_SAMPLE_FORMAT AV_SAMPLE_FMT_S16
   78 
   79 
   80 /** Our output buffer*/
   81 static unsigned char *buffer;
   82 
   83 /** Actual output buffer size */
   84 static int totalSize;
   85 
   86 /**
   87  * Convert an error code into a text message.
   88  * @param error Error code to be converted
   89  * @return Corresponding error text (not thread-safe)
   90  */
   91 static char *const
   92 get_error_text (const int error)
   93 {
   94   static char error_buffer[255];
   95   av_strerror (error, error_buffer, sizeof(error_buffer));
   96   return error_buffer;
   97 }
   98 
   99 
  100 /**
  101  * Read callback.
  102  *
  103  * @param opaque the 'struct EXTRACTOR_ExtractContext'
  104  * @param buf where to write data
  105  * @param buf_size how many bytes to read
  106  * @return -1 on error (or for unknown file size)
  107  */
  108 static int
  109 read_cb (void *opaque,
  110          uint8_t *buf,
  111          int buf_size)
  112 {
  113   struct EXTRACTOR_ExtractContext *ec = opaque;
  114   void *data;
  115   ssize_t ret;
  116 
  117   ret = ec->read (ec->cls, &data, buf_size);
  118   if (ret <= 0)
  119     return ret;
  120   memcpy (buf, data, ret);
  121   return ret;
  122 }
  123 
  124 
  125 /**
  126  * Seek callback.
  127  *
  128  * @param opaque the 'struct EXTRACTOR_ExtractContext'
  129  * @param offset where to seek
  130  * @param whence how to seek; AVSEEK_SIZE to return file size without seeking
  131  * @return -1 on error (or for unknown file size)
  132  */
  133 static int64_t
  134 seek_cb (void *opaque,
  135          int64_t offset,
  136          int whence)
  137 {
  138   struct EXTRACTOR_ExtractContext *ec = opaque;
  139 
  140   if (AVSEEK_SIZE == whence)
  141     return ec->get_size (ec->cls);
  142   return ec->seek (ec->cls, offset, whence);
  143 }
  144 
  145 
  146 /**
  147  * write callback.
  148  *
  149  * @param opaque NULL
  150  * @param pBuffer to write
  151  * @param pBufferSize , amount to write
  152  * @return 0 on error
  153  */
  154 static int
  155 writePacket (void *opaque,
  156              unsigned char *pBuffer,
  157              int pBufferSize)
  158 {
  159   int sizeToCopy = pBufferSize;
  160 
  161   if ( (totalSize + pBufferSize) > HARD_LIMIT_SIZE)
  162     sizeToCopy = HARD_LIMIT_SIZE - totalSize;
  163 
  164   memcpy (buffer + totalSize, pBuffer, sizeToCopy);
  165   totalSize += sizeToCopy;
  166   return sizeToCopy;
  167 }
  168 
  169 
  170 /**
  171  * Open an output file and the required encoder.
  172  * Also set some basic encoder parameters.
  173  * Some of these parameters are based on the input file's parameters.
  174  */
  175 static int
  176 open_output_file (
  177   AVCodecContext *input_codec_context,
  178   AVFormatContext **output_format_context,
  179   AVCodecContext **output_codec_context)
  180 {
  181   AVStream *stream               = NULL;
  182   AVCodec *output_codec          = NULL;
  183   AVIOContext *io_ctx;
  184   int error;
  185   unsigned char *iob;
  186 
  187   if (NULL == (iob = av_malloc (16 * 1024)))
  188     return AVERROR_EXIT;
  189   if (NULL == (io_ctx = avio_alloc_context (iob, 16 * 1024,
  190                                             AVIO_FLAG_WRITE, NULL,
  191                                             NULL,
  192                                             &writePacket /* no writing */,
  193                                             NULL)))
  194   {
  195     av_free (iob);
  196     return AVERROR_EXIT;
  197   }
  198   if (NULL == ((*output_format_context) = avformat_alloc_context ()))
  199   {
  200     av_free (io_ctx);
  201     return AVERROR_EXIT;
  202   }
  203   (*output_format_context)->pb = io_ctx;
  204 
  205   /** Guess the desired container format based on the file extension. */
  206   if (! ((*output_format_context)->oformat = av_guess_format (NULL,
  207                                                               "file.ogg",
  208                                                               NULL)))
  209   {
  210 #if DEBUG
  211     fprintf (stderr, "Could not find output file format\n");
  212 #endif
  213     error = AVERROR (ENOSYS);
  214     goto cleanup;
  215   }
  216 
  217   /** Find the encoder to be used by its name. */
  218   if (! (output_codec = avcodec_find_encoder (AV_CODEC_ID_OPUS)))
  219   {
  220 #if DEBUG
  221     fprintf (stderr, "Could not find an OPUS encoder.\n");
  222 #endif
  223     error = AVERROR (ENOSYS);
  224     goto cleanup;
  225   }
  226 
  227   /** Create a new audio stream in the output file container. */
  228   if (! (stream = avformat_new_stream (*output_format_context, output_codec)))
  229   {
  230 #if DEBUG
  231     fprintf (stderr, "Could not create new stream\n");
  232 #endif
  233     error = AVERROR (ENOMEM);
  234     goto cleanup;
  235   }
  236 
  237   /** Save the encoder context for easiert access later. */
  238   *output_codec_context = stream->codec;
  239 
  240   /**
  241    * Set the basic encoder parameters.
  242    * The input file's sample rate is used to avoid a sample rate conversion.
  243    */
  244   (*output_codec_context)->channels       = OUTPUT_CHANNELS;
  245   (*output_codec_context)->channel_layout = av_get_default_channel_layout (
  246     OUTPUT_CHANNELS);
  247   (*output_codec_context)->sample_rate    = 48000; // Opus need 48000
  248   (*output_codec_context)->sample_fmt     = AV_SAMPLE_FMT_S16;
  249   (*output_codec_context)->bit_rate       = OUTPUT_BIT_RATE;
  250 
  251   /** Open the encoder for the audio stream to use it later. */
  252   if ((error = avcodec_open2 (*output_codec_context, output_codec, NULL)) < 0)
  253   {
  254 #if DEBUG
  255     fprintf (stderr, "Could not open output codec (error '%s')\n",
  256              get_error_text (error));
  257 #endif
  258     goto cleanup;
  259   }
  260   return 0;
  261 
  262 cleanup:
  263   av_free (io_ctx);
  264   return error < 0 ? error : AVERROR_EXIT;
  265 }
  266 
  267 
  268 /** Initialize one data packet for reading or writing. */
  269 static void
  270 init_packet (AVPacket *packet)
  271 {
  272   av_init_packet (packet);
  273   /** Set the packet data and size so that it is recognized as being empty. */
  274   packet->data = NULL;
  275   packet->size = 0;
  276 }
  277 
  278 
  279 /** Initialize one audio frame for reading from the input file */
  280 static int
  281 init_input_frame (AVFrame **frame)
  282 {
  283   *frame = av_frame_alloc ();
  284   if (NULL == *frame)
  285   {
  286 #if DEBUG
  287     fprintf (stderr, "Could not allocate input frame\n");
  288 #endif
  289     return AVERROR (ENOMEM);
  290   }
  291   return 0;
  292 }
  293 
  294 
  295 /**
  296  * Initialize the audio resampler based on the input and output codec settings.
  297  * If the input and output sample formats differ, a conversion is required
  298  * libavresample takes care of this, but requires initialization.
  299  */
  300 static int
  301 init_resampler (AVCodecContext *input_codec_context,
  302                 AVCodecContext *output_codec_context,
  303                 AVAudioResampleContext  **resample_context)
  304 {
  305   /**
  306    * Only initialize the resampler if it is necessary, i.e.,
  307    * if and only if the sample formats differ.
  308    */
  309   if ((input_codec_context->sample_fmt != output_codec_context->sample_fmt) ||
  310       (input_codec_context->channels != output_codec_context->channels) )
  311   {
  312     int error;
  313 
  314     /** Create a resampler context for the conversion. */
  315     if (! (*resample_context = avresample_alloc_context ()))
  316     {
  317 #if DEBUG
  318       fprintf (stderr, "Could not allocate resample context\n");
  319 #endif
  320       return AVERROR (ENOMEM);
  321     }
  322 
  323 
  324     /**
  325      * Set the conversion parameters.
  326      * Default channel layouts based on the number of channels
  327      * are assumed for simplicity (they are sometimes not detected
  328      * properly by the demuxer and/or decoder).
  329      */av_opt_set_int (*resample_context, "in_channel_layout",
  330                     av_get_default_channel_layout (
  331                       input_codec_context->channels), 0);
  332     av_opt_set_int (*resample_context, "out_channel_layout",
  333                     av_get_default_channel_layout (
  334                       output_codec_context->channels), 0);
  335     av_opt_set_int (*resample_context, "in_sample_rate",
  336                     input_codec_context->sample_rate, 0);
  337     av_opt_set_int (*resample_context, "out_sample_rate",
  338                     output_codec_context->sample_rate, 0);
  339     av_opt_set_int (*resample_context, "in_sample_fmt",
  340                     input_codec_context->sample_fmt, 0);
  341     av_opt_set_int (*resample_context, "out_sample_fmt",
  342                     output_codec_context->sample_fmt, 0);
  343 
  344     /** Open the resampler with the specified parameters. */
  345     if ((error = avresample_open (*resample_context)) < 0)
  346     {
  347 #if DEBUG
  348       fprintf (stderr, "Could not open resample context\n");
  349 #endif
  350       avresample_free (resample_context);
  351       return error;
  352     }
  353   }
  354   return 0;
  355 }
  356 
  357 
  358 /** Initialize a FIFO buffer for the audio samples to be encoded. */
  359 static int
  360 init_fifo (AVAudioFifo **fifo)
  361 {
  362   /** Create the FIFO buffer based on the specified output sample format. */
  363   if (! (*fifo = av_audio_fifo_alloc (OUTPUT_SAMPLE_FORMAT, OUTPUT_CHANNELS,
  364                                       1)))
  365   {
  366 #if DEBUG
  367     fprintf (stderr, "Could not allocate FIFO\n");
  368 #endif
  369     return AVERROR (ENOMEM);
  370   }
  371   return 0;
  372 }
  373 
  374 
  375 /** Write the header of the output file container. */
  376 static int
  377 write_output_file_header (AVFormatContext *output_format_context)
  378 {
  379   int error;
  380   if ((error = avformat_write_header (output_format_context, NULL)) < 0)
  381   {
  382 #if DEBUG
  383     fprintf (stderr, "Could not write output file header (error '%s')\n",
  384              get_error_text (error));
  385 #endif
  386     return error;
  387   }
  388   return 0;
  389 }
  390 
  391 
  392 /** Decode one audio frame from the input file. */
  393 static int
  394 decode_audio_frame (AVFrame *frame,
  395                     AVFormatContext *input_format_context,
  396                     AVCodecContext *input_codec_context, int audio_stream_index,
  397                     int *data_present, int *finished)
  398 {
  399   /** Packet used for temporary storage. */
  400   AVPacket input_packet;
  401   int error;
  402   init_packet (&input_packet);
  403 
  404   /** Read one audio frame from the input file into a temporary packet. */
  405   while (1)
  406   {
  407     if ((error = av_read_frame (input_format_context, &input_packet)) < 0)
  408     {
  409       /** If we are the the end of the file, flush the decoder below. */
  410       if (error == AVERROR_EOF)
  411       {
  412 #if DEBUG
  413         fprintf (stderr, "EOF in decode_audio\n");
  414 #endif
  415         *finished = 1;
  416       }
  417       else
  418       {
  419 #if DEBUG
  420         fprintf (stderr, "Could not read frame (error '%s')\n",
  421                  get_error_text (error));
  422 #endif
  423         return error;
  424       }
  425     }
  426 
  427     if (input_packet.stream_index == audio_stream_index)
  428       break;
  429   }
  430 
  431   /**
  432    * Decode the audio frame stored in the temporary packet.
  433    * The input audio stream decoder is used to do this.
  434    * If we are at the end of the file, pass an empty packet to the decoder
  435    * to flush it.
  436    */if ((error = avcodec_decode_audio4 (input_codec_context, frame,
  437                                       data_present, &input_packet)) < 0)
  438   {
  439 #if DEBUG
  440     fprintf (stderr, "Could not decode frame (error '%s')\n",
  441              get_error_text (error));
  442 #endif
  443     av_packet_unref (&input_packet);
  444     return error;
  445   }
  446 
  447   /**
  448    * If the decoder has not been flushed completely, we are not finished,
  449    * so that this function has to be called again.
  450    */
  451   if (*finished && *data_present)
  452     *finished = 0;
  453   av_packet_unref (&input_packet);
  454   return 0;
  455 }
  456 
  457 
  458 /**
  459  * Initialize a temporary storage for the specified number of audio samples.
  460  * The conversion requires temporary storage due to the different format.
  461  * The number of audio samples to be allocated is specified in frame_size.
  462  */
  463 static int
  464 init_converted_samples (uint8_t ***converted_input_samples, int*out_linesize,
  465                         AVCodecContext *output_codec_context,
  466                         int frame_size)
  467 {
  468   int error;
  469 
  470   /**
  471    * Allocate as many pointers as there are audio channels.
  472    * Each pointer will later point to the audio samples of the corresponding
  473    * channels (although it may be NULL for interleaved formats).
  474    */if (! (*converted_input_samples = calloc (output_codec_context->channels,
  475                                             sizeof(**converted_input_samples))))
  476   {
  477 #if DEBUG
  478     fprintf (stderr, "Could not allocate converted input sample pointers\n");
  479 #endif
  480     return AVERROR (ENOMEM);
  481   }
  482 
  483   /**
  484    * Allocate memory for the samples of all channels in one consecutive
  485    * block for convenience.
  486    */
  487   if ((error = av_samples_alloc (*converted_input_samples, out_linesize,
  488                                  output_codec_context->channels,
  489                                  frame_size,
  490                                  output_codec_context->sample_fmt, 0)) < 0)
  491   {
  492 #if DEBUG
  493     fprintf (stderr,
  494              "Could not allocate converted input samples (error '%s')\n",
  495              get_error_text (error));
  496 #endif
  497     av_freep (&(*converted_input_samples)[0]);
  498     free (*converted_input_samples);
  499     return error;
  500   }
  501   return 0;
  502 }
  503 
  504 
  505 /**
  506  * Convert the input audio samples into the output sample format.
  507  * The conversion happens on a per-frame basis, the size of which is specified
  508  * by frame_size.
  509  */
  510 static int
  511 convert_samples (uint8_t **input_data,
  512                  uint8_t **converted_data, const int in_sample, const int
  513                  out_sample, const int out_linesize,
  514                  AVAudioResampleContext  *resample_context)
  515 {
  516   int error;
  517 
  518   /** Convert the samples using the resampler. */
  519   if ((error = avresample_convert (resample_context, converted_data,
  520                                    out_linesize,
  521                                    out_sample, input_data, 0, in_sample)) < 0)
  522   {
  523 #if DEBUG
  524     fprintf (stderr, "Could not convert input samples (error '%s')\n",
  525              get_error_text (error));
  526 #endif
  527     return error;
  528   }
  529 
  530 
  531   /**
  532    * Perform a sanity check so that the number of converted samples is
  533    * not greater than the number of samples to be converted.
  534    * If the sample rates differ, this case has to be handled differently
  535    */if (avresample_available (resample_context))
  536   {
  537 #if DEBUG
  538     fprintf (stderr, "%i Converted samples left over\n",avresample_available (
  539                resample_context));
  540 #endif
  541   }
  542 
  543 
  544   return 0;
  545 }
  546 
  547 
  548 /** Add converted input audio samples to the FIFO buffer for later processing. */
  549 static int
  550 add_samples_to_fifo (AVAudioFifo *fifo,
  551                      uint8_t **converted_input_samples,
  552                      const int frame_size)
  553 {
  554   int error;
  555 
  556   /**
  557    * Make the FIFO as large as it needs to be to hold both,
  558    * the old and the new samples.
  559    */
  560   if ((error = av_audio_fifo_realloc (fifo, av_audio_fifo_size (fifo)
  561                                       + frame_size)) < 0)
  562   {
  563 #if DEBUG
  564     fprintf (stderr, "Could not reallocate FIFO\n");
  565 #endif
  566     return error;
  567   }
  568 
  569   /** Store the new samples in the FIFO buffer. */
  570   if (av_audio_fifo_write (fifo, (void **) converted_input_samples,
  571                            frame_size) < frame_size)
  572   {
  573 #if DEBUG
  574     fprintf (stderr, "Could not write data to FIFO\n");
  575 #endif
  576     return AVERROR_EXIT;
  577   }
  578   return 0;
  579 }
  580 
  581 
  582 /**
  583  * Read one audio frame from the input file, decodes, converts and stores
  584  * it in the FIFO buffer.
  585  */
  586 static int
  587 read_decode_convert_and_store (AVAudioFifo *fifo,
  588                                AVFormatContext *input_format_context,
  589                                AVCodecContext *input_codec_context,
  590                                AVCodecContext *output_codec_context,
  591                                AVAudioResampleContext  *resampler_context, int
  592                                audio_stream_index,
  593                                int *finished)
  594 {
  595   /** Temporary storage of the input samples of the frame read from the file. */
  596   AVFrame *input_frame = NULL;
  597   /** Temporary storage for the converted input samples. */
  598   uint8_t **converted_input_samples = NULL;
  599   int data_present;
  600   int ret = AVERROR_EXIT;
  601 
  602   /** Initialize temporary storage for one input frame. */
  603   if (init_input_frame (&input_frame))
  604   {
  605 #if DEBUG
  606     fprintf (stderr, "Failed at init frame\n");
  607 #endif
  608     goto cleanup;
  609 
  610   }
  611   /** Decode one frame worth of audio samples. */
  612   if (decode_audio_frame (input_frame, input_format_context,
  613                           input_codec_context, audio_stream_index,
  614                           &data_present,  finished))
  615   {
  616 #if DEBUG
  617     fprintf (stderr, "Failed at decode audio\n");
  618 #endif
  619 
  620     goto cleanup;
  621 
  622   }
  623   /**
  624    * If we are at the end of the file and there are no more samples
  625    * in the decoder which are delayed, we are actually finished.
  626    * This must not be treated as an error.
  627    */if (*finished && ! data_present)
  628   {
  629     ret = 0;
  630 #if DEBUG
  631     fprintf (stderr, "Failed at finished or no data\n");
  632 #endif
  633     goto cleanup;
  634   }
  635   /** If there is decoded data, convert and store it */
  636   if (data_present)
  637   {
  638     int out_linesize;
  639     // FIX ME: I'm losing samples, but can't get it to work.
  640     int out_samples = avresample_available (resampler_context)
  641                       + avresample_get_delay (resampler_context)
  642                       + input_frame->nb_samples;
  643 
  644 
  645     // fprintf(stderr, "Input nbsamples %i out_samples: %i \n",input_frame->nb_samples,out_samples);
  646 
  647     /** Initialize the temporary storage for the converted input samples. */
  648     if (init_converted_samples (&converted_input_samples, &out_linesize,
  649                                 output_codec_context,
  650                                 out_samples))
  651     {
  652 #if DEBUG
  653       fprintf (stderr, "Failed at init_converted_samples\n");
  654 #endif
  655       goto cleanup;
  656     }
  657 
  658     /**
  659      * Convert the input samples to the desired output sample format.
  660      * This requires a temporary storage provided by converted_input_samples.
  661      */
  662     if (convert_samples (input_frame->extended_data, converted_input_samples,
  663                          input_frame->nb_samples, out_samples, out_linesize,
  664                          resampler_context))
  665     {
  666 
  667 
  668 #if DEBUG
  669       fprintf (stderr, "Failed at convert_samples, input frame %i \n",
  670                input_frame->nb_samples);
  671 #endif
  672       goto cleanup;
  673     }
  674     /** Add the converted input samples to the FIFO buffer for later processing. */
  675     if (add_samples_to_fifo (fifo, converted_input_samples,
  676                              out_samples))
  677     {
  678 #if DEBUG
  679       fprintf (stderr, "Failed at add_samples_to_fifo\n");
  680 #endif
  681       goto cleanup;
  682     }
  683     ret = 0;
  684   }
  685   ret = 0;
  686 
  687 cleanup:
  688   if (converted_input_samples)
  689   {
  690     av_freep (&converted_input_samples[0]);
  691     free (converted_input_samples);
  692   }
  693   av_frame_free (&input_frame);
  694   return ret;
  695 }
  696 
  697 
  698 /**
  699  * Initialize one input frame for writing to the output file.
  700  * The frame will be exactly frame_size samples large.
  701  */
  702 static int
  703 init_output_frame (AVFrame **frame,
  704                    AVCodecContext *output_codec_context,
  705                    int frame_size)
  706 {
  707   int error;
  708 
  709   /** Create a new frame to store the audio samples. */
  710   *frame = av_frame_alloc ();
  711   if (NULL == *frame)
  712   {
  713 #if DEBUG
  714     fprintf (stderr, "Could not allocate output frame\n");
  715 #endif
  716     return AVERROR_EXIT;
  717   }
  718 
  719   /**
  720    * Set the frame's parameters, especially its size and format.
  721    * av_frame_get_buffer needs this to allocate memory for the
  722    * audio samples of the frame.
  723    * Default channel layouts based on the number of channels
  724    * are assumed for simplicity.
  725    */(*frame)->nb_samples  = frame_size;
  726   (*frame)->channel_layout = output_codec_context->channel_layout;
  727   (*frame)->format         = output_codec_context->sample_fmt;
  728   (*frame)->sample_rate    = output_codec_context->sample_rate;
  729 
  730 
  731   // fprintf(stderr, "%i %i  \n",frame_size , (*frame)->format,(*frame)->sample_rate);
  732 
  733   /**
  734    * Allocate the samples of the created frame. This call will make
  735    * sure that the audio frame can hold as many samples as specified.
  736    */
  737   if ((error = av_frame_get_buffer (*frame, 0)) < 0)
  738   {
  739 #if DEBUG
  740     fprintf (stderr, "Could allocate output frame samples (error '%s')\n",
  741              get_error_text (error));
  742 #endif
  743     av_frame_free (frame);
  744     return error;
  745   }
  746 
  747   return 0;
  748 }
  749 
  750 
  751 /** Encode one frame worth of audio to the output file. */
  752 static int
  753 encode_audio_frame (AVFrame *frame,
  754                     AVFormatContext *output_format_context,
  755                     AVCodecContext *output_codec_context,
  756                     int *data_present)
  757 {
  758   /** Packet used for temporary storage. */
  759   AVPacket output_packet;
  760   int error;
  761   init_packet (&output_packet);
  762 
  763   /**
  764    * Encode the audio frame and store it in the temporary packet.
  765    * The output audio stream encoder is used to do this.
  766    */
  767   if ((error = avcodec_encode_audio2 (output_codec_context, &output_packet,
  768                                       frame, data_present)) < 0)
  769   {
  770 #if DEBUG
  771     fprintf (stderr, "Could not encode frame (error '%s')\n",
  772              get_error_text (error));
  773 #endif
  774     av_packet_unref (&output_packet);
  775     return error;
  776   }
  777 
  778   /** Write one audio frame from the temporary packet to the output file. */
  779   if (*data_present)
  780   {
  781     if ((error = av_write_frame (output_format_context, &output_packet)) < 0)
  782     {
  783 #if DEBUG
  784       fprintf (stderr, "Could not write frame (error '%s')\n",
  785                get_error_text (error));
  786 #endif
  787 
  788       av_packet_unref (&output_packet);
  789       return error;
  790     }
  791 
  792     av_packet_unref (&output_packet);
  793   }
  794 
  795   return 0;
  796 }
  797 
  798 
  799 /**
  800  * Load one audio frame from the FIFO buffer, encode and write it to the
  801  * output file.
  802  */
  803 static int
  804 load_encode_and_write (AVAudioFifo *fifo,
  805                        AVFormatContext *output_format_context,
  806                        AVCodecContext *output_codec_context)
  807 {
  808   /** Temporary storage of the output samples of the frame written to the file. */
  809   AVFrame *output_frame;
  810   /**
  811    * Use the maximum number of possible samples per frame.
  812    * If there is less than the maximum possible frame size in the FIFO
  813    * buffer use this number. Otherwise, use the maximum possible frame size
  814    */const int frame_size = FFMIN (av_audio_fifo_size (fifo),
  815                                 output_codec_context->frame_size);
  816   int data_written;
  817 
  818   /** Initialize temporary storage for one output frame. */
  819   if (init_output_frame (&output_frame, output_codec_context, frame_size))
  820     return AVERROR_EXIT;
  821 
  822   /**
  823    * Read as many samples from the FIFO buffer as required to fill the frame.
  824    * The samples are stored in the frame temporarily.
  825    */
  826   if (av_audio_fifo_read (fifo, (void **) output_frame->data, frame_size) <
  827       frame_size)
  828   {
  829 #if DEBUG
  830     fprintf (stderr, "Could not read data from FIFO\n");
  831 #endif
  832     av_frame_free (&output_frame);
  833     return AVERROR_EXIT;
  834   }
  835 
  836   /** Encode one frame worth of audio samples. */
  837   if (encode_audio_frame (output_frame, output_format_context,
  838                           output_codec_context, &data_written))
  839   {
  840     av_frame_free (&output_frame);
  841     return AVERROR_EXIT;
  842   }
  843   av_frame_free (&output_frame);
  844   return 0;
  845 }
  846 
  847 
  848 /** Write the trailer of the output file container. */
  849 static int
  850 write_output_file_trailer (AVFormatContext *output_format_context)
  851 {
  852   int error;
  853   if ((error = av_write_trailer (output_format_context)) < 0)
  854   {
  855 #if DEBUG
  856     fprintf (stderr, "Could not write output file trailer (error '%s')\n",
  857              get_error_text (error));
  858 #endif
  859     return error;
  860   }
  861   return 0;
  862 }
  863 
  864 
  865 #define ENUM_CODEC_ID enum AVCodecID
  866 
  867 
  868 /**
  869  * Perform the audio snippet extraction
  870  *
  871  * @param ec extraction context to use
  872  */
  873 static void
  874 extract_audio (struct EXTRACTOR_ExtractContext *ec)
  875 {
  876   AVIOContext *io_ctx;
  877   struct AVFormatContext *format_ctx;
  878   AVCodecContext *codec_ctx;
  879   AVFormatContext *output_format_context = NULL;
  880   AVCodec *codec;
  881   AVDictionary *options;
  882   AVFrame *frame;
  883   AVCodecContext*output_codec_context = NULL;
  884   AVAudioResampleContext  *resample_context = NULL;
  885   AVAudioFifo *fifo = NULL;
  886 
  887   int audio_stream_index;
  888   int i;
  889   int err;
  890   int duration;
  891   unsigned char *iob;
  892 
  893 
  894   totalSize = 0;
  895   if (NULL == (iob = av_malloc (16 * 1024)))
  896     return;
  897   if (NULL == (io_ctx = avio_alloc_context (iob,
  898                                             16 * 1024,
  899                                             0, ec,
  900                                             &read_cb,
  901                                             NULL /* no writing */,
  902                                             &seek_cb)))
  903   {
  904     av_free (iob);
  905     return;
  906   }
  907   if (NULL == (format_ctx = avformat_alloc_context ()))
  908   {
  909     av_free (io_ctx);
  910     return;
  911   }
  912   format_ctx->pb = io_ctx;
  913   options = NULL;
  914   if (0 != avformat_open_input (&format_ctx, "<no file>", NULL, &options))
  915   {
  916     av_free (io_ctx);
  917     return;
  918   }
  919   av_dict_free (&options);
  920   if (0 > avformat_find_stream_info (format_ctx, NULL))
  921   {
  922 #if DEBUG
  923     fprintf (stderr,
  924              "Failed to read stream info\n");
  925 #endif
  926     avformat_close_input (&format_ctx);
  927     av_free (io_ctx);
  928     return;
  929   }
  930   codec = NULL;
  931   codec_ctx = NULL;
  932   audio_stream_index = -1;
  933   for (i = 0; i<format_ctx->nb_streams; i++)
  934   {
  935     codec_ctx = format_ctx->streams[i]->codec;
  936     if (AVMEDIA_TYPE_AUDIO != codec_ctx->codec_type)
  937       continue;
  938     if (NULL == (codec = avcodec_find_decoder (codec_ctx->codec_id)))
  939       continue;
  940     options = NULL;
  941     if (0 != (err = avcodec_open2 (codec_ctx, codec, &options)))
  942     {
  943       codec = NULL;
  944       continue;
  945     }
  946     av_dict_free (&options);
  947     audio_stream_index = i;
  948     break;
  949   }
  950   if ( (-1 == audio_stream_index) ||
  951        (0 == codec_ctx->channels) )
  952   {
  953 #if DEBUG
  954     fprintf (stderr,
  955              "No audio streams or no suitable codec found\n");
  956 #endif
  957     if (NULL != codec)
  958       avcodec_close (codec_ctx);
  959     avformat_close_input (&format_ctx);
  960     av_free (io_ctx);
  961     return;
  962   }
  963 
  964   frame = av_frame_alloc ();
  965   if (NULL == frame)
  966   {
  967 #if DEBUG
  968     fprintf (stderr,
  969              "Failed to allocate frame\n");
  970 #endif
  971     avcodec_close (codec_ctx);
  972     avformat_close_input (&format_ctx);
  973     av_free (io_ctx);
  974     return;
  975   }
  976 
  977 
  978   if (! (buffer = malloc (HARD_LIMIT_SIZE)))
  979     goto cleanup;
  980 
  981 
  982   /** Open the output file for writing. */
  983   if (open_output_file (codec_ctx,
  984                         &output_format_context,
  985                         &output_codec_context))
  986     goto cleanup;
  987   /** Initialize the resampler to be able to convert audio sample formats. */
  988   if (init_resampler (codec_ctx,
  989                       output_codec_context,
  990                       &resample_context))
  991     goto cleanup;
  992   /** Initialize the FIFO buffer to store audio samples to be encoded. */
  993   if (init_fifo (&fifo))
  994     goto cleanup;
  995 
  996   /** Write the header of the output file container. */
  997   if (write_output_file_header (output_format_context))
  998     goto cleanup;
  999 
 1000 
 1001   if (format_ctx->duration == AV_NOPTS_VALUE)
 1002   {
 1003     duration = -1;
 1004 #if DEBUG
 1005     fprintf (stderr,
 1006              "Duration unknown\n");
 1007 #endif
 1008   }
 1009   else
 1010   {
 1011     duration = format_ctx->duration;
 1012 #if DEBUG
 1013     fprintf (stderr,
 1014              "Duration: %lld\n",
 1015              format_ctx->duration);
 1016 #endif
 1017   }
 1018 
 1019   /* if duration is known, seek to first tried,
 1020    * else use 10 sec into stream */
 1021 
 1022   if (-1 != duration)
 1023     err = av_seek_frame (format_ctx, -1, (duration / 3), 0);
 1024   else
 1025     err = av_seek_frame (format_ctx, -1, 10 * AV_TIME_BASE, 0);
 1026 
 1027 
 1028   if (err >= 0)
 1029     avcodec_flush_buffers (codec_ctx);
 1030 
 1031 
 1032   /**
 1033    * Loop as long as we have input samples to read or output samples
 1034    * to write; abort as soon as we have neither.
 1035    */
 1036   while (1)
 1037   {
 1038     /** Use the encoder's desired frame size for processing. */
 1039     const int output_frame_size = output_codec_context->frame_size;
 1040     int finished                = 0;
 1041 
 1042     /**
 1043      * Make sure that there is one frame worth of samples in the FIFO
 1044      * buffer so that the encoder can do its work.
 1045      * Since the decoder's and the encoder's frame size may differ, we
 1046      * need to FIFO buffer to store as many frames worth of input samples
 1047      * that they make up at least one frame worth of output samples.
 1048      */while ((av_audio_fifo_size (fifo) < output_frame_size))
 1049     {
 1050       /**
 1051        * Decode one frame worth of audio samples, convert it to the
 1052        * output sample format and put it into the FIFO buffer.
 1053        */
 1054       if (read_decode_convert_and_store (fifo,
 1055                                          format_ctx,
 1056                                          codec_ctx,
 1057                                          output_codec_context,
 1058                                          resample_context,
 1059                                          audio_stream_index,
 1060                                          &finished))
 1061       {
 1062         goto cleanup;
 1063       }
 1064 
 1065       /**
 1066        * If we are at the end of the input file, we continue
 1067        * encoding the remaining audio samples to the output file.
 1068        */
 1069       if (finished)
 1070         break;
 1071     }
 1072 
 1073     /* Already over our limit*/
 1074     if (totalSize >= MAX_SIZE)
 1075       finished = 1;
 1076 
 1077     /**
 1078      * If we have enough samples for the encoder, we encode them.
 1079      * At the end of the file, we pass the remaining samples to
 1080      * the encoder.
 1081      *///
 1082     while (av_audio_fifo_size (fifo) >= output_frame_size ||
 1083            (finished && av_audio_fifo_size (fifo) > 0))
 1084     {
 1085       /**
 1086        * Take one frame worth of audio samples from the FIFO buffer,
 1087        * encode it and write it to the output file.
 1088        */
 1089       if (load_encode_and_write (fifo,
 1090                                  output_format_context,
 1091                                  output_codec_context))
 1092         goto cleanup;
 1093     }
 1094     /**
 1095      * If we are at the end of the input file and have encoded
 1096      * all remaining samples, we can exit this loop and finish.
 1097      */
 1098     if (finished)
 1099     {
 1100       int data_written;
 1101       /** Flush the encoder as it may have delayed frames. */
 1102       do {
 1103         encode_audio_frame (NULL,
 1104                             output_format_context,
 1105                             output_codec_context,
 1106                             &data_written);
 1107       } while (data_written);
 1108       break;
 1109     }
 1110   }
 1111 
 1112   /** Write the trailer of the output file container. */
 1113   if (write_output_file_trailer (output_format_context))
 1114     goto cleanup;
 1115   ec->proc (ec->cls,
 1116             "previewopus",
 1117             EXTRACTOR_METATYPE_AUDIO_PREVIEW,
 1118             EXTRACTOR_METAFORMAT_BINARY,
 1119             "audio/opus",
 1120             buffer,
 1121             totalSize);
 1122 
 1123 #if OUTPUT_FILE
 1124   {
 1125     FILE *f;
 1126 
 1127     f = fopen ("example.opus", "wb");
 1128     if (! f)
 1129     {
 1130       fprintf (stderr, "Could not open %s\n", "file");
 1131       exit (1);
 1132     }
 1133     fwrite (buffer, 1, totalSize, f);
 1134     fclose (f);
 1135   }
 1136 #endif
 1137 
 1138 cleanup:
 1139   av_free (frame);
 1140   free (buffer);
 1141 
 1142   if (fifo)
 1143     av_audio_fifo_free (fifo);
 1144   if (resample_context)
 1145   {
 1146     avresample_close (resample_context);
 1147     avresample_free (&resample_context);
 1148   }
 1149   if (output_codec_context)
 1150     avcodec_close (output_codec_context);
 1151 
 1152   avcodec_close (codec_ctx);
 1153   avformat_close_input (&format_ctx);
 1154   av_free (io_ctx);
 1155 }
 1156 
 1157 
 1158 /**
 1159  * Main method for the opus-preview plugin.
 1160  *
 1161  * @param ec extraction context
 1162  */
 1163 void
 1164 EXTRACTOR_previewopus_extract_method (struct EXTRACTOR_ExtractContext *ec)
 1165 {
 1166   ssize_t iret;
 1167   void *data;
 1168 
 1169   if (-1 == (iret = ec->read (ec->cls,
 1170                               &data,
 1171                               16 * 1024)))
 1172     return;
 1173 
 1174   if (0 != ec->seek (ec->cls, 0, SEEK_SET))
 1175     return;
 1176 
 1177   extract_audio (ec);
 1178 }
 1179 
 1180 
 1181 /**
 1182  * Log callback.  Does nothing.
 1183  *
 1184  * @param ptr NULL
 1185  * @param level log level
 1186  * @param format format string
 1187  * @param ap arguments for format
 1188  */
 1189 static void
 1190 previewopus_av_log_callback (void*ptr,
 1191                              int level,
 1192                              const char *format,
 1193                              va_list ap)
 1194 {
 1195 #if DEBUG
 1196   vfprintf (stderr, format, ap);
 1197 #endif
 1198 }
 1199 
 1200 
 1201 /**
 1202  * Initialize av-libs
 1203  */
 1204 void __attribute__ ((constructor))
 1205 previewopus_lib_init (void)
 1206 {
 1207   av_log_set_callback (&previewopus_av_log_callback);
 1208 }
 1209 
 1210 
 1211 /**
 1212  * Destructor for the library, cleans up.
 1213  */
 1214 void __attribute__ ((destructor))
 1215 previewopus_ltdl_fini ()
 1216 {
 1217 
 1218 }
 1219 
 1220 
 1221 /* end of previewopus_extractor.c */