LCOV - code coverage report
Current view: top level - libavcodec - roqaudioenc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 71 85 83.5 %
Date: 2017-12-16 13:57:32 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * RoQ audio encoder
       3             :  *
       4             :  * Copyright (c) 2005 Eric Lasota
       5             :  *    Based on RoQ specs (c)2001 Tim Ferguson
       6             :  *
       7             :  * This file is part of FFmpeg.
       8             :  *
       9             :  * FFmpeg is free software; you can redistribute it and/or
      10             :  * modify it under the terms of the GNU Lesser General Public
      11             :  * License as published by the Free Software Foundation; either
      12             :  * version 2.1 of the License, or (at your option) any later version.
      13             :  *
      14             :  * FFmpeg is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * Lesser General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU Lesser General Public
      20             :  * License along with FFmpeg; if not, write to the Free Software
      21             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      22             :  */
      23             : 
      24             : #include "avcodec.h"
      25             : #include "bytestream.h"
      26             : #include "internal.h"
      27             : #include "mathops.h"
      28             : 
      29             : #define ROQ_FRAME_SIZE           735
      30             : #define ROQ_HEADER_SIZE   8
      31             : 
      32             : #define MAX_DPCM (127*127)
      33             : 
      34             : 
      35             : typedef struct ROQDPCMContext {
      36             :     short lastSample[2];
      37             :     int input_frames;
      38             :     int buffered_samples;
      39             :     int16_t *frame_buffer;
      40             :     int64_t first_pts;
      41             : } ROQDPCMContext;
      42             : 
      43             : 
      44           1 : static av_cold int roq_dpcm_encode_close(AVCodecContext *avctx)
      45             : {
      46           1 :     ROQDPCMContext *context = avctx->priv_data;
      47             : 
      48           1 :     av_freep(&context->frame_buffer);
      49             : 
      50           1 :     return 0;
      51             : }
      52             : 
      53           1 : static av_cold int roq_dpcm_encode_init(AVCodecContext *avctx)
      54             : {
      55           1 :     ROQDPCMContext *context = avctx->priv_data;
      56             :     int ret;
      57             : 
      58           1 :     if (avctx->channels > 2) {
      59           0 :         av_log(avctx, AV_LOG_ERROR, "Audio must be mono or stereo\n");
      60           0 :         return AVERROR(EINVAL);
      61             :     }
      62           1 :     if (avctx->sample_rate != 22050) {
      63           0 :         av_log(avctx, AV_LOG_ERROR, "Audio must be 22050 Hz\n");
      64           0 :         return AVERROR(EINVAL);
      65             :     }
      66             : 
      67           1 :     avctx->frame_size = ROQ_FRAME_SIZE;
      68           2 :     avctx->bit_rate   = (ROQ_HEADER_SIZE + ROQ_FRAME_SIZE * avctx->channels) *
      69           1 :                         (22050 / ROQ_FRAME_SIZE) * 8;
      70             : 
      71           1 :     context->frame_buffer = av_malloc(8 * ROQ_FRAME_SIZE * avctx->channels *
      72             :                                       sizeof(*context->frame_buffer));
      73           1 :     if (!context->frame_buffer) {
      74           0 :         ret = AVERROR(ENOMEM);
      75           0 :         goto error;
      76             :     }
      77             : 
      78           1 :     context->lastSample[0] = context->lastSample[1] = 0;
      79             : 
      80           1 :     return 0;
      81           0 : error:
      82           0 :     roq_dpcm_encode_close(avctx);
      83           0 :     return ret;
      84             : }
      85             : 
      86      264600 : static unsigned char dpcm_predict(short *previous, short current)
      87             : {
      88             :     int diff;
      89             :     int negative;
      90             :     int result;
      91             :     int predicted;
      92             : 
      93      264600 :     diff = current - *previous;
      94             : 
      95      264600 :     negative = diff<0;
      96      264600 :     diff = FFABS(diff);
      97             : 
      98      264600 :     if (diff >= MAX_DPCM)
      99       10896 :         result = 127;
     100             :     else {
     101      253704 :         result = ff_sqrt(diff);
     102      253704 :         result += diff > result*result+result;
     103             :     }
     104             : 
     105             :     /* See if this overflows */
     106      264600 :  retry:
     107      264600 :     diff = result*result;
     108      264600 :     if (negative)
     109      131603 :         diff = -diff;
     110      264600 :     predicted = *previous + diff;
     111             : 
     112             :     /* If it overflows, back off a step */
     113      264600 :     if (predicted > 32767 || predicted < -32768) {
     114           0 :         result--;
     115           0 :         goto retry;
     116             :     }
     117             : 
     118             :     /* Add the sign bit */
     119      264600 :     result |= negative << 7;   //if (negative) result |= 128;
     120             : 
     121      264600 :     *previous = predicted;
     122             : 
     123      264600 :     return result;
     124             : }
     125             : 
     126         182 : static int roq_dpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
     127             :                                  const AVFrame *frame, int *got_packet_ptr)
     128             : {
     129             :     int i, stereo, data_size, ret;
     130         182 :     const int16_t *in = frame ? (const int16_t *)frame->data[0] : NULL;
     131             :     uint8_t *out;
     132         182 :     ROQDPCMContext *context = avctx->priv_data;
     133             : 
     134         182 :     stereo = (avctx->channels == 2);
     135             : 
     136         182 :     if (!in && context->input_frames >= 8)
     137           2 :         return 0;
     138             : 
     139         180 :     if (in && context->input_frames < 8) {
     140           8 :         memcpy(&context->frame_buffer[context->buffered_samples * avctx->channels],
     141           8 :                in, avctx->frame_size * avctx->channels * sizeof(*in));
     142           8 :         context->buffered_samples += avctx->frame_size;
     143           8 :         if (context->input_frames == 0)
     144           1 :             context->first_pts = frame->pts;
     145           8 :         if (context->input_frames < 7) {
     146           7 :             context->input_frames++;
     147           7 :             return 0;
     148             :         }
     149             :     }
     150         173 :     if (context->input_frames < 8)
     151           1 :         in = context->frame_buffer;
     152             : 
     153         173 :     if (stereo) {
     154         173 :         context->lastSample[0] &= 0xFF00;
     155         173 :         context->lastSample[1] &= 0xFF00;
     156             :     }
     157             : 
     158         173 :     if (context->input_frames == 7)
     159           1 :         data_size = avctx->channels * context->buffered_samples;
     160             :     else
     161         172 :         data_size = avctx->channels * avctx->frame_size;
     162             : 
     163         173 :     if ((ret = ff_alloc_packet2(avctx, avpkt, ROQ_HEADER_SIZE + data_size, 0)) < 0)
     164           0 :         return ret;
     165         173 :     out = avpkt->data;
     166             : 
     167         173 :     bytestream_put_byte(&out, stereo ? 0x21 : 0x20);
     168         173 :     bytestream_put_byte(&out, 0x10);
     169         173 :     bytestream_put_le32(&out, data_size);
     170             : 
     171         173 :     if (stereo) {
     172         173 :         bytestream_put_byte(&out, (context->lastSample[1])>>8);
     173         173 :         bytestream_put_byte(&out, (context->lastSample[0])>>8);
     174             :     } else
     175           0 :         bytestream_put_le16(&out, context->lastSample[0]);
     176             : 
     177             :     /* Write the actual samples */
     178      264773 :     for (i = 0; i < data_size; i++)
     179      264600 :         *out++ = dpcm_predict(&context->lastSample[i & 1], *in++);
     180             : 
     181         173 :     avpkt->pts      = context->input_frames <= 7 ? context->first_pts : frame->pts;
     182         173 :     avpkt->duration = data_size / avctx->channels;
     183             : 
     184         173 :     context->input_frames++;
     185         173 :     if (!in)
     186           0 :         context->input_frames = FFMAX(context->input_frames, 8);
     187             : 
     188         173 :     *got_packet_ptr = 1;
     189         173 :     return 0;
     190             : }
     191             : 
     192             : AVCodec ff_roq_dpcm_encoder = {
     193             :     .name           = "roq_dpcm",
     194             :     .long_name      = NULL_IF_CONFIG_SMALL("id RoQ DPCM"),
     195             :     .type           = AVMEDIA_TYPE_AUDIO,
     196             :     .id             = AV_CODEC_ID_ROQ_DPCM,
     197             :     .priv_data_size = sizeof(ROQDPCMContext),
     198             :     .init           = roq_dpcm_encode_init,
     199             :     .encode2        = roq_dpcm_encode_frame,
     200             :     .close          = roq_dpcm_encode_close,
     201             :     .capabilities   = AV_CODEC_CAP_DELAY,
     202             :     .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
     203             :                                                      AV_SAMPLE_FMT_NONE },
     204             : };

Generated by: LCOV version 1.13