OggExtractor.cpp中readPage()函数解读

本文深入解析Android中的OggExtractor类,特别是readPage()函数,该函数负责读取Ogg文件的页结构。Ogg是一种包含音视频信息的容器格式,其页面由页头部和数据组成,大小可变且最大不超过65307字节。通过readPage(),可以解读每个页头的27字节信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android利用stagefright进行音视频文件的解析,其中OggExtractor类继承MediaExtractor类。ogg是一种多媒体容器,官网(http://www.xiph.org/)提供免费开源的音视频格式。OGG每页之间相互独立,都包含了各自应有的信息,页的大小是可变的,通常为4-8KB,最大值不超过65307字节(27+255+255×255=65307)。页由页头部(pageheader)和页数据(pagedata)组成。OggExtractor.cpp中的readPage()函数会读取页头部,页头部总共27个字节。

页结构

    struct Page {
        uint64_t mGranulePosition;
        int32_t mPrevPacketSize;
        uint64_t mPrevPacketPos;
        uint32_t mSerialNo;
        uint32_t mPageNo;
        uint8_t mFlags;
        uint8_t mNumSegments;
        uint8_t mLace[255];
    };

ssize_t MyOggExtractor::readPage(off64_t offset, Page *page) {
    uint8_t header[27];
    ssize_t n;
    if ((n = mSource->readAt(offset, header, sizeof(header)))
            < (ssize_t)sizeof(header)) {
        ALOGV("failed to read %zu bytes at offset %#016llx, got %zd bytes",
                sizeof(header), (long long)offset, n);

        if (n < 0) {
            return n;
        } else if (n == 0) {
            return ERROR_END_OF_STREAM;
        } else {
            return ERROR_IO;
        }
    }

    if (memcmp(header, "OggS", 4)) {
        return ERROR_MALFORMED;
    }

    if (header[4] != 0) {
        // Wrong version.

        return ERROR_UNSUPPORTED;
    }

    page->mFlags = header[5];

    if (page->mFlags & ~7) {
        // Only bits 0-2 are defined in version 0.
        return ERROR_MALFORMED;
    }

    page->mGranulePosition = U64LE_AT(&header[6]);

    page->mSerialNo = U32LE_AT(&header[14]);
    page->mPageNo = U32LE_AT(&header[18]);

    page->mNumSegments = header[26];
    if (mSource->readAt(
                offset + sizeof(header), page->mLace, page->mNumSegments)
            < (ssize_t)page->mNumSegments) {
        return ERROR_IO;
    }

    size_t totalSize = 0;;
    for (size_t i = 0; i < page->mNumSegments; ++i) {
        totalSize += page->mLace[i];
    }

    return sizeof(header) + page->mNumSegments + totalSize;
}

OGG 页结构
--------------------------------------------------------------------------------
域名称      占用字节  描述
--------------------------------------------------------------------------------
capture_pattern    4  页标识,"OggS"的ASCII字符 4F 67 67 53
structure_version   1  版本ID,当前版本默认=0
Header_type_flag   1  页头部类型
Granule_position   8  区段位置
Serial_number     4  逻辑流的序列号
Page_seguence_number 4  本页在逻辑流的序号,OGG解码器据此识别有无页丢失。
CRC_cbecksum     4  循环冗余校验码校验和
Number_page_segments 1  本页的区段数量,指明区段表中有多少个区段长度,≤255
Segment_table    ≤255 区段长度表,每个字节表示一个区段的长度
--------------------------------------------------------------------------------
说明:
①页标识:标识着一个页的开始。其作用是分离Ogg封装格式还原媒体编码时识别新页。
②头部类型1字节8位值前3位的意义:
 第1位=1:本页的媒体编码数据与前一页属于同一个逻辑流的同一个包,=0:表示本页是新包。
 第2位=1:本页为逻辑流的第一页bos;=0:不是第一页。
 第3位=1:本页为逻辑流的最后一页eos;=0:不是最后一页。
③区段位置不是指区段在文件中的位置,而是指区段在逻辑流中的位置。它存储了媒体编码相关的参数信息,对于音频流来说,它存储着到本页为止逻辑流在PCM输出中采样码的数目,可以由它来算得时间戳。对于视频流来说,它存储着到本页为止视频帧编码的数目。若此值=0,表示截止到本页,逻辑流的包未结束。
④流序列号,即本页所在的流ID,它是区分本页所属逻辑流与其他逻辑流的序号,可以通过这个值来划分流。
⑤循环冗余校验码校验和包含页的32位CRC校验(头部零CRC校验、页数据校验)的产生多项式为:0x04c11db7。
⑥区段长度表记录着逻辑流中的每个包中每个区段的长度值,取值范围是0-255。包中的最后一个区段长度<255,其它区段长度都=255。这些值以区段出现的先后顺序排列。此域的字节数是区段数量域所表示的数字,即在0-255字节之间。从区段长度表中可以计算出每个包的长度,例如:区段表中的值为 4D FF 45 FF FF FF 40 FF FF 66,那么:
  第一包有1个区段,总长度=4D
  第二包有2个区段,总长度=FF+45
  第三包有4个区段,总长度=FF+FF+FF+40
  第四包有3个区段,总长度=FF+FF+66
⑦页头部的长度和整个页的长度计算:
 页头部长度=27+区段数量
 页长度=页头长度+区段长度表中每个区段的大小=页头部长度+所有区段长度之和。
⑧页头部后面紧接着页数据,页数据包括本页所有的区段数据。

15:50:28.339 [main] DEBUG com.alibaba.excel.metadata.property.ExcelHeadProperty - The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is NONE 15:50:28.366 [main] DEBUG com.alibaba.excel.context.AnalysisContextImpl - Initialization 'AnalysisContextImpl' complete java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid30672.hprof ... Heap dump file created [1102448651 bytes in 1.777 secs] Exception in thread "main" com.alibaba.excel.exception.ExcelAnalysisException: java.lang.OutOfMemoryError: Java heap space at com.alibaba.excel.analysis.ExcelAnalyserImpl.<init>(ExcelAnalyserImpl.java:61) at com.alibaba.excel.ExcelReader.<init>(ExcelReader.java:30) at com.alibaba.excel.read.builder.ExcelReaderBuilder.build(ExcelReaderBuilder.java:214) at com.alibaba.excel.read.builder.ExcelReaderBuilder.sheet(ExcelReaderBuilder.java:251) at com.alibaba.excel.read.builder.ExcelReaderBuilder.sheet(ExcelReaderBuilder.java:243) at com.soyotec.unixde.dtm.common.impl.datafile.handler.ExcelDataHandler.readPage(ExcelDataHandler.java:38) at com.soyotec.unixde.dtm.common.impl.datafile.Test.main(Test.java:27) Caused by: java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3236) at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118) at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93) at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153) at org.apache.poi.util.IOUtils.toByteArray(IOUtils.java:155) at org.apache.poi.util.IOUtils.toByteArray(IOUtils.java:121) at org.apache.poi.util.IOUtils.toByteArray(IOUtils.java:108) at org.apache.poi.openxml4j.util.ZipArchiveFakeEntry.<init>(ZipArchiveFakeEntry.java:47) at org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource.<init>(ZipInputStreamZipEntrySource.java:53) at org.apache.poi.openxml4j.opc.ZipPackage.openZipEntrySourceStream(ZipPackage.java:210) at org.apache.poi.openxml4j.opc.ZipPackage.openZipEntrySource
03-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值