當前位置:
首頁 > 知識 > Android中MetaData.cpp數據存儲學習

Android中MetaData.cpp數據存儲學習

代碼路徑:frameworksavmedialibstagefrightfoundationMetaData.cpp

這個是在學習NuPlayer的時候看到的,覺得有必要記錄一下,積累C++數據存儲的技巧;在NuPlayer的getFrameRate()函數中,用到了MetaData,所以從這裡開始記錄:

float NuPlayer::getFrameRate() {

sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);

if (meta == NULL) {

return 0;

}

int32_t rate;

if (!meta->findInt32(kKeyFrameRate, &rate)) {

// fall back to try file meta

sp<MetaData> fileMeta = getFileMeta();

if (fileMeta == NULL) {

ALOGW("source has video meta but not file meta");

return -1;

}

int32_t fileMetaRate;

if (!fileMeta->findInt32(kKeyFrameRate, &fileMetaRate)) { //通過findInt32函數,查找鍵kKeyFrameRate對應的值

return -1;

}

return fileMetaRate;

}

return rate;

}

下面來看,MetaData是如何存儲/獲取值的:

先來看findInt32對應的存儲方法MetaData::setInt32

bool MetaData::setInt32(uint32_t key, int32_t value) {

return setData(key, TYPE_INT32, &value, sizeof(value));

}

bool MetaData::setData(

uint32_t key, uint32_t type, const void *data, size_t size) {

bool overwrote_existing = true;

ssize_t i = mItems.indexOfKey(key); //檢查key是否已存在,不存在的話,創建一個添加進入

if (i < 0) {

typed_data item;

i = mItems.add(key, item); //添加一個新的item

overwrote_existing = false;

}

typed_data &item = mItems.editValueAt(i); //獲取剛才添加好的item的引用,並進行編輯複製操作

item.setData(type, data, size);

return overwrote_existing;

}

以上代碼有兩個知識點:

1. 從上面申明item可以知道item是typed_data類型,而typed_data是類MetaData中的一個結構體,這個結構體專門用來保存數據

2. setData()的最後一個參數是size_t,傳入的是value值的位元組大小;可以得知C++存儲數據時,需要考慮存儲數據的位元組數

下面來看item.setData(type, data, size)這個方法的實現,代碼是在結構體typed_data中:

void MetaData::typed_data::setData(uint32_t type, const void *data, size_t size) {

clear(); //clear()的作用稍後再說明

mType = type; //type保存在成員變數中

void *dst = allocateStorage(size); //申請size大小的內存,這是明白了size的作用

if (dst) {

memcpy(dst, data, size); //將data地址的數據copy size位元組到dts地址中去

}

}

以上有兩個函數clear()/allocateStorage(),需要繼續跟蹤以明白它是如何實現的

void *MetaData::typed_data::allocateStorage(size_t size) {

mSize = size; //將size存儲在成員變數中

if (usesReservoir()) { //判斷是否使用已有存儲池來存儲數據

return &u.reservoir; //可以使用的話,返回u.reservoir地址

}

u.ext_data = malloc(mSize); //如果不可以使用,則重新申請一塊mSize大小的內存

if (u.ext_data == NULL) {

ALOGE("Couldn"t allocate %zu bytes for item", size);

mSize = 0;

}

return u.ext_data;

}

//下面來看usesReservoir():

bool usesReservoir() const {

return mSize <= sizeof(u.reservoir); //哦,明白了,是判斷要存儲的數據是否大於存儲池的空間,如果小於的話,就將data存在u.reservoir中

}

看了剛才的allocateStorage()函數的實現後,不禁會好奇u.ext_data和u.reservoir兩個元素,它是結構體typed_data中定義的用一個聯合體:

union { //是定義在共用體中,共用體的特點是,只是使用其中一個成員,如果使用兩個的話,前一個的值將會丟棄

void *ext_data; //void* 表示不確定類型的指針,可以接受任意類型的賦值

float reservoir;

} u;

我們可以存上面的allocateStorage()函數看到,如果存儲的數據小於float位元組數的話,就存儲在u.reservoir地址中;如果存儲的數據大於float位元組數,則使用void*來存儲;

----------------------------------------存儲的過程已解釋,下面來看取數據的過程--------------------------------------------

來看frameworksavmedialibstagefrightfoundationMetaData.cpp中findInt32()函數的實現:

bool MetaData::findInt32(uint32_t key, int32_t *value) { //通過key獲取對應value的值

uint32_t type = 0;

const void *data; //要獲取的是data的地址

size_t size;

if (!findData(key, &type, &data, &size) || type != TYPE_INT32) { //先獲取key對應的type/data/size的值;然後比較type是否是TYPE_INT32類型,如果不是說明key不是通過setInt32()來存儲的,直接返回false

return false;

}

CHECK_EQ(size, sizeof(*value)); //比較*value和我們獲取的data大小是否一致,如果一致就將data數據賦值給value

*value = *(int32_t *)data;

return true;

}

bool MetaData::findData(uint32_t key, uint32_t *type,

const void **data, size_t *size) const {

ssize_t i = mItems.indexOfKey(key); //獲取key在mItems中的id

if (i < 0) {

return false;

}

const typed_data &item = mItems.valueAt(i); //通過id獲取存儲的item的值

item.getData(type, data, size); //獲取值

return true;

}

從mItems.indexOfKey(key)/mItems.valueAt(i)可以明白,我們存儲的數據其實都是存在了mItems中去了

void MetaData::typed_data::getData(

uint32_t *type, const void **data, size_t *size) const {

*type = mType; //直接使用之前存在成員變數中的數據給它們賦值

*size = mSize;

*data = storage(); //給一級指針賦值,這樣*data的值就是storage返回的地址了

}

void *storage() {

//從size判斷是當時數據存儲成了哪個類型

return usesReservoir() ? &u.reservoir : u.ext_data;

}

這樣取數據的過程就完成了

關於data的二級指針,不太明白,日後再論

Android中MetaData.cpp數據存儲學習

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

Windows 下雙 Python 開發環境配置
mysql視圖

TAG:程序員小新人學習 |