关于视频录制文件4G限制的处理方式

录像默认会有4G的限制,之所以有这样的限制,是因为目前很多存储设备都是fat格式的,fat的size是32位表示的,天然就有4G的限制,而且实际上在限制4G的情况下只能录出来3.8G。是因为
1)要留一部分buffer写moovbox
2)有的还要留部分buffer作为写数据的cache

在文件\frameworks\av\media\libstagefright\MPEG4Writer.cpp中,有对视频文件size的限制函数fileSizeLimit,源码如下:

bool MPEG4Writer::exceedsFileSizeLimit() {
    // No limit
    if (mMaxFileSizeLimitBytes == 0) {
        return false;
    }
    int64_t nTotalBytesEstimate = static_cast<int64_t>(mInMemoryCacheSize);
    for (List<Track *>::iterator it = mTracks.begin();
         it != mTracks.end(); ++it) {
        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
    }

    if (!mStreamableFile) {
        // Add 1024 bytes as error tolerance
        return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
    }

    // Be conservative in the estimate: do not exceed 95% of
    // the target file limit. For small target file size limit, though,
    // this will not help.
    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
}

可以看到return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);的计算方式。mMaxFileSizeLimitBytes是4G,4G * 95% = 3.8G。

这种情况下的处理方式:

方式一:

通过adb shell blkid dev/block/mmcblk1p1判断sdcard的限制,此时如果输出的结果:

dev/block/mmcblk1p1: UUID="70CD-07EB" TYPE="vfat"

则表示sdcard是fat型的,fat用32位表示文件的大小,天然就有2^32 = 4G的限制。
这种情况下,软件是无法无法处理的,接受现状。

方式二:

在sdcard没有限制的情况下,可以通过软件在/frameworks/base/media/java/android/media/MediaRecorder.java的setVideoEncodingBitRate()中加入语句 setParameter(“param-use-64bit-offset=1”);来突破4G的限制,逻辑如下:
添加之后的函数:

    public void setVideoEncodingBitRate(int bitRate) {
        if (bitRate <= 0) {
            throw new IllegalArgumentException("Video encoding bit rate is not positive");
        }
        setParameter("video-param-encoding-bitrate=" + bitRate);
        setParameter("param-use-64bit-offset=1"); //add this
    }

从后往前查找 /frameworks/av/media/libstagefright/MPEG4Writer.cpp的函数MPEG4Writer::start中有通过
param->findInt32(kKey64BitFileOffset, &use64BitOffset)来判断fat是否用32位表示文件大小,如有如下设置则表示文件是64位来表示的,也就是没有4G的限制了。

    ......
    int32_t use64BitOffset;
    if (param &&
        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
        use64BitOffset) {
        mUse32BitOffset = false;
    }
    ......

而use64BitOffset的值取决于kKey64BitFileOffsetkKey64BitFileOffset的值是在文件/frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp中通过语句(*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset)设置的,可以看到具体函数:

void StagefrightRecorder::setupMPEG4orWEBMMetaData(sp<MetaData> *meta) {
    int64_t startTimeUs = systemTime() / 1000;
    (*meta)->setInt64(kKeyTime, startTimeUs);
    (*meta)->setInt32(kKeyFileType, mOutputFormat);
    (*meta)->setInt32(kKeyBitRate, mTotalBitRate);
    if (mMovieTimeScale > 0) {
        (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
    }
    if (mOutputFormat != OUTPUT_FORMAT_WEBM) {
        (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
        if (mTrackEveryTimeDurationUs > 0) {
            (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
        }
        if (mRotationDegrees != 0) {
            (*meta)->setInt32(kKeyRotation, mRotationDegrees);
        }
    }
}

所以需要查看mUse64BitFileOffset的值。看他的赋值函数,主要取决于use64Bit。

status_t StagefrightRecorder::setParam64BitFileOffset(bool use64Bit) {
    ALOGV("setParam64BitFileOffset: %s",
        use64Bit? "use 64 bit file offset": "use 32 bit file offset");
    mUse64BitFileOffset = use64Bit;
    return OK;
}

setParam64BitFileOffset被调用的地方:

status_t StagefrightRecorder::setParameter(
        const String8 &key, const String8 &value) {
    ALOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
    if (key == "max-duration") {
        int64_t max_duration_ms;
        if (safe_strtoi64(value.string(), &max_duration_ms)) {
            return setParamMaxFileDurationUs(1000LL * max_duration_ms);
        }
    } else if (key == "max-filesize") {
        int64_t max_filesize_bytes;
        if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
            return setParamMaxFileSizeBytes(max_filesize_bytes);
        }
    ......
    } else if (key == "param-use-64bit-offset") {
        int32_t use64BitOffset;
        if (safe_strtoi32(value.string(), &use64BitOffset)) {
            return setParam64BitFileOffset(use64BitOffset != 0);
        }
    ......

可以看到主要是通过key == "param-use-64bit-offset"来决定的,所以添加语句 setParameter(“param-use-64bit-offset=1”);来设置这个key的参数,就可以表示所录制的视频文件大小可以超过4G了。

方式三:

在https://android.googlesource.com/platform/frameworks/av/+/android-8.1.0_r14/media/libmediaplayerservice/StagefrightRecorder.cpp中也有看到如下处理方式(但此方法未经过实测验证,不能保证没有风险,仅供参考):
Enable recording files larger than 4GB by forcing 64-bit file-offsets
in the writer, if application indicates max-file-size greater than 4GB.

CRs-Fixed: 807377
Change-Id: Id1af5bdf3543af156e6d3d80be2e00c7df3b4134

— a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -87,6 +87,7 @@ static const char *kRecorderVideoLevel = "android.media.mediarecorder.video-enco
static const char *kRecorderCaptureFpsEnable = “android.media.mediarecorder.capture-fpsenable”;
static const char *kRecorderCaptureFps = “android.media.mediarecorder.capture-fps”;
static const char *kRecorderRotation = “android.media.mediarecorder.rotation”;
+static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 4GB

// To collect the encoder usage for the battery app
static void addBatteryData(uint32_t params) {
@@ -581,6 +582,10 @@ status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
}

mMaxFileSizeBytes = bytes;
+

  • // If requested size is >4GB, force 64-bit offsets
  • mUse64BitFileOffset |= (bytes >= kMax32BitFileSize);
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值