Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * YUV4MPEG demuxer
  3.  * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
  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 "internal.h"
  24. #include "yuv4mpeg.h"
  25.  
  26. /* Header size increased to allow room for optional flags */
  27. #define MAX_YUV4_HEADER 80
  28. #define MAX_FRAME_HEADER 80
  29.  
  30. static int yuv4_read_header(AVFormatContext *s)
  31. {
  32.     char header[MAX_YUV4_HEADER + 10];  // Include headroom for
  33.                                         // the longest option
  34.     char *tokstart, *tokend, *header_end;
  35.     int i;
  36.     AVIOContext *pb = s->pb;
  37.     int width = -1, height  = -1, raten   = 0,
  38.         rated =  0, aspectn =  0, aspectd = 0;
  39.     enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE, alt_pix_fmt = AV_PIX_FMT_NONE;
  40.     enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
  41.     enum AVFieldOrder field_order = AV_FIELD_UNKNOWN;
  42.     AVStream *st;
  43.  
  44.     for (i = 0; i < MAX_YUV4_HEADER; i++) {
  45.         header[i] = avio_r8(pb);
  46.         if (header[i] == '\n') {
  47.             header[i + 1] = 0x20;  // Add a space after last option.
  48.                                    // Makes parsing "444" vs "444alpha" easier.
  49.             header[i + 2] = 0;
  50.             break;
  51.         }
  52.     }
  53.     if (i == MAX_YUV4_HEADER)
  54.         return -1;
  55.     if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC)))
  56.         return -1;
  57.  
  58.     header_end = &header[i + 1]; // Include space
  59.     for (tokstart = &header[strlen(Y4M_MAGIC) + 1];
  60.          tokstart < header_end; tokstart++) {
  61.         if (*tokstart == 0x20)
  62.             continue;
  63.         switch (*tokstart++) {
  64.         case 'W': // Width. Required.
  65.             width    = strtol(tokstart, &tokend, 10);
  66.             tokstart = tokend;
  67.             break;
  68.         case 'H': // Height. Required.
  69.             height   = strtol(tokstart, &tokend, 10);
  70.             tokstart = tokend;
  71.             break;
  72.         case 'C': // Color space
  73.             if (strncmp("420jpeg", tokstart, 7) == 0) {
  74.                 pix_fmt = AV_PIX_FMT_YUV420P;
  75.                 chroma_sample_location = AVCHROMA_LOC_CENTER;
  76.             } else if (strncmp("420mpeg2", tokstart, 8) == 0) {
  77.                 pix_fmt = AV_PIX_FMT_YUV420P;
  78.                 chroma_sample_location = AVCHROMA_LOC_LEFT;
  79.             } else if (strncmp("420paldv", tokstart, 8) == 0) {
  80.                 pix_fmt = AV_PIX_FMT_YUV420P;
  81.                 chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
  82.             } else if (strncmp("420p16", tokstart, 6) == 0) {
  83.                 pix_fmt = AV_PIX_FMT_YUV420P16;
  84.             } else if (strncmp("422p16", tokstart, 6) == 0) {
  85.                 pix_fmt = AV_PIX_FMT_YUV422P16;
  86.             } else if (strncmp("444p16", tokstart, 6) == 0) {
  87.                 pix_fmt = AV_PIX_FMT_YUV444P16;
  88.             } else if (strncmp("420p14", tokstart, 6) == 0) {
  89.                 pix_fmt = AV_PIX_FMT_YUV420P14;
  90.             } else if (strncmp("422p14", tokstart, 6) == 0) {
  91.                 pix_fmt = AV_PIX_FMT_YUV422P14;
  92.             } else if (strncmp("444p14", tokstart, 6) == 0) {
  93.                 pix_fmt = AV_PIX_FMT_YUV444P14;
  94.             } else if (strncmp("420p12", tokstart, 6) == 0) {
  95.                 pix_fmt = AV_PIX_FMT_YUV420P12;
  96.             } else if (strncmp("422p12", tokstart, 6) == 0) {
  97.                 pix_fmt = AV_PIX_FMT_YUV422P12;
  98.             } else if (strncmp("444p12", tokstart, 6) == 0) {
  99.                 pix_fmt = AV_PIX_FMT_YUV444P12;
  100.             } else if (strncmp("420p10", tokstart, 6) == 0) {
  101.                 pix_fmt = AV_PIX_FMT_YUV420P10;
  102.             } else if (strncmp("422p10", tokstart, 6) == 0) {
  103.                 pix_fmt = AV_PIX_FMT_YUV422P10;
  104.             } else if (strncmp("444p10", tokstart, 6) == 0) {
  105.                 pix_fmt = AV_PIX_FMT_YUV444P10;
  106.             } else if (strncmp("420p9", tokstart, 5) == 0) {
  107.                 pix_fmt = AV_PIX_FMT_YUV420P9;
  108.             } else if (strncmp("422p9", tokstart, 5) == 0) {
  109.                 pix_fmt = AV_PIX_FMT_YUV422P9;
  110.             } else if (strncmp("444p9", tokstart, 5) == 0) {
  111.                 pix_fmt = AV_PIX_FMT_YUV444P9;
  112.             } else if (strncmp("420", tokstart, 3) == 0) {
  113.                 pix_fmt = AV_PIX_FMT_YUV420P;
  114.                 chroma_sample_location = AVCHROMA_LOC_CENTER;
  115.             } else if (strncmp("411", tokstart, 3) == 0) {
  116.                 pix_fmt = AV_PIX_FMT_YUV411P;
  117.             } else if (strncmp("422", tokstart, 3) == 0) {
  118.                 pix_fmt = AV_PIX_FMT_YUV422P;
  119.             } else if (strncmp("444alpha", tokstart, 8) == 0 ) {
  120.                 av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 "
  121.                        "YUV4MPEG stream.\n");
  122.                 return -1;
  123.             } else if (strncmp("444", tokstart, 3) == 0) {
  124.                 pix_fmt = AV_PIX_FMT_YUV444P;
  125.             } else if (strncmp("mono16", tokstart, 6) == 0) {
  126.                 pix_fmt = AV_PIX_FMT_GRAY16;
  127.             } else if (strncmp("mono", tokstart, 4) == 0) {
  128.                 pix_fmt = AV_PIX_FMT_GRAY8;
  129.             } else {
  130.                 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown "
  131.                        "pixel format.\n");
  132.                 return -1;
  133.             }
  134.             while (tokstart < header_end && *tokstart != 0x20)
  135.                 tokstart++;
  136.             break;
  137.         case 'I': // Interlace type
  138.             switch (*tokstart++){
  139.             case '?':
  140.                 field_order = AV_FIELD_UNKNOWN;
  141.                 break;
  142.             case 'p':
  143.                 field_order = AV_FIELD_PROGRESSIVE;
  144.                 break;
  145.             case 't':
  146.                 field_order = AV_FIELD_TT;
  147.                 break;
  148.             case 'b':
  149.                 field_order = AV_FIELD_BB;
  150.                 break;
  151.             case 'm':
  152.                 av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed "
  153.                        "interlaced and non-interlaced frames.\n");
  154.             default:
  155.                 av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
  156.                 return AVERROR(EINVAL);
  157.             }
  158.             break;
  159.         case 'F': // Frame rate
  160.             sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown
  161.             while (tokstart < header_end && *tokstart != 0x20)
  162.                 tokstart++;
  163.             break;
  164.         case 'A': // Pixel aspect
  165.             sscanf(tokstart, "%d:%d", &aspectn, &aspectd); // 0:0 if unknown
  166.             while (tokstart < header_end && *tokstart != 0x20)
  167.                 tokstart++;
  168.             break;
  169.         case 'X': // Vendor extensions
  170.             if (strncmp("YSCSS=", tokstart, 6) == 0) {
  171.                 // Older nonstandard pixel format representation
  172.                 tokstart += 6;
  173.                 if (strncmp("420JPEG", tokstart, 7) == 0)
  174.                     alt_pix_fmt = AV_PIX_FMT_YUV420P;
  175.                 else if (strncmp("420MPEG2", tokstart, 8) == 0)
  176.                     alt_pix_fmt = AV_PIX_FMT_YUV420P;
  177.                 else if (strncmp("420PALDV", tokstart, 8) == 0)
  178.                     alt_pix_fmt = AV_PIX_FMT_YUV420P;
  179.                 else if (strncmp("420P9", tokstart, 5) == 0)
  180.                     alt_pix_fmt = AV_PIX_FMT_YUV420P9;
  181.                 else if (strncmp("422P9", tokstart, 5) == 0)
  182.                     alt_pix_fmt = AV_PIX_FMT_YUV422P9;
  183.                 else if (strncmp("444P9", tokstart, 5) == 0)
  184.                     alt_pix_fmt = AV_PIX_FMT_YUV444P9;
  185.                 else if (strncmp("420P10", tokstart, 6) == 0)
  186.                     alt_pix_fmt = AV_PIX_FMT_YUV420P10;
  187.                 else if (strncmp("422P10", tokstart, 6) == 0)
  188.                     alt_pix_fmt = AV_PIX_FMT_YUV422P10;
  189.                 else if (strncmp("444P10", tokstart, 6) == 0)
  190.                     alt_pix_fmt = AV_PIX_FMT_YUV444P10;
  191.                 else if (strncmp("420P12", tokstart, 6) == 0)
  192.                     alt_pix_fmt = AV_PIX_FMT_YUV420P12;
  193.                 else if (strncmp("422P12", tokstart, 6) == 0)
  194.                     alt_pix_fmt = AV_PIX_FMT_YUV422P12;
  195.                 else if (strncmp("444P12", tokstart, 6) == 0)
  196.                     alt_pix_fmt = AV_PIX_FMT_YUV444P12;
  197.                 else if (strncmp("420P14", tokstart, 6) == 0)
  198.                     alt_pix_fmt = AV_PIX_FMT_YUV420P14;
  199.                 else if (strncmp("422P14", tokstart, 6) == 0)
  200.                     alt_pix_fmt = AV_PIX_FMT_YUV422P14;
  201.                 else if (strncmp("444P14", tokstart, 6) == 0)
  202.                     alt_pix_fmt = AV_PIX_FMT_YUV444P14;
  203.                 else if (strncmp("420P16", tokstart, 6) == 0)
  204.                     alt_pix_fmt = AV_PIX_FMT_YUV420P16;
  205.                 else if (strncmp("422P16", tokstart, 6) == 0)
  206.                     alt_pix_fmt = AV_PIX_FMT_YUV422P16;
  207.                 else if (strncmp("444P16", tokstart, 6) == 0)
  208.                     alt_pix_fmt = AV_PIX_FMT_YUV444P16;
  209.                 else if (strncmp("411", tokstart, 3) == 0)
  210.                     alt_pix_fmt = AV_PIX_FMT_YUV411P;
  211.                 else if (strncmp("422", tokstart, 3) == 0)
  212.                     alt_pix_fmt = AV_PIX_FMT_YUV422P;
  213.                 else if (strncmp("444", tokstart, 3) == 0)
  214.                     alt_pix_fmt = AV_PIX_FMT_YUV444P;
  215.             }
  216.             while (tokstart < header_end && *tokstart != 0x20)
  217.                 tokstart++;
  218.             break;
  219.         }
  220.     }
  221.  
  222.     if (width == -1 || height == -1) {
  223.         av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
  224.         return -1;
  225.     }
  226.  
  227.     if (pix_fmt == AV_PIX_FMT_NONE) {
  228.         if (alt_pix_fmt == AV_PIX_FMT_NONE)
  229.             pix_fmt = AV_PIX_FMT_YUV420P;
  230.         else
  231.             pix_fmt = alt_pix_fmt;
  232.     }
  233.  
  234.     if (raten <= 0 || rated <= 0) {
  235.         // Frame rate unknown
  236.         raten = 25;
  237.         rated = 1;
  238.     }
  239.  
  240.     if (aspectn == 0 && aspectd == 0) {
  241.         // Pixel aspect unknown
  242.         aspectd = 1;
  243.     }
  244.  
  245.     st = avformat_new_stream(s, NULL);
  246.     if (!st)
  247.         return AVERROR(ENOMEM);
  248.     st->codec->width  = width;
  249.     st->codec->height = height;
  250.     av_reduce(&raten, &rated, raten, rated, (1UL << 31) - 1);
  251.     avpriv_set_pts_info(st, 64, rated, raten);
  252.     st->avg_frame_rate                = av_inv_q(st->time_base);
  253.     st->codec->pix_fmt                = pix_fmt;
  254.     st->codec->codec_type             = AVMEDIA_TYPE_VIDEO;
  255.     st->codec->codec_id               = AV_CODEC_ID_RAWVIDEO;
  256.     st->sample_aspect_ratio           = (AVRational){ aspectn, aspectd };
  257.     st->codec->chroma_sample_location = chroma_sample_location;
  258.     st->codec->field_order            = field_order;
  259.     s->packet_size = avpicture_get_size(st->codec->pix_fmt, width, height) + Y4M_FRAME_MAGIC_LEN;
  260.     if ((int) s->packet_size < 0)
  261.         return s->packet_size;
  262.     s->internal->data_offset = avio_tell(pb);
  263.  
  264.     st->duration = (avio_size(pb) - avio_tell(pb)) / s->packet_size;
  265.  
  266.     return 0;
  267. }
  268.  
  269. static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
  270. {
  271.     int i;
  272.     char header[MAX_FRAME_HEADER+1];
  273.     int ret;
  274.     int64_t off = avio_tell(s->pb);
  275.  
  276.     for (i = 0; i < MAX_FRAME_HEADER; i++) {
  277.         header[i] = avio_r8(s->pb);
  278.         if (header[i] == '\n') {
  279.             header[i + 1] = 0;
  280.             break;
  281.         }
  282.     }
  283.     if (s->pb->error)
  284.         return s->pb->error;
  285.     else if (s->pb->eof_reached)
  286.         return AVERROR_EOF;
  287.     else if (i == MAX_FRAME_HEADER)
  288.         return AVERROR_INVALIDDATA;
  289.  
  290.     if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC)))
  291.         return AVERROR_INVALIDDATA;
  292.  
  293.     ret = av_get_packet(s->pb, pkt, s->packet_size - Y4M_FRAME_MAGIC_LEN);
  294.     if (ret < 0)
  295.         return ret;
  296.     else if (ret != s->packet_size - Y4M_FRAME_MAGIC_LEN)
  297.         return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO);
  298.  
  299.     pkt->stream_index = 0;
  300.     pkt->pts = (off - s->internal->data_offset) / s->packet_size;
  301.     pkt->duration = 1;
  302.     return 0;
  303. }
  304.  
  305. static int yuv4_read_seek(AVFormatContext *s, int stream_index,
  306.                           int64_t pts, int flags)
  307. {
  308.     avio_seek(s->pb, pts * s->packet_size + s->internal->data_offset, SEEK_SET);
  309.     return 0;
  310. }
  311.  
  312. static int yuv4_probe(AVProbeData *pd)
  313. {
  314.     /* check file header */
  315.     if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC) - 1) == 0)
  316.         return AVPROBE_SCORE_MAX;
  317.     else
  318.         return 0;
  319. }
  320.  
  321. AVInputFormat ff_yuv4mpegpipe_demuxer = {
  322.     .name           = "yuv4mpegpipe",
  323.     .long_name      = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
  324.     .read_probe     = yuv4_probe,
  325.     .read_header    = yuv4_read_header,
  326.     .read_packet    = yuv4_read_packet,
  327.     .read_seek      = yuv4_read_seek,
  328.     .extensions     = "y4m",
  329. };
  330.