Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * PMP demuxer.
  3.  * Copyright (c) 2011 Reimar Döffinger
  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/intreadwrite.h"
  23. #include "avformat.h"
  24. #include "internal.h"
  25.  
  26. typedef struct {
  27.     int cur_stream;
  28.     int num_streams;
  29.     int audio_packets;
  30.     int current_packet;
  31.     uint32_t *packet_sizes;
  32.     int packet_sizes_alloc;
  33. } PMPContext;
  34.  
  35. static int pmp_probe(AVProbeData *p) {
  36.     if (AV_RN32(p->buf) == AV_RN32("pmpm") &&
  37.         AV_RL32(p->buf + 4) == 1)
  38.         return AVPROBE_SCORE_MAX;
  39.     return 0;
  40. }
  41.  
  42. static int pmp_header(AVFormatContext *s)
  43. {
  44.     PMPContext *pmp = s->priv_data;
  45.     AVIOContext *pb = s->pb;
  46.     int tb_num, tb_den;
  47.     uint32_t index_cnt;
  48.     int audio_codec_id = AV_CODEC_ID_NONE;
  49.     int srate, channels;
  50.     unsigned i;
  51.     uint64_t pos;
  52.     int64_t fsize = avio_size(pb);
  53.  
  54.     AVStream *vst = avformat_new_stream(s, NULL);
  55.     if (!vst)
  56.         return AVERROR(ENOMEM);
  57.     vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  58.     avio_skip(pb, 8);
  59.     switch (avio_rl32(pb)) {
  60.     case 0:
  61.         vst->codec->codec_id = AV_CODEC_ID_MPEG4;
  62.         break;
  63.     case 1:
  64.         vst->codec->codec_id = AV_CODEC_ID_H264;
  65.         break;
  66.     default:
  67.         av_log(s, AV_LOG_ERROR, "Unsupported video format\n");
  68.         break;
  69.     }
  70.     index_cnt = avio_rl32(pb);
  71.     vst->codec->width  = avio_rl32(pb);
  72.     vst->codec->height = avio_rl32(pb);
  73.  
  74.     tb_num = avio_rl32(pb);
  75.     tb_den = avio_rl32(pb);
  76.     avpriv_set_pts_info(vst, 32, tb_num, tb_den);
  77.     vst->nb_frames = index_cnt;
  78.     vst->duration = index_cnt;
  79.  
  80.     switch (avio_rl32(pb)) {
  81.     case 0:
  82.         audio_codec_id = AV_CODEC_ID_MP3;
  83.         break;
  84.     case 1:
  85.         av_log(s, AV_LOG_ERROR, "AAC not yet correctly supported\n");
  86.         audio_codec_id = AV_CODEC_ID_AAC;
  87.         break;
  88.     default:
  89.         av_log(s, AV_LOG_ERROR, "Unsupported audio format\n");
  90.         break;
  91.     }
  92.     pmp->num_streams = avio_rl16(pb) + 1;
  93.     avio_skip(pb, 10);
  94.     srate = avio_rl32(pb);
  95.     channels = avio_rl32(pb) + 1;
  96.     pos = avio_tell(pb) + 4LL*index_cnt;
  97.     for (i = 0; i < index_cnt; i++) {
  98.         uint32_t size = avio_rl32(pb);
  99.         int flags = size & 1 ? AVINDEX_KEYFRAME : 0;
  100.         if (url_feof(pb)) {
  101.             av_log(s, AV_LOG_FATAL, "Encountered EOF while reading index.\n");
  102.             return AVERROR_INVALIDDATA;
  103.         }
  104.         size >>= 1;
  105.         if (size < 9 + 4*pmp->num_streams) {
  106.             av_log(s, AV_LOG_ERROR, "Packet too small\n");
  107.             return AVERROR_INVALIDDATA;
  108.         }
  109.         av_add_index_entry(vst, pos, i, size, 0, flags);
  110.         pos += size;
  111.         if (fsize > 0 && i == 0 && pos > fsize) {
  112.             av_log(s, AV_LOG_ERROR, "File ends before first packet\n");
  113.             return AVERROR_INVALIDDATA;
  114.         }
  115.     }
  116.     for (i = 1; i < pmp->num_streams; i++) {
  117.         AVStream *ast = avformat_new_stream(s, NULL);
  118.         if (!ast)
  119.             return AVERROR(ENOMEM);
  120.         ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
  121.         ast->codec->codec_id = audio_codec_id;
  122.         ast->codec->channels = channels;
  123.         ast->codec->sample_rate = srate;
  124.         avpriv_set_pts_info(ast, 32, 1, srate);
  125.     }
  126.     return 0;
  127. }
  128.  
  129. static int pmp_packet(AVFormatContext *s, AVPacket *pkt)
  130. {
  131.     PMPContext *pmp = s->priv_data;
  132.     AVIOContext *pb = s->pb;
  133.     int ret = 0;
  134.     int i;
  135.  
  136.     if (url_feof(pb))
  137.         return AVERROR_EOF;
  138.     if (pmp->cur_stream == 0) {
  139.         int num_packets;
  140.         pmp->audio_packets = avio_r8(pb);
  141.         if (!pmp->audio_packets) {
  142.             avpriv_request_sample(s, "0 audio packets");
  143.             return AVERROR_PATCHWELCOME;
  144.         }
  145.         num_packets = (pmp->num_streams - 1) * pmp->audio_packets + 1;
  146.         avio_skip(pb, 8);
  147.         pmp->current_packet = 0;
  148.         av_fast_malloc(&pmp->packet_sizes,
  149.                        &pmp->packet_sizes_alloc,
  150.                        num_packets * sizeof(*pmp->packet_sizes));
  151.         if (!pmp->packet_sizes_alloc) {
  152.             av_log(s, AV_LOG_ERROR, "Cannot (re)allocate packet buffer\n");
  153.             return AVERROR(ENOMEM);
  154.         }
  155.         for (i = 0; i < num_packets; i++)
  156.             pmp->packet_sizes[i] = avio_rl32(pb);
  157.     }
  158.     ret = av_get_packet(pb, pkt, pmp->packet_sizes[pmp->current_packet]);
  159.     if (ret >= 0) {
  160.         ret = 0;
  161.         // FIXME: this is a hack that should be removed once
  162.         // compute_pkt_fields() can handle timestamps properly
  163.         if (pmp->cur_stream == 0)
  164.             pkt->dts = s->streams[0]->cur_dts++;
  165.         pkt->stream_index = pmp->cur_stream;
  166.     }
  167.     if (pmp->current_packet % pmp->audio_packets == 0)
  168.         pmp->cur_stream = (pmp->cur_stream + 1) % pmp->num_streams;
  169.     pmp->current_packet++;
  170.     return ret;
  171. }
  172.  
  173. static int pmp_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags)
  174. {
  175.     PMPContext *pmp = s->priv_data;
  176.     pmp->cur_stream = 0;
  177.     // fall back on default seek now
  178.     return -1;
  179. }
  180.  
  181. static int pmp_close(AVFormatContext *s)
  182. {
  183.     PMPContext *pmp = s->priv_data;
  184.     av_freep(&pmp->packet_sizes);
  185.     return 0;
  186. }
  187.  
  188. AVInputFormat ff_pmp_demuxer = {
  189.     .name           = "pmp",
  190.     .long_name      = NULL_IF_CONFIG_SMALL("Playstation Portable PMP"),
  191.     .priv_data_size = sizeof(PMPContext),
  192.     .read_probe     = pmp_probe,
  193.     .read_header    = pmp_header,
  194.     .read_packet    = pmp_packet,
  195.     .read_seek      = pmp_seek,
  196.     .read_close     = pmp_close,
  197. };
  198.