Skip to content
Snippets Groups Projects
yuv.c 3.69 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * .Y.U.V image format
     * Copyright (c) 2003 Fabrice Bellard.
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2 of the License, or (at your option) any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     */
    #include "avformat.h"
    
    static int sizes[][2] = {
        { 640, 480 },
        { 720, 480 },
        { 720, 576 },
        { 352, 288 },
        { 352, 240 },
        { 160, 128 },
        { 512, 384 },
        { 640, 352 },
        { 640, 240 },
    };
    
    static int infer_size(int *width_ptr, int *height_ptr, int size)
    {
        int i;
    
        for(i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
            if ((sizes[i][0] * sizes[i][1]) == size) {
                *width_ptr = sizes[i][0];
                *height_ptr = sizes[i][1];
                return 0;
            }
        }
        return -1;
    }
    
    static int yuv_read(ByteIOContext *f,
                        int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
    {
        ByteIOContext pb1, *pb = &pb1;
        int img_size, ret;
        char fname[1024], *p;
        int size;
        URLContext *h;
        AVImageInfo info1, *info = &info1;
        
        /* XXX: hack hack */
        h = url_fileno(f);
        img_size = url_seek(h, 0, SEEK_END);
        url_get_filename(h, fname, sizeof(fname));
    
        if (infer_size(&info->width, &info->height, img_size) < 0) {
            return -EIO;
        }
        info->pix_fmt = PIX_FMT_YUV420P;
        
        ret = alloc_cb(opaque, info);
        if (ret)
            return ret;
        
        size = info->width * info->height;
        
        p = strrchr(fname, '.');
        if (!p || p[1] != 'Y')
            return -EIO;
    
        get_buffer(f, info->pict.data[0], size);
        
        p[1] = 'U';
        if (url_fopen(pb, fname, URL_RDONLY) < 0)
            return -EIO;
    
        get_buffer(pb, info->pict.data[1], size / 4);
        url_fclose(pb);
        
        p[1] = 'V';
        if (url_fopen(pb, fname, URL_RDONLY) < 0)
            return -EIO;
    
        get_buffer(pb, info->pict.data[2], size / 4);
        url_fclose(pb);
        return 0;
    }
    
    static int yuv_write(ByteIOContext *pb2, AVImageInfo *info)
    {
        ByteIOContext pb1, *pb;
        char fname[1024], *p;
        int i, j, width, height;
        UINT8 *ptr;
        URLContext *h;
        static const char *ext = "YUV";
        
        /* XXX: hack hack */
        h = url_fileno(pb2);
        url_get_filename(h, fname, sizeof(fname));
    
        p = strrchr(fname, '.');
        if (!p || p[1] != 'Y')
            return -EIO;
    
        width = info->width;
        height = info->height;
    
        for(i=0;i<3;i++) {
            if (i == 1) {
                width >>= 1;
                height >>= 1;
            }
    
            if (i >= 1) {
                pb = &pb1;
                p[1] = ext[i];
                if (url_fopen(pb, fname, URL_WRONLY) < 0)
                    return -EIO;
            } else {
                pb = pb2;
            }
        
            ptr = info->pict.data[i];
            for(j=0;j<height;j++) {
                put_buffer(pb, ptr, width);
                ptr += info->pict.linesize[i];
            }
            put_flush_packet(pb);
            if (i >= 1) {
                url_fclose(pb);
            }
        }
        return 0;
    }
        
    static int yuv_probe(AVProbeData *pd)
    {
        if (match_ext(pd->filename, "Y"))
            return AVPROBE_SCORE_MAX;
        else
            return 0;
    }
    
    AVImageFormat yuv_image_format = {
        "yuv",
        "Y",
        yuv_probe,
        yuv_read,
        (1 << PIX_FMT_YUV420P),
        yuv_write,
    };