`
阿尔萨斯
  • 浏览: 4202846 次
社区版块
存档分类
最新评论

MediaInfo源代码分析 5:JPEG解析代码分析

 
阅读更多

注:此前已经写了一系列分析MediaInfo源代码的文章,列表如下:
MediaInfo源代码分析 1:整体结构
MediaInfo源代码分析 2:API函数
MediaInfo源代码分析 3:Open()函数
MediaInfo源代码分析 4:Inform()函数
MediaInfo源代码分析 5:JPEG解析代码分析

===================


本文分析MediaInfo中解码JPEG信息的模块。之前写了几篇文章都是关于MediaInfo主程序的,并没有分析其具体是如何解析不同多媒体文件信息的。在这里分析一下解码JPEG文件的代码。其他格式如BMP,GIF等解析的思路基本上是类似的。

File_Jpeg.h的File_Jpeg类的定义如下所示:

//***************************************************************************
// Class File_Jpeg
//***************************************************************************
//继承 File__Analyze
class File_Jpeg : public File__Analyze
{
public :
    //In
    stream_t StreamKind;
    bool     Interlaced;

    //Constructor/Destructor
    File_Jpeg();

private :
    //Streams management
    void Streams_Accept();

    //Buffer - File header
    bool FileHeader_Begin();

    //Buffer - Synchro
    bool Synchronize();
    bool Synched_Test();
    void Synched_Init();

    //Buffer - Demux
    #if MEDIAINFO_DEMUX
    bool Demux_UnpacketizeContainer_Test() {return Demux_UnpacketizeContainer_Test_OneFramePerFile();}
    #endif //MEDIAINFO_DEMUX

    //Buffer - Global
    void Read_Buffer_Unsynched();
    #if MEDIAINFO_SEEK
    size_t Read_Buffer_Seek (size_t Method, int64u Value, int64u ID) {return Read_Buffer_Seek_OneFramePerFile(Method, Value, ID);}
    #endif //MEDIAINFO_SEEK

    //Buffer - Per element
	//解析头
    void Header_Parse();
    bool Header_Parser_Fill_Size();
	//解析数据
    void Data_Parse();

    //Elements
	//JPEG中的单元
	//解析相应的单元,并获得信息
    void TEM () {};
    void SOC () {}
    void SIZ ();
    void COD ();
    void COC () {Skip_XX(Element_Size, "Data");}
    void TLM () {Skip_XX(Element_Size, "Data");}
    void PLM () {Skip_XX(Element_Size, "Data");}
    void PLT () {Skip_XX(Element_Size, "Data");}
    void QCD ();
    void QCC () {Skip_XX(Element_Size, "Data");}
    void RGN () {Skip_XX(Element_Size, "Data");}
    void PPM () {Skip_XX(Element_Size, "Data");}
    void PPT () {Skip_XX(Element_Size, "Data");}
    void CME () {Skip_XX(Element_Size, "Data");}
    void SOT () {Skip_XX(Element_Size, "Data");}
    void SOP () {Skip_XX(Element_Size, "Data");}
    void EPH () {Skip_XX(Element_Size, "Data");}
    void SOD ();
    void SOF_();
    void S0F0() {SOF_();};
    void S0F1() {SOF_();};
    void S0F2() {SOF_();};
    void S0F3() {SOF_();}
    void DHT () {Skip_XX(Element_Size, "Data");}
    void S0F5() {SOF_();}
    void S0F6() {SOF_();}
    void S0F7() {SOF_();}
    void JPG () {Skip_XX(Element_Size, "Data");}
    void S0F9() {SOF_();}
    void S0FA() {SOF_();}
    void S0FB() {SOF_();}
    void DAC () {Skip_XX(Element_Size, "Data");}
    void S0FD() {SOF_();}
    void S0FE() {SOF_();}
    void S0FF() {SOF_();}
    void RST0() {};
    void RST1() {};
    void RST2() {};
    void RST3() {};
    void RST4() {};
    void RST5() {};
    void RST6() {};
    void RST7() {};
    void SOI () {};
    void EOI () {};
    void SOS ();
    void DQT () {Skip_XX(Element_Size, "Data");}
    void DNL () {Skip_XX(Element_Size, "Data");}
    void DRI () {Skip_XX(Element_Size, "Data");}
    void DHP () {Skip_XX(Element_Size, "Data");}
    void EXP () {Skip_XX(Element_Size, "Data");}
    void APP0();
    void APP0_AVI1();
    void APP0_JFIF();
    void APP0_JFFF();
    void APP0_JFFF_JPEG();
    void APP0_JFFF_1B();
    void APP0_JFFF_3B();
    void APP1();
    void APP1_EXIF();
    void APP2() {Skip_XX(Element_Size, "Data");}
    void APP3() {Skip_XX(Element_Size, "Data");}
    void APP4() {Skip_XX(Element_Size, "Data");}
    void APP5() {Skip_XX(Element_Size, "Data");}
    void APP6() {Skip_XX(Element_Size, "Data");}
    void APP7() {Skip_XX(Element_Size, "Data");}
    void APP8() {Skip_XX(Element_Size, "Data");}
    void APP9() {Skip_XX(Element_Size, "Data");}
    void APPA() {Skip_XX(Element_Size, "Data");}
    void APPB() {Skip_XX(Element_Size, "Data");}
    void APPC() {Skip_XX(Element_Size, "Data");}
    void APPD() {Skip_XX(Element_Size, "Data");}
    void APPE();
    void APPE_Adobe0();
    void APPF() {Skip_XX(Element_Size, "Data");}
    void JPG0() {Skip_XX(Element_Size, "Data");}
    void JPG1() {Skip_XX(Element_Size, "Data");}
    void JPG2() {Skip_XX(Element_Size, "Data");}
    void JPG3() {Skip_XX(Element_Size, "Data");}
    void JPG4() {Skip_XX(Element_Size, "Data");}
    void JPG5() {Skip_XX(Element_Size, "Data");}
    void JPG6() {Skip_XX(Element_Size, "Data");}
    void JPG7() {Skip_XX(Element_Size, "Data");}
    void JPG8() {Skip_XX(Element_Size, "Data");}
    void JPG9() {Skip_XX(Element_Size, "Data");}
    void JPGA() {Skip_XX(Element_Size, "Data");}
    void JPGB() {Skip_XX(Element_Size, "Data");}
    void JPGC() {Skip_XX(Element_Size, "Data");}
    void JPGD() {Skip_XX(Element_Size, "Data");}
    void COM () {Skip_XX(Element_Size, "Data");}

    //Temp
    int8u APPE_Adobe0_transform;
    bool  APP0_JFIF_Parsed;
    bool  SOS_SOD_Parsed;
};


上面代码有以下几个特点:

1.继承了File__Analyze类

2.包含了很多JPEG中的数据单元的解析:DHT(),DQT()等等


下面来分别仔细看看源代码:

1.File__Analyze类代码巨多无比,先不分析。他继承了继承了File__Base

2.看一个解码具体单元的代码:SOF_()

注:SOF0(Start of Image,图像开始)。

SOF0,Start of Frame,帧图像开始

标记代码 2字节 固定值0xFFC0

包含9个具体字段:
① 数据长度 2字节 ①~⑥六个字段的总长度
即不包括标记代码,但包括本字段
② 精度 1字节 每个数据样本的位数
通常是8位,一般软件都不支持 12位和16位
③ 图像高度 2字节 图像高度(单位:像素),如果不支持 DNL 就必须 >0
④ 图像宽度 2字节 图像宽度(单位:像素),如果不支持 DNL 就必须 >0
⑤ 颜色分量数 1字节 只有3个数值可选
1:灰度图;3:YCrCb或YIQ;4:CMYK
而JFIF中使用YCrCb,故这里颜色分量数恒为3
⑥颜色分量信息 颜色分量数×3字节(通常为9字节)
a) 颜色分量ID 1字节
b) 水平/垂直采样因子 1字节 高4位:水平采样因子
低4位:垂直采样因子
(曾经看到某资料把这两者调转了)
c) 量化表 1字节 当前分量使用的量化表的ID

本标记段中,字段⑥应该重复出现,有多少个颜色分量(字段⑤),就出现多少次(一般为3次)。

=====================================

void File_Jpeg::SOF_()
{
    //Parsing
    vector<Jpeg_samplingfactor> SamplingFactors;
    int16u Height, Width;
    int8u  Resolution, Count;
    Get_B1 (Resolution,                                         "P - Sample precision");
    Get_B2 (Height,                                             "Y - Number of lines");
    Get_B2 (Width,                                              "X - Number of samples per line");
    Get_B1 (Count,                                              "Nf - Number of image components in frame");
    for (int8u Pos=0; Pos<Count; Pos++)
    {
        Jpeg_samplingfactor SamplingFactor;
        Element_Begin1("Component");
        Get_B1 (   SamplingFactor.Ci,                           "Ci - Component identifier"); if (SamplingFactor.Ci>Count) Element_Info1(Ztring().append(1, (Char)SamplingFactor.Ci)); else Element_Info1(SamplingFactor.Ci);
        BS_Begin();
        Get_S1 (4, SamplingFactor.Hi,                           "Hi - Horizontal sampling factor"); Element_Info1(SamplingFactor.Hi);
        Get_S1 (4, SamplingFactor.Vi,                           "Vi - Vertical sampling factor"); Element_Info1(SamplingFactor.Vi);
        BS_End();
        Skip_B1(                                                "Tqi - Quantization table destination selector");
        Element_End0();

        //Filling list of HiVi
        SamplingFactors.push_back(SamplingFactor);
    }

    FILLING_BEGIN_PRECISE();
        if (Frame_Count==0 && Field_Count==0)
        {
            Accept("JPEG");
            Fill("JPEG");

            if (Count_Get(StreamKind_Last)==0)
                Stream_Prepare(StreamKind_Last);
            Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_Format), "JPEG");
            Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_Codec), "JPEG");
            if (StreamKind_Last==Stream_Image)
                Fill(Stream_Image, 0, Image_Codec_String, "JPEG", Unlimited, true, true); //To Avoid automatic filling
            if (StreamKind_Last==Stream_Video)
                Fill(Stream_Video, 0, Video_InternetMediaType, "video/JPEG", Unlimited, true, true);
            Fill(StreamKind_Last, 0, Fill_Parameter(StreamKind_Last, Generic_BitDepth), Resolution);
            Fill(StreamKind_Last, 0, "Height", Height*(Interlaced?2:1));
            Fill(StreamKind_Last, 0, "Width", Width);

            //ColorSpace from http://docs.oracle.com/javase/1.4.2/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
            switch (APPE_Adobe0_transform)
            {
                case 0x01 :
                            if (Count==3)
                                Fill(StreamKind_Last, 0, "ColorSpace", "YUV");
                case 0x02 :
                            if (Count==4)
                                Fill(StreamKind_Last, 0, "ColorSpace", "YCCB");
                            break;
                default   :
                            {
                            int8u Ci[256];
                            memset(Ci, 0, 256);;
                            for (int8u Pos=0; Pos<Count; Pos++)
                                Ci[SamplingFactors[Pos].Ci]++;

                            switch (Count)
                            {
                                case 1 :    Fill(StreamKind_Last, 0, "ColorSpace", "Y"); break;
                                case 2 :    Fill(StreamKind_Last, 0, "ColorSpace", "YA"); break;
                                case 3 :
                                                 if (!APP0_JFIF_Parsed && Ci['R']==1 && Ci['G']==1 && Ci['B']==1)                                                       //RGB
                                                Fill(StreamKind_Last, 0, "ColorSpace", "RGB");
                                            else if ((Ci['Y']==1 && ((Ci['C']==1 && Ci['c']==1)                                                                         //YCc
                                                                  || Ci['C']==2))                                                                                       //YCC
                                                  || APP0_JFIF_Parsed                                                                                                   //APP0 JFIF header present so YCC
                                                  || APPE_Adobe0_transform==0                                                                                           //transform set to YCC
                                                  || (SamplingFactors[0].Ci==0 && SamplingFactors[1].Ci==1 && SamplingFactors[2].Ci==2)                                 //012
                                                  || (SamplingFactors[0].Ci==1 && SamplingFactors[1].Ci==2 && SamplingFactors[2].Ci==3))                                //123
                                                Fill(StreamKind_Last, 0, "ColorSpace", "YUV");
                                            break;
                                case 4 :
                                                 if (!APP0_JFIF_Parsed && Ci['R']==1 && Ci['G']==1 && Ci['B']==1 && Ci['A']==1)                                         //RGBA
                                                Fill(StreamKind_Last, 0, "ColorSpace", "RGBA");
                                            else if ((Ci['Y']==1 && Ci['A']==1 && ((Ci['C']==1 && Ci['c']==1)                                                           //YCcA
                                                                                || Ci['C']==2))                                                                         //YCCA
                                                  || APP0_JFIF_Parsed                                                                                                   //APP0 JFIF header present so YCCA
                                                  || (SamplingFactors[0].Ci==0 && SamplingFactors[1].Ci==1 && SamplingFactors[2].Ci==2 && SamplingFactors[3].Ci==3)     //0123
                                                  || (SamplingFactors[0].Ci==1 && SamplingFactors[1].Ci==2 && SamplingFactors[2].Ci==3 && SamplingFactors[3].Ci==4))    //1234
                                                Fill(StreamKind_Last, 0, "ColorSpace", "YUVA");
                                            else if (APPE_Adobe0_transform==0)                                                                                          //transform set to CMYK
                                                Fill(StreamKind_Last, 0, "ColorSpace", "YCCB");
                                            break;
                                default:    ;
                            }
                            }
            }

            //Chroma subsampling
            if ((SamplingFactors.size()==3 || SamplingFactors.size()==4) && SamplingFactors[1].Hi==1 && SamplingFactors[2].Hi==1 && SamplingFactors[1].Vi==1 && SamplingFactors[2].Vi==1)
            {
                string ChromaSubsampling;
                switch (SamplingFactors[0].Hi)
                {
                    case 1 :
                            switch (SamplingFactors[0].Vi)
                            {
                                case 1 : ChromaSubsampling="4:4:4"; break;
                                default: ;
                            }
                            break;
                    case 2 :
                            switch (SamplingFactors[0].Vi)
                            {
                                case 1 : ChromaSubsampling="4:2:2"; break;
                                case 2 : ChromaSubsampling="4:2:0"; break;
                                default: ;
                            }
                            break;
                    case 4 :
                            switch (SamplingFactors[0].Vi)
                            {
                                case 1 : ChromaSubsampling="4:1:1"; break;
                                default: ;
                            }
                            break;
                    default: ;
                }
                if (!ChromaSubsampling.empty())
                {
                    if (SamplingFactors.size()==4)
                    {
                        if (ChromaSubsampling=="4:4:4" && SamplingFactors[3].Hi==1 && SamplingFactors[3].Vi==1)
                            ChromaSubsampling+=":4";
                        else
                            ChromaSubsampling+=":?";
                    }
                    Fill(StreamKind_Last, 0, "ChromaSubsampling", ChromaSubsampling);
                }
            }
        }
    FILLING_END();
}


从代码的含义可知,提取出了图像的宽,高,采样方式等信息。

详细的代码暂时没有时间研究了,先这样了。



分享到:
评论

相关推荐

    MediaInfo_GUI_19.09_Windows.exe

    The MediaInfo data display includes: Container: format, profile, commercial name of the format, duration, overall bit rate, writing application and library, title, author, director, album, track ...

    视频检测 MediaInfo

    MediaInfo 用来分析视频和音频文件的编码和内容信息,是一款是自由软件 (免费使用、免费获得源代码,许可协议:GNU GPL/LGPL)。 支持格式:视频:MKV, OGM, AVI, DivX, WMV, QuickTime, Real, MPEG-1, MPEG-2, MPEG-4...

    视频音频编码分析软件MediaInfo0.7.7.6

    MediaInfo 用来分析视频和音频文件的编码和内容信息,是一款是自由软件 (免费使用、免费获得源代码,许可协议:GNU GPL/LGPL)。 MediaInfo可以获得多媒体文件的哪些信息? 内容信息:标题,作者,专辑名,音轨号,...

    MediaInfo.zip

    一个可以获取媒体文件...C:\MediaInfo\MediaInfo.exe --help 解析 C:\123.mp4的参数 C:\MediaInfo\MediaInfo.exe C:\123.mp4 解析 C:\123.mp4, 并以XML格式输出 C:\MediaInfo\MediaInfo.exe --Output=XML C:\123.mp4

    mediainfo.js:使用emscripten将MediaInfo移植到Web

    它使用从C ++源代码编译而来。演示版在浏览器中尝试mediainfo.js: ://mediainfo.js.org用法浏览器您可以使用CDN将脚本文件直接包含在页面中,也可以使用JavaScript捆绑程序(例如webpack)。 CDN : [removed]...

    音视频信息解析工具_MediaInfo.rar

    音视频信息解析工具_MediaInfo.rar

    MediaInfo_GUI_20.03_Windows(多媒体文件分析图形化工具)

    使用MediaInfo可以分析多媒体的信息如下: 内容信息:标题,作者,专辑名,音轨号,日期,总时间…… 视频:编码器,长宽比,帧频率,比特率…… 音频:编码器,采样率,声道数,语言,比特率……

    MediaInfo视频编码分析查询器

    视频编码分析查询器 查询视频的编码形式

    mediainfo_0.7.31.rar

    mediainfo源码vs可以编译通过,mediainfo的版本0.7.31

    媒体分析MediaInfo

    媒体格式分析MediaInfo可以查询媒体文件编码,比特率等

    视频媒体信息检测工具 MediaInfo 21.03 中文.zip

    MediaInfo 支持众多音频和视频格式,它可以快速分析音频或视频文件的编码及信息,对于一些喜爱收藏高清视频的人来说,它可以快速帮你诊断出你下载的视频是不是真正的高清文件。当然 MediaInfo 其实不仅仅可以查阅...

    视频编码信息检测(MediaInfo) v18.12 中文版.rar

    MediaInfo(绿色中文版)用来分析视频和音频文件的编码和内容信息,检测视频编码信息,把目前几个主流的CODEC viewer的功能都给包进来了.像是对新格式的支持, 提供相关CODECs和播放软件的网页连结等等 使用MediaInfo...

    Mediainfo-Template:Mediainfo自定义模板示例

    Mediainfo-模板 命令行示例标准通知文件mediainfo --Inform=file:///Path/To-File/Inform-Example.txt 'Blue Planet II - S01E02 - The Deep.mkv' 命令行示例$ if()通知文件通过管道传递到“ TR”以删除空白行...

    MediaInfo_GUI_0.7.90_Windows

    MediaInfo 是自由软件 (免费使用、免费获得源代码,许可协议: BSD) (版本号:0.7.90/图形界面/安装程序/Windows, 32/64 bit/5 MB) -----------------------------------------------------------------------------...

    mediainfo:mediainfo命令行实用程序的包装器:从audioimagevideo文件中读取信息

    mediainfo是命令行实用程序mediainfo的包装,用于从音频/视频文件中读取信息。 还支持图像文件。 要求 您必须在系统上安装mediainfo命令行实用程序。 以下是基于Debian的系统: $ sudo apt install mediainfo 文献...

    MediaInfo音视频信息解析类

    有源码和说明,包括一些简单的实例,适合自己二次封装并使用。

    Mediainfo获取视频信息

    MediaInfo 用来分析视频和音频文件的编码和内容信息,是一款是自由软件 (免费使用、免费获得源代码)。 可获取视频宽、高、编码等等信息。C++编写。 本工程在vs2010下编译。

    mediainfo媒体分析工具

    该工具可以分析媒体文件的文件格式、编码格式以及音视频码率等信息,对研究流媒体研究的工作者很有帮助。

    MediaInfo_DLL_19.04_GNU_FromSource.tar.bz2

    MediaInfo是一款非常实用的视频参数检测工具,除了可以对...MediaInfo 用来分析视频和音频文件的编码和内容信息,是一款是自由软件 (免费使用、免费获得源代码,许可协议:GNU GPL/LGPL)。MediaInfo_DLL为它的开发库。

    MediaInfo 0.7.31 源码

    MediaInfo 0.7.31 源码。MediaInfo是一款优秀的识别媒体文件格式的软件。

Global site tag (gtag.js) - Google Analytics