LCOV - code coverage report
Current view: top level - src/libavformat - astenc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 70 85 82.4 %
Date: 2017-03-25 17:02:41 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * AST muxer
       3             :  * Copyright (c) 2012 James Almer
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include "avformat.h"
      23             : #include "avio_internal.h"
      24             : #include "internal.h"
      25             : #include "ast.h"
      26             : #include "libavutil/mathematics.h"
      27             : #include "libavutil/opt.h"
      28             : 
      29             : typedef struct ASTMuxContext {
      30             :     AVClass *class;
      31             :     int64_t  size;
      32             :     int64_t  samples;
      33             :     int64_t  loopstart;
      34             :     int64_t  loopend;
      35             :     int      fbs;
      36             : } ASTMuxContext;
      37             : 
      38             : #define CHECK_LOOP(type) \
      39             :     if (ast->loop ## type > 0) { \
      40             :         ast->loop ## type = av_rescale_rnd(ast->loop ## type, par->sample_rate, 1000, AV_ROUND_DOWN); \
      41             :         if (ast->loop ## type < 0 || ast->loop ## type > UINT_MAX) { \
      42             :             av_log(s, AV_LOG_ERROR, "Invalid loop" #type " value\n"); \
      43             :             return AVERROR(EINVAL);  \
      44             :         } \
      45             :     }
      46             : 
      47           1 : static int ast_write_header(AVFormatContext *s)
      48             : {
      49           1 :     ASTMuxContext *ast = s->priv_data;
      50           1 :     AVIOContext *pb = s->pb;
      51             :     AVCodecParameters *par;
      52             :     unsigned int codec_tag;
      53             : 
      54           1 :     if (s->nb_streams == 1) {
      55           1 :         par = s->streams[0]->codecpar;
      56             :     } else {
      57           0 :         av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
      58           0 :         return AVERROR(EINVAL);
      59             :     }
      60             : 
      61           1 :     if (par->codec_id == AV_CODEC_ID_ADPCM_AFC) {
      62           0 :         av_log(s, AV_LOG_ERROR, "muxing ADPCM AFC is not implemented\n");
      63           0 :         return AVERROR_PATCHWELCOME;
      64             :     }
      65             : 
      66           1 :     codec_tag = ff_codec_get_tag(ff_codec_ast_tags, par->codec_id);
      67           1 :     if (!codec_tag) {
      68           0 :         av_log(s, AV_LOG_ERROR, "unsupported codec\n");
      69           0 :         return AVERROR(EINVAL);
      70             :     }
      71             : 
      72           1 :     if (ast->loopend > 0 && ast->loopstart >= ast->loopend) {
      73           0 :         av_log(s, AV_LOG_ERROR, "loopend can't be less or equal to loopstart\n");
      74           0 :         return AVERROR(EINVAL);
      75             :     }
      76             : 
      77             :     /* Convert milliseconds to samples */
      78           1 :     CHECK_LOOP(start)
      79           1 :     CHECK_LOOP(end)
      80             : 
      81           1 :     ffio_wfourcc(pb, "STRM");
      82             : 
      83           1 :     ast->size = avio_tell(pb);
      84           1 :     avio_wb32(pb, 0); /* File size minus header */
      85           1 :     avio_wb16(pb, codec_tag);
      86           1 :     avio_wb16(pb, 16); /* Bit depth */
      87           1 :     avio_wb16(pb, par->channels);
      88           1 :     avio_wb16(pb, 0); /* Loop flag */
      89           1 :     avio_wb32(pb, par->sample_rate);
      90             : 
      91           1 :     ast->samples = avio_tell(pb);
      92           1 :     avio_wb32(pb, 0); /* Number of samples */
      93           1 :     avio_wb32(pb, 0); /* Loopstart */
      94           1 :     avio_wb32(pb, 0); /* Loopend */
      95           1 :     avio_wb32(pb, 0); /* Size of first block */
      96             : 
      97             :     /* Unknown */
      98           1 :     avio_wb32(pb, 0);
      99           1 :     avio_wl32(pb, 0x7F);
     100           1 :     avio_wb64(pb, 0);
     101           1 :     avio_wb64(pb, 0);
     102           1 :     avio_wb32(pb, 0);
     103             : 
     104           1 :     avio_flush(pb);
     105             : 
     106           1 :     return 0;
     107             : }
     108             : 
     109          44 : static int ast_write_packet(AVFormatContext *s, AVPacket *pkt)
     110             : {
     111          44 :     AVIOContext *pb = s->pb;
     112          44 :     ASTMuxContext *ast = s->priv_data;
     113          44 :     AVCodecParameters *par = s->streams[0]->codecpar;
     114          44 :     int size = pkt->size / par->channels;
     115             : 
     116          44 :     if (s->streams[0]->nb_frames == 0)
     117           1 :         ast->fbs = size;
     118             : 
     119          44 :     ffio_wfourcc(pb, "BLCK");
     120          44 :     avio_wb32(pb, size); /* Block size */
     121             : 
     122             :     /* padding */
     123          44 :     avio_wb64(pb, 0);
     124          44 :     avio_wb64(pb, 0);
     125          44 :     avio_wb64(pb, 0);
     126             : 
     127          44 :     avio_write(pb, pkt->data, pkt->size);
     128             : 
     129          44 :     return 0;
     130             : }
     131             : 
     132           1 : static int ast_write_trailer(AVFormatContext *s)
     133             : {
     134           1 :     AVIOContext *pb = s->pb;
     135           1 :     ASTMuxContext *ast = s->priv_data;
     136           1 :     AVCodecParameters *par = s->streams[0]->codecpar;
     137           1 :     int64_t file_size = avio_tell(pb);
     138           1 :     int64_t samples = (file_size - 64 - (32 * s->streams[0]->nb_frames)) / par->block_align; /* PCM_S16BE_PLANAR */
     139             : 
     140           1 :     av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples);
     141             : 
     142           1 :     if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
     143             :         /* Number of samples */
     144           1 :         avio_seek(pb, ast->samples, SEEK_SET);
     145           1 :         avio_wb32(pb, samples);
     146             : 
     147             :         /* Loopstart if provided */
     148           1 :         if (ast->loopstart > 0) {
     149           1 :         if (ast->loopstart >= samples) {
     150           0 :             av_log(s, AV_LOG_WARNING, "Loopstart value is out of range and will be ignored\n");
     151           0 :             ast->loopstart = -1;
     152           0 :             avio_skip(pb, 4);
     153             :         } else
     154           1 :         avio_wb32(pb, ast->loopstart);
     155             :         } else
     156           0 :             avio_skip(pb, 4);
     157             : 
     158             :         /* Loopend if provided. Otherwise number of samples again */
     159           1 :         if (ast->loopend && ast->loopstart >= 0) {
     160           1 :             if (ast->loopend > samples) {
     161           0 :                 av_log(s, AV_LOG_WARNING, "Loopend value is out of range and will be ignored\n");
     162           0 :                 ast->loopend = samples;
     163             :             }
     164           1 :             avio_wb32(pb, ast->loopend);
     165             :         } else {
     166           0 :             avio_wb32(pb, samples);
     167             :         }
     168             : 
     169             :         /* Size of first block */
     170           1 :         avio_wb32(pb, ast->fbs);
     171             : 
     172             :         /* File size minus header */
     173           1 :         avio_seek(pb, ast->size, SEEK_SET);
     174           1 :         avio_wb32(pb, file_size - 64);
     175             : 
     176             :         /* Loop flag */
     177           1 :         if (ast->loopstart >= 0) {
     178           1 :             avio_skip(pb, 6);
     179           1 :             avio_wb16(pb, 0xFFFF);
     180             :         }
     181             : 
     182           1 :         avio_seek(pb, file_size, SEEK_SET);
     183           1 :         avio_flush(pb);
     184             :     }
     185           1 :     return 0;
     186             : }
     187             : 
     188             : #define OFFSET(obj) offsetof(ASTMuxContext, obj)
     189             : static const AVOption options[] = {
     190             :   { "loopstart", "Loopstart position in milliseconds.", OFFSET(loopstart), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
     191             :   { "loopend",   "Loopend position in milliseconds.",   OFFSET(loopend),   AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
     192             :   { NULL },
     193             : };
     194             : 
     195             : static const AVClass ast_muxer_class = {
     196             :     .class_name = "AST muxer",
     197             :     .item_name  = av_default_item_name,
     198             :     .option     = options,
     199             :     .version    = LIBAVUTIL_VERSION_INT,
     200             : };
     201             : 
     202             : AVOutputFormat ff_ast_muxer = {
     203             :     .name              = "ast",
     204             :     .long_name         = NULL_IF_CONFIG_SMALL("AST (Audio Stream)"),
     205             :     .extensions        = "ast",
     206             :     .priv_data_size    = sizeof(ASTMuxContext),
     207             :     .audio_codec       = AV_CODEC_ID_PCM_S16BE_PLANAR,
     208             :     .video_codec       = AV_CODEC_ID_NONE,
     209             :     .write_header      = ast_write_header,
     210             :     .write_packet      = ast_write_packet,
     211             :     .write_trailer     = ast_write_trailer,
     212             :     .priv_class        = &ast_muxer_class,
     213             :     .codec_tag         = (const AVCodecTag* const []){ff_codec_ast_tags, 0},
     214             : };

Generated by: LCOV version 1.13