avformat/yuv4mpegdec: simplify math
[ffmpeg.git] / libavformat / yuv4mpegdec.c
index 120630f..eff7fc5 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/imgutils.h"
+
 #include "avformat.h"
 #include "internal.h"
 #include "yuv4mpeg.h"
@@ -31,13 +33,14 @@ static int yuv4_read_header(AVFormatContext *s)
 {
     char header[MAX_YUV4_HEADER + 10];  // Include headroom for
                                         // the longest option
-    char *tokstart, *tokend, *header_end, interlaced = '?';
+    char *tokstart, *tokend, *header_end;
     int i;
     AVIOContext *pb = s->pb;
     int width = -1, height  = -1, raten   = 0,
         rated =  0, aspectn =  0, aspectd = 0;
     enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE, alt_pix_fmt = AV_PIX_FMT_NONE;
     enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED;
+    enum AVFieldOrder field_order = AV_FIELD_UNKNOWN;
     AVStream *st;
 
     for (i = 0; i < MAX_YUV4_HEADER; i++) {
@@ -123,6 +126,12 @@ static int yuv4_read_header(AVFormatContext *s)
                 pix_fmt = AV_PIX_FMT_YUV444P;
             } else if (strncmp("mono16", tokstart, 6) == 0) {
                 pix_fmt = AV_PIX_FMT_GRAY16;
+            } else if (strncmp("mono12", tokstart, 6) == 0) {
+                pix_fmt = AV_PIX_FMT_GRAY12;
+            } else if (strncmp("mono10", tokstart, 6) == 0) {
+                pix_fmt = AV_PIX_FMT_GRAY10;
+            } else if (strncmp("mono9", tokstart, 5) == 0) {
+                pix_fmt = AV_PIX_FMT_GRAY9;
             } else if (strncmp("mono", tokstart, 4) == 0) {
                 pix_fmt = AV_PIX_FMT_GRAY8;
             } else {
@@ -134,7 +143,26 @@ static int yuv4_read_header(AVFormatContext *s)
                 tokstart++;
             break;
         case 'I': // Interlace type
-            interlaced = *tokstart++;
+            switch (*tokstart++){
+            case '?':
+                field_order = AV_FIELD_UNKNOWN;
+                break;
+            case 'p':
+                field_order = AV_FIELD_PROGRESSIVE;
+                break;
+            case 't':
+                field_order = AV_FIELD_TT;
+                break;
+            case 'b':
+                field_order = AV_FIELD_BB;
+                break;
+            case 'm':
+                av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed "
+                       "interlaced and non-interlaced frames.\n");
+            default:
+                av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
+                return AVERROR(EINVAL);
+            }
             break;
         case 'F': // Frame rate
             sscanf(tokstart, "%d:%d", &raten, &rated); // 0:0 if unknown
@@ -225,37 +253,23 @@ static int yuv4_read_header(AVFormatContext *s)
     st = avformat_new_stream(s, NULL);
     if (!st)
         return AVERROR(ENOMEM);
-    st->codec->width  = width;
-    st->codec->height = height;
+    st->codecpar->width  = width;
+    st->codecpar->height = height;
     av_reduce(&raten, &rated, raten, rated, (1UL << 31) - 1);
     avpriv_set_pts_info(st, 64, rated, raten);
     st->avg_frame_rate                = av_inv_q(st->time_base);
-    st->codec->pix_fmt                = pix_fmt;
-    st->codec->codec_type             = AVMEDIA_TYPE_VIDEO;
-    st->codec->codec_id               = AV_CODEC_ID_RAWVIDEO;
+    st->codecpar->format              = pix_fmt;
+    st->codecpar->codec_type          = AVMEDIA_TYPE_VIDEO;
+    st->codecpar->codec_id            = AV_CODEC_ID_RAWVIDEO;
     st->sample_aspect_ratio           = (AVRational){ aspectn, aspectd };
-    st->codec->chroma_sample_location = chroma_sample_location;
+    st->codecpar->chroma_location     = chroma_sample_location;
+    st->codecpar->field_order         = field_order;
+    s->packet_size = av_image_get_buffer_size(st->codecpar->format, width, height, 1) + Y4M_FRAME_MAGIC_LEN;
+    if ((int) s->packet_size < 0)
+        return s->packet_size;
+    s->internal->data_offset = avio_tell(pb);
 
-    switch (interlaced){
-    case 'p':
-        st->codec->field_order = AV_FIELD_PROGRESSIVE;
-        break;
-    case 't':
-        st->codec->field_order = AV_FIELD_TB;
-        break;
-    case 'b':
-        st->codec->field_order = AV_FIELD_BT;
-        break;
-    case 'm':
-        av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed "
-               "interlaced and non-interlaced frames.\n");
-    case '?':
-        st->codec->field_order = AV_FIELD_UNKNOWN;
-        break;
-    default:
-        av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
-        return AVERROR(EINVAL);
-    }
+    st->duration = (avio_size(pb) - avio_tell(pb)) / s->packet_size;
 
     return 0;
 }
@@ -264,8 +278,8 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     int i;
     char header[MAX_FRAME_HEADER+1];
-    int packet_size, width, height, ret;
-    AVStream *st = s->streams[0];
+    int ret;
+    int64_t off = avio_tell(s->pb);
 
     for (i = 0; i < MAX_FRAME_HEADER; i++) {
         header[i] = avio_r8(s->pb);
@@ -284,20 +298,30 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
     if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC)))
         return AVERROR_INVALIDDATA;
 
-    width  = st->codec->width;
-    height = st->codec->height;
-
-    packet_size = avpicture_get_size(st->codec->pix_fmt, width, height);
-    if (packet_size < 0)
-        return packet_size;
-
-    ret = av_get_packet(s->pb, pkt, packet_size);
+    ret = av_get_packet(s->pb, pkt, s->packet_size - Y4M_FRAME_MAGIC_LEN);
     if (ret < 0)
         return ret;
-    else if (ret != packet_size)
+    else if (ret != s->packet_size - Y4M_FRAME_MAGIC_LEN) {
+        av_packet_unref(pkt);
         return s->pb->eof_reached ? AVERROR_EOF : AVERROR(EIO);
-
+    }
     pkt->stream_index = 0;
+    pkt->pts = (off - s->internal->data_offset) / s->packet_size;
+    pkt->duration = 1;
+    return 0;
+}
+
+static int yuv4_read_seek(AVFormatContext *s, int stream_index,
+                          int64_t pts, int flags)
+{
+    int64_t pos;
+
+    if (flags & AVSEEK_FLAG_BACKWARD)
+        pts = FFMAX(0, pts - 1);
+    pos = pts * s->packet_size;
+
+    if (avio_seek(s->pb, pos + s->internal->data_offset, SEEK_SET) < 0)
+        return -1;
     return 0;
 }
 
@@ -316,5 +340,6 @@ AVInputFormat ff_yuv4mpegpipe_demuxer = {
     .read_probe     = yuv4_probe,
     .read_header    = yuv4_read_header,
     .read_packet    = yuv4_read_packet,
+    .read_seek      = yuv4_read_seek,
     .extensions     = "y4m",
 };