Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * ARMovie/RPL demuxer
  3.  * Copyright (c) 2007 Christian Ohm, 2008 Eli Friedman
  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 "libavutil/avstring.h"
  23. #include "libavutil/dict.h"
  24. #include "avformat.h"
  25. #include "internal.h"
  26. #include <stdlib.h>
  27.  
  28. #define RPL_SIGNATURE "ARMovie\x0A"
  29. #define RPL_SIGNATURE_SIZE 8
  30.  
  31. /** 256 is arbitrary, but should be big enough for any reasonable file. */
  32. #define RPL_LINE_LENGTH 256
  33.  
  34. static int rpl_probe(AVProbeData *p)
  35. {
  36.     if (memcmp(p->buf, RPL_SIGNATURE, RPL_SIGNATURE_SIZE))
  37.         return 0;
  38.  
  39.     return AVPROBE_SCORE_MAX;
  40. }
  41.  
  42. typedef struct RPLContext {
  43.     // RPL header data
  44.     int32_t frames_per_chunk;
  45.  
  46.     // Stream position data
  47.     uint32_t chunk_number;
  48.     uint32_t chunk_part;
  49.     uint32_t frame_in_part;
  50. } RPLContext;
  51.  
  52. static int read_line(AVIOContext * pb, char* line, int bufsize)
  53. {
  54.     int i;
  55.     for (i = 0; i < bufsize - 1; i++) {
  56.         int b = avio_r8(pb);
  57.         if (b == 0)
  58.             break;
  59.         if (b == '\n') {
  60.             line[i] = '\0';
  61.             return url_feof(pb) ? -1 : 0;
  62.         }
  63.         line[i] = b;
  64.     }
  65.     line[i] = '\0';
  66.     return -1;
  67. }
  68.  
  69. static int32_t read_int(const char* line, const char** endptr, int* error)
  70. {
  71.     unsigned long result = 0;
  72.     for (; *line>='0' && *line<='9'; line++) {
  73.         if (result > (0x7FFFFFFF - 9) / 10)
  74.             *error = -1;
  75.         result = 10 * result + *line - '0';
  76.     }
  77.     *endptr = line;
  78.     return result;
  79. }
  80.  
  81. static int32_t read_line_and_int(AVIOContext * pb, int* error)
  82. {
  83.     char line[RPL_LINE_LENGTH];
  84.     const char *endptr;
  85.     *error |= read_line(pb, line, sizeof(line));
  86.     return read_int(line, &endptr, error);
  87. }
  88.  
  89. /** Parsing for fps, which can be a fraction. Unfortunately,
  90.   * the spec for the header leaves out a lot of details,
  91.   * so this is mostly guessing.
  92.   */
  93. static AVRational read_fps(const char* line, int* error)
  94. {
  95.     int64_t num, den = 1;
  96.     AVRational result;
  97.     num = read_int(line, &line, error);
  98.     if (*line == '.')
  99.         line++;
  100.     for (; *line>='0' && *line<='9'; line++) {
  101.         // Truncate any numerator too large to fit into an int64_t
  102.         if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10)
  103.             break;
  104.         num  = 10 * num + *line - '0';
  105.         den *= 10;
  106.     }
  107.     if (!num)
  108.         *error = -1;
  109.     av_reduce(&result.num, &result.den, num, den, 0x7FFFFFFF);
  110.     return result;
  111. }
  112.  
  113. static int rpl_read_header(AVFormatContext *s)
  114. {
  115.     AVIOContext *pb = s->pb;
  116.     RPLContext *rpl = s->priv_data;
  117.     AVStream *vst = NULL, *ast = NULL;
  118.     int total_audio_size;
  119.     int error = 0;
  120.  
  121.     uint32_t i;
  122.  
  123.     int32_t audio_format, chunk_catalog_offset, number_of_chunks;
  124.     AVRational fps;
  125.  
  126.     char line[RPL_LINE_LENGTH];
  127.  
  128.     // The header for RPL/ARMovie files is 21 lines of text
  129.     // containing the various header fields.  The fields are always
  130.     // in the same order, and other text besides the first
  131.     // number usually isn't important.
  132.     // (The spec says that there exists some significance
  133.     // for the text in a few cases; samples needed.)
  134.     error |= read_line(pb, line, sizeof(line));      // ARMovie
  135.     error |= read_line(pb, line, sizeof(line));      // movie name
  136.     av_dict_set(&s->metadata, "title"    , line, 0);
  137.     error |= read_line(pb, line, sizeof(line));      // date/copyright
  138.     av_dict_set(&s->metadata, "copyright", line, 0);
  139.     error |= read_line(pb, line, sizeof(line));      // author and other
  140.     av_dict_set(&s->metadata, "author"   , line, 0);
  141.  
  142.     // video headers
  143.     vst = avformat_new_stream(s, NULL);
  144.     if (!vst)
  145.         return AVERROR(ENOMEM);
  146.     vst->codec->codec_type      = AVMEDIA_TYPE_VIDEO;
  147.     vst->codec->codec_tag       = read_line_and_int(pb, &error);  // video format
  148.     vst->codec->width           = read_line_and_int(pb, &error);  // video width
  149.     vst->codec->height          = read_line_and_int(pb, &error);  // video height
  150.     vst->codec->bits_per_coded_sample = read_line_and_int(pb, &error);  // video bits per sample
  151.     error |= read_line(pb, line, sizeof(line));                   // video frames per second
  152.     fps = read_fps(line, &error);
  153.     avpriv_set_pts_info(vst, 32, fps.den, fps.num);
  154.  
  155.     // Figure out the video codec
  156.     switch (vst->codec->codec_tag) {
  157. #if 0
  158.         case 122:
  159.             vst->codec->codec_id = AV_CODEC_ID_ESCAPE122;
  160.             break;
  161. #endif
  162.         case 124:
  163.             vst->codec->codec_id = AV_CODEC_ID_ESCAPE124;
  164.             // The header is wrong here, at least sometimes
  165.             vst->codec->bits_per_coded_sample = 16;
  166.             break;
  167.         case 130:
  168.             vst->codec->codec_id = AV_CODEC_ID_ESCAPE130;
  169.             break;
  170.         default:
  171.             avpriv_report_missing_feature(s, "Video format %i",
  172.                                           vst->codec->codec_tag);
  173.             vst->codec->codec_id = AV_CODEC_ID_NONE;
  174.     }
  175.  
  176.     // Audio headers
  177.  
  178.     // ARMovie supports multiple audio tracks; I don't have any
  179.     // samples, though. This code will ignore additional tracks.
  180.     audio_format = read_line_and_int(pb, &error);  // audio format ID
  181.     if (audio_format) {
  182.         ast = avformat_new_stream(s, NULL);
  183.         if (!ast)
  184.             return AVERROR(ENOMEM);
  185.         ast->codec->codec_type      = AVMEDIA_TYPE_AUDIO;
  186.         ast->codec->codec_tag       = audio_format;
  187.         ast->codec->sample_rate     = read_line_and_int(pb, &error);  // audio bitrate
  188.         ast->codec->channels        = read_line_and_int(pb, &error);  // number of audio channels
  189.         ast->codec->bits_per_coded_sample = read_line_and_int(pb, &error);  // audio bits per sample
  190.         // At least one sample uses 0 for ADPCM, which is really 4 bits
  191.         // per sample.
  192.         if (ast->codec->bits_per_coded_sample == 0)
  193.             ast->codec->bits_per_coded_sample = 4;
  194.  
  195.         ast->codec->bit_rate = ast->codec->sample_rate *
  196.                                ast->codec->bits_per_coded_sample *
  197.                                ast->codec->channels;
  198.  
  199.         ast->codec->codec_id = AV_CODEC_ID_NONE;
  200.         switch (audio_format) {
  201.             case 1:
  202.                 if (ast->codec->bits_per_coded_sample == 16) {
  203.                     // 16-bit audio is always signed
  204.                     ast->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
  205.                     break;
  206.                 }
  207.                 // There are some other formats listed as legal per the spec;
  208.                 // samples needed.
  209.                 break;
  210.             case 101:
  211.                 if (ast->codec->bits_per_coded_sample == 8) {
  212.                     // The samples with this kind of audio that I have
  213.                     // are all unsigned.
  214.                     ast->codec->codec_id = AV_CODEC_ID_PCM_U8;
  215.                     break;
  216.                 } else if (ast->codec->bits_per_coded_sample == 4) {
  217.                     ast->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_EA_SEAD;
  218.                     break;
  219.                 }
  220.                 break;
  221.         }
  222.         if (ast->codec->codec_id == AV_CODEC_ID_NONE)
  223.             avpriv_request_sample(s, "Audio format %i", audio_format);
  224.         avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate);
  225.     } else {
  226.         for (i = 0; i < 3; i++)
  227.             error |= read_line(pb, line, sizeof(line));
  228.     }
  229.  
  230.     rpl->frames_per_chunk = read_line_and_int(pb, &error);  // video frames per chunk
  231.     if (rpl->frames_per_chunk > 1 && vst->codec->codec_tag != 124)
  232.         av_log(s, AV_LOG_WARNING,
  233.                "Don't know how to split frames for video format %i. "
  234.                "Video stream will be broken!\n", vst->codec->codec_tag);
  235.  
  236.     number_of_chunks = read_line_and_int(pb, &error);  // number of chunks in the file
  237.     // The number in the header is actually the index of the last chunk.
  238.     number_of_chunks++;
  239.  
  240.     error |= read_line(pb, line, sizeof(line));  // "even" chunk size in bytes
  241.     error |= read_line(pb, line, sizeof(line));  // "odd" chunk size in bytes
  242.     chunk_catalog_offset =                       // offset of the "chunk catalog"
  243.         read_line_and_int(pb, &error);           //   (file index)
  244.     error |= read_line(pb, line, sizeof(line));  // offset to "helpful" sprite
  245.     error |= read_line(pb, line, sizeof(line));  // size of "helpful" sprite
  246.     error |= read_line(pb, line, sizeof(line));  // offset to key frame list
  247.  
  248.     // Read the index
  249.     avio_seek(pb, chunk_catalog_offset, SEEK_SET);
  250.     total_audio_size = 0;
  251.     for (i = 0; !error && i < number_of_chunks; i++) {
  252.         int64_t offset, video_size, audio_size;
  253.         error |= read_line(pb, line, sizeof(line));
  254.         if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64,
  255.                         &offset, &video_size, &audio_size))
  256.             error = -1;
  257.         av_add_index_entry(vst, offset, i * rpl->frames_per_chunk,
  258.                            video_size, rpl->frames_per_chunk, 0);
  259.         if (ast)
  260.             av_add_index_entry(ast, offset + video_size, total_audio_size,
  261.                                audio_size, audio_size * 8, 0);
  262.         total_audio_size += audio_size * 8;
  263.     }
  264.  
  265.     if (error) return AVERROR(EIO);
  266.  
  267.     return 0;
  268. }
  269.  
  270. static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
  271. {
  272.     RPLContext *rpl = s->priv_data;
  273.     AVIOContext *pb = s->pb;
  274.     AVStream* stream;
  275.     AVIndexEntry* index_entry;
  276.     uint32_t ret;
  277.  
  278.     if (rpl->chunk_part == s->nb_streams) {
  279.         rpl->chunk_number++;
  280.         rpl->chunk_part = 0;
  281.     }
  282.  
  283.     stream = s->streams[rpl->chunk_part];
  284.  
  285.     if (rpl->chunk_number >= stream->nb_index_entries)
  286.         return AVERROR_EOF;
  287.  
  288.     index_entry = &stream->index_entries[rpl->chunk_number];
  289.  
  290.     if (rpl->frame_in_part == 0)
  291.         if (avio_seek(pb, index_entry->pos, SEEK_SET) < 0)
  292.             return AVERROR(EIO);
  293.  
  294.     if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
  295.         stream->codec->codec_tag == 124) {
  296.         // We have to split Escape 124 frames because there are
  297.         // multiple frames per chunk in Escape 124 samples.
  298.         uint32_t frame_size;
  299.  
  300.         avio_skip(pb, 4); /* flags */
  301.         frame_size = avio_rl32(pb);
  302.         if (avio_seek(pb, -8, SEEK_CUR) < 0)
  303.             return AVERROR(EIO);
  304.  
  305.         ret = av_get_packet(pb, pkt, frame_size);
  306.         if (ret != frame_size) {
  307.             av_free_packet(pkt);
  308.             return AVERROR(EIO);
  309.         }
  310.         pkt->duration = 1;
  311.         pkt->pts = index_entry->timestamp + rpl->frame_in_part;
  312.         pkt->stream_index = rpl->chunk_part;
  313.  
  314.         rpl->frame_in_part++;
  315.         if (rpl->frame_in_part == rpl->frames_per_chunk) {
  316.             rpl->frame_in_part = 0;
  317.             rpl->chunk_part++;
  318.         }
  319.     } else {
  320.         ret = av_get_packet(pb, pkt, index_entry->size);
  321.         if (ret != index_entry->size) {
  322.             av_free_packet(pkt);
  323.             return AVERROR(EIO);
  324.         }
  325.  
  326.         if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  327.             // frames_per_chunk should always be one here; the header
  328.             // parsing will warn if it isn't.
  329.             pkt->duration = rpl->frames_per_chunk;
  330.         } else {
  331.             // All the audio codecs supported in this container
  332.             // (at least so far) are constant-bitrate.
  333.             pkt->duration = ret * 8;
  334.         }
  335.         pkt->pts = index_entry->timestamp;
  336.         pkt->stream_index = rpl->chunk_part;
  337.         rpl->chunk_part++;
  338.     }
  339.  
  340.     // None of the Escape formats have keyframes, and the ADPCM
  341.     // format used doesn't have keyframes.
  342.     if (rpl->chunk_number == 0 && rpl->frame_in_part == 0)
  343.         pkt->flags |= AV_PKT_FLAG_KEY;
  344.  
  345.     return ret;
  346. }
  347.  
  348. AVInputFormat ff_rpl_demuxer = {
  349.     .name           = "rpl",
  350.     .long_name      = NULL_IF_CONFIG_SMALL("RPL / ARMovie"),
  351.     .priv_data_size = sizeof(RPLContext),
  352.     .read_probe     = rpl_probe,
  353.     .read_header    = rpl_read_header,
  354.     .read_packet    = rpl_read_packet,
  355. };
  356.