Unity 3D : 實作 YUV 影片播放解碼器 ( YUV Video Player )。

本範例是一個簡單的 YUV 影片播放器 ( YUV Video Player )。

這次片源採用 FFMPEG 直接將一般 H264 MP4 Video 轉成 YUV420 格式,附檔名是 *.yuv。

YUV 格式在輸入之前必須先輸入影片的 寬 ( Width ) & 高 ( Height ),由於 YUV 檔是無頭檔參數來描述寬高,如果沒有輸入寬高,基本上是無法解碼的 (畫面不會正常顯示,只能亂猜)。

本範例使用下面這種方式排列

这里写图片描述

C # :

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class Test_YUV420 : MonoBehaviour
{
    public RawImage img;

    int frameCount;

    int frameNow = 0;

    byte[] file;

    // Plana 連續儲存,Packed 交錯儲存
    // 本範例使用 Plana YUV420 格式
    void Start()
    {
        file = File.ReadAllBytes("C:/FFMPEG/Video_854_480_YUV420.yuv");

        frameCount = GetFrameCount(file, 854, 480); // 影像寬高

        print("Frame Count : " + frameCount);

        //File.WriteAllBytes("C:/FFMPEG/Video_854_480_YUV420_1.png", t.EncodeToPNG());
    }

    void Update()
    {
        if (frameNow >= frameCount - 1) return;

        img.texture = GetTexture(file, 854, 480); // 影像寬高

        frameNow++;

        print("Frame : " + (frameNow) + " (" + (int)(frameNow / (float)(frameCount - 1) * 100) + "%)");
    }

    int GetFrameCount(byte[] file, int width, int height)
    {
        return file.Length / ((width * height) * 3 / 2);
    }

    Texture2D t = null;

    Texture2D GetTexture(byte[] file, int width, int height)
    {
        if (t != null) Destroy(t);

        t = new Texture2D(width, height, TextureFormat.RGB24, false);

        int Ysize = t.width * t.height;
        int UorVsize = t.width * t.height / 4;

        Color[] cArr = new Color[t.width * t.height];

        byte U = 0;
        byte V = 0;

        int k = 0;

        int offset = frameNow * ((width * height) * 3 / 2);

        for (int y = 0; y < t.height; y += 2)
        {
            for (int x = 0; x < t.width; x += 2)
            {
                U = file[offset + Ysize + k++];
                V = file[offset + Ysize + k + UorVsize];

                int i = y * t.width + x;
                int mY = t.height - 1 - y;

                byte Y00 = file[offset + i];
                byte Y01 = file[offset + i + t.width];
                byte Y10 = file[offset + i + 1];
                byte Y11 = file[offset + i + t.width + 1];

                float R00 = (Y00 + 1.4075f * (V - 128)) / 255f;
                float G00 = (Y00 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
                float B00 = (Y00 + 1.779f * (U - 128)) / 255f;

                float R01 = (Y01 + 1.4075f * (V - 128)) / 255f;
                float G01 = (Y01 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
                float B01 = (Y01 + 1.779f * (U - 128)) / 255f;

                float R10 = (Y10 + 1.4075f * (V - 128)) / 255f;
                float G10 = (Y10 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
                float B10 = (Y10 + 1.779f * (U - 128)) / 255f;

                float R11 = (Y11 + 1.4075f * (V - 128)) / 255f;
                float G11 = (Y11 - 0.3455f * (U - 128) - 0.7169f * (V - 128)) / 255f;
                float B11 = (Y11 + 1.779f * (U - 128)) / 255f;

                t.SetPixel(x, mY, new Color(R00, G00, B00, 1));
                t.SetPixel(x, mY - 1, new Color(R01, G01, B01, 1));
                t.SetPixel(x + 1, mY, new Color(R10, G10, B10, 1));
                t.SetPixel(x + 1, mY - 1, new Color(R11, G11, B11, 1));
            }
        }
        t.Apply();
        return t;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值