`

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调用MFC源码及Lib

    1. **加载文件**:首先,你需要使用`MediaInfo_Open()`函数打开你要分析的多媒体文件,该函数会返回一个句柄,用于后续的操作。 2. **提取信息**:接着,你可以调用`MediaInfo_Inform()`或`MediaInfo_Get()`函数,...

    MediaInfo音视频信息解析类

    MediaInfo是一款强大的多媒体信息分析工具,它能够详细地解析音频和视频文件的各种元数据,包括编码格式、比特率、采样率、声道数等。MediaInfo提供了DLL动态链接库的形式,方便开发者将其集成到自己的应用程序中,...

    mediainfo_0.7.31.rar

    这个“mediainfo_0.7.31.rar”压缩包包含了mediainfo的源代码,版本为0.7.31,适合开发者用于学习、定制或在Visual Studio环境下进行编译。 Mediainfo的源码是用C++编写的,它的设计目标是提供一个跨平台的解决...

    MediaInfo视频编码分析查询器

    "编码分析"是指通过特定工具,如MediaInfo,解析视频文件的元数据,获取编码信息。这对于视频制作、编辑、传输和播放都是必不可少的步骤。例如,在进行视频转码或压缩时,需要知道原文件的编码类型,以便选择合适的...

    媒体分析MediaInfo

    《全面解析MediaInfo:探索媒体文件的内在奥秘》 在数字媒体的世界里,了解文件的内部构造和编码参数是至关重要的。MediaInfo就是这样一款强大的工具,专为媒体专业人士和普通用户提供了详尽的媒体文件分析功能。它...

    MediaInfo_software

    MediaInfo 是一款强大的媒体信息查看工具,专门用于分析和提取各种多媒体文件的详细技术信息。这个软件可以帮助用户轻松地了解视频、音频文件的编码格式、分辨率、比特率、采样率等关键参数,从而在处理多媒体文件时...

    MediaInfo_CLI_0.7.99_Windows_x64.zip

    MediaInfo遵循开源许可,可能使用的是GPL或MIT等开放源代码许可证,允许自由使用和分享。 4. **History.txt**:这是一个版本历史记录文件,列出了该版本的更新内容、改进和修复的bug,帮助用户了解软件的发展历程...

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

    MediaInfo是一款强大的多媒体信息分析工具,它能够详细地解析各种音视频文件的元数据和编码信息,帮助用户了解媒体文件的详细技术规格。MediaInfo支持众多格式,包括但不限于MP4、AVI、MKV、WMV、MP3、AAC等,涵盖了...

    MediaInfo-64位

    MediaInfo的一大优点是开源且跨平台,它的源代码遵循GPLv2许可协议,这意味着用户可以自由查看、修改并分发源代码。此外,MediaInfo还提供了命令行版本和图形用户界面版本,以满足不同用户的需求。 总的来说,...

    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 媒体分析工具** MediaInfo 是一款强大的媒体信息分析工具,它能够提供详尽的多媒体文件元数据信息,包括视频、音频、字幕等不同轨道的数据。这款工具对于媒体处理、流媒体研究、视频编码和解码、内容...

    视频检测 MediaInfo

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

    Mediainfo获取视频信息

    MediainfoTest这个文件可能是一个测试项目或者示例代码,用于演示如何使用Mediainfo库来获取并解析视频信息。通过这样的测试,开发者可以学习如何在自己的应用程序中集成Mediainfo的功能,以实现多媒体文件的元数据...

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

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

    MediaInfo_20.03.dmg.zip

    MediaInfo是一款强大的多媒体信息分析工具,专为用户提供详细的音频、视频文件元数据。这款软件在全球范围内广受欢迎,因其用户友好的界面和免费无限制的特性而备受赞誉。MediaInfo_20.03.dmg.zip是针对Mac OS平台的...

    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)

    8. **开源项目**:MediaInfo是开源软件,遵循GPL许可证,这意味着源代码公开,用户可以自由查看、修改和分发。 在实际应用中,MediaInfo的使用场景广泛: - **视频编辑**:在剪辑和后期制作过程中,MediaInfo可以...

    MediaInfo_GUI_21.03_Windows.zip

    MediaInfo是一款强大的多媒体信息分析工具,它主要用于获取和展示各种音视频文件的详细技术信息。这个软件可以帮助用户深入了解媒体文件的编码方式、流信息、元数据等关键参数,对于视频编辑、媒体处理以及问题排查...

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

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

Global site tag (gtag.js) - Google Analytics