FFmpeg接口-AVDictionary的使用介紹和源碼分析

目錄

  1. AVDictionary的使用介紹
  2. FFmpeg中AVDictionary的使用
  3. AVDictionary的源碼學(xué)習(xí)
  4. 總結(jié)

參考

1. AVDictionary的使用介紹

AVDictionary是一個(gè)健值對(duì)存儲(chǔ)工具檀咙,類似于c++中的map,ffmpeg中有很多 API 通過它來傳遞參數(shù)璃诀。

AVDictionary 的定義如下:

//libavutil/dict.h
typedef struct AVDictionaryEntry {  
    char *key;  
    char *value;  
} AVDictionaryEntry;  

struct AVDictionary {  
    int count;  
    AVDictionaryEntry *elems;  
};

1.1. 基本用法

  1. 創(chuàng)建AVDictionary:將值為NULL的AVDictionary 指針變量的地址傳遞給av_dict_set()弧可。
  • AVDictionary結(jié)構(gòu)體的具體實(shí)現(xiàn)沒有在接口中暴露,不知道AVDictionary結(jié)構(gòu)體占用的內(nèi)存大小劣欢,所以使用者無法直接定義一個(gè)AVDictionary的變量棕诵,使用時(shí)需要定義一個(gè)AVDictionary指針的變量。
  • int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)凿将,如果*pm == NULL年鸳,會(huì)創(chuàng)建一個(gè)AVDictionary結(jié)構(gòu)體,把地址賦值給*pm丸相。av_dict_set函數(shù)的完整簽名:
AVDictionary *d = NULL;
av_dict_set(&d, "version", "1.0", AV_DICT_MATCH_CASE);
  • flags可以設(shè)為不同的選項(xiàng)的組合搔确,包含AV_DICT_MATCH_CASE時(shí)表示key的匹配是要區(qū)分大小寫的,默認(rèn)是不區(qū)分的,這一點(diǎn)要特別注意膳算。
  1. 添加key-value對(duì)座硕。
av_dict_set(&d, "version", "1.0", AV_DICT_MATCH_CASE);
av_dict_set_int(&d, "count", 3, AV_DICT_MATCH_CASE);
  1. 使用AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)檢索條目(AVDictionaryEntry)或遍歷字典。
  • AVDictionaryEntry中包含(char *)類型的key和value涕蜂。
  • 返回的AVDictionaryEntry不應(yīng)該被修改否則會(huì)發(fā)生未定義的行為华匾。

檢索條目

AVDictionaryEntry *t = NULL;

t = av_dict_get(d, "version", NULL, AV_DICT_MATCH_CASE);
av_log(NULL, AV_LOG_DEBUG, "version: %s", t->value);

t = av_dict_get(d, "count", NULL, AV_DICT_MATCH_CASE);
av_log(NULL, AV_LOG_DEBUG, "count: %d", (int) (*t->value));

遍歷字典

AVDictionaryEntry *t = NULL;
while ((t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX))) {
    av_log(NULL, AV_LOG_DEBUG, "%s: %s", t->key, t->value);
}
  1. 最后使用av_dict_free()釋放AVDictionary及其所有內(nèi)容。
av_dict_free(&d);

1.2 flags的用法

av_dict_get()和av_dict_set()函數(shù)都有一個(gè)flags參數(shù)机隙,下面對(duì)它的作用進(jìn)行介紹蜘拉,flags包含下面7個(gè)選項(xiàng),可以進(jìn)行組合使用:

#define AV_DICT_MATCH_CASE      1   /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */
#define AV_DICT_IGNORE_SUFFIX   2   /**< Return first entry in a dictionary whose first part corresponds to the search key,
                                         ignoring the suffix of the found key string. Only relevant in av_dict_get(). */
#define AV_DICT_DONT_STRDUP_KEY 4   /**< Take ownership of a key that's been
                                         allocated with av_malloc() or another memory allocation function. */
#define AV_DICT_DONT_STRDUP_VAL 8   /**< Take ownership of a value that's been
                                         allocated with av_malloc() or another memory allocation function. */
#define AV_DICT_DONT_OVERWRITE 16   ///< Don't overwrite existing entries.
#define AV_DICT_APPEND         32   /**< If the entry already exists, append to it.  Note that no
                                      delimiter is added, the strings are simply concatenated. */
#define AV_DICT_MULTIKEY       64   /**< Allow to store several equal keys in the dictionary */
  1. AV_DICT_MATCH_CASE:在字典中檢索key是需要區(qū)分大小寫有鹿,默認(rèn)是不區(qū)分大小寫的旭旭,這點(diǎn)需要特別注意。看一下如下的示例葱跋。
    AVDictionary *dict = NULL;
    av_dict_set(&dict, "version", "1.0", 0); 
    av_dict_set(&dict, "VERsion", "2.0", 0); 
    AVDictionaryEntry *t = NULL;
    while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
        fprintf(stdout, "%s: %s\n", t->key, t->value);
    }  
   av_dict_free(&d); 

程序的輸出是

VERsion: 2.0
  • av_dict_set在不設(shè)置AV_DICT_MATCH_CASE的情況下持寄,如果key值與字典中的key值在忽略大小寫的情況下是匹配的,會(huì)覆蓋字典中匹配條目的key和value娱俺。
  1. AV_DICT_IGNORE_SUFFIX:如果key值是字典中某個(gè)條目key值的前綴稍味,則認(rèn)為是匹配的。
    AVDictionary *dict = NULL;
    av_dict_set(&dict, "language", "ch", 0); 
    av_dict_set(&dict, "version", "1.0", 0); 
    AVDictionaryEntry *t1 = av_dict_get(dict, "ver", NULL, AV_DICT_IGNORE_SUFFIX);
    AVDictionaryEntry *t2 = av_dict_get(dict, "", NULL, AV_DICT_IGNORE_SUFFIX);
    fprintf(stdout, "t1, %s: %s\n", t1->key, t1->value);
    fprintf(stdout, "t2, %s: %s\n", t2->key, t2->value);
    av_dict_free(&d); 

上面示例的輸出

t1, version: 1.0
t2, language: ch
  • 由于flags包含了AV_DICT_IGNORE_SUFFIX的選項(xiàng)荠卷,所以key的匹配是按忽略后綴的方式(key是字典中條目的key的前綴)進(jìn)行的模庐,"ver"字符串是"version"字符串的前綴,所以獲取到字典中key為"version"的條目油宜。而“”空字符串是所有字符串的前綴掂碱,所以獲取到字典中的第一個(gè)條目。
  1. AV_DICT_DONT_STRDUP_KEY或AV_DICT_DONT_STRDUP_VAL:接管使用key或value指針指向的內(nèi)存的管理權(quán)验庙,不對(duì)key或value的值進(jìn)行復(fù)制顶吮。如下面示例所示。
    AVDictionary *d = NULL;
    AVDictionaryEntry *t = NULL;
    
    char *k = av_strdup("key");       // if your strings are already allocated,
    char *v = av_strdup("value");     // you can avoid copying them like this
    av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
    
    while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) {
        fprintf(stdout, "%s: %s\n", t->key, t->value);  
    }   
    av_dict_free(&d);

  1. AV_DICT_DONT_OVERWRITE:不覆蓋現(xiàn)有條目粪薛。如下面示例所示悴了。
    AVDictionary *d = NULL;
    AVDictionaryEntry *t = NULL;

    av_dict_set(&d, "version", "1.0", 0);
    av_dict_set(&d, "version", "2.0", AV_DICT_DONT_OVERWRITE);

    while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) {
        fprintf(stdout, "%s: %s\n", t->key, t->value);
    }
    av_dict_free(&d);

輸出結(jié)果為:version: 1.0

  1. AV_DICT_APPEND:如果目已經(jīng)存在,則value值直接拼接到之前的值的后面违寿。注意湃交,沒有添加分隔符,字符串只是連接在一起藤巢。如下面示例所示搞莺。
    AVDictionary *d = NULL;
    AVDictionaryEntry *t = NULL;
    
    av_dict_set(&d, "version", "1.0", 0); 
    av_dict_set(&d, "version", "2.0", AV_DICT_APPEND);
    
    while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) {
        fprintf(stdout, "%s: %s\n", t->key, t->value);  
    }   
    av_dict_free(&d);

輸出結(jié)果為:version: 1.02.0

  1. AV_DICT_MULTIKEY:允許在字典中存儲(chǔ)幾個(gè)相等的key。如下面示例所示掂咒。
    AVDictionary *dict = NULL;
    av_dict_set(&dict, "version", "1.0", 0);
    av_dict_set(&dict, "VERsion", "2.0", AV_DICT_MULTIKEY);
    av_dict_set(&dict, "version", "3.0", AV_DICT_MULTIKEY);
    AVDictionaryEntry *t = NULL;
    while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
        fprintf(stdout, "%s: %s\n", t->key, t->value);
    }
    av_dict_free(&dict);

輸出結(jié)果為:

version: 1.0
VERsion: 2.0
version: 3.0

2. FFmpeg中AVDictionary的使用

ffmpeg 中很多 API 都是靠 AVDictionary 來傳遞參數(shù)的才沧,比如常用的:

int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);

最后一個(gè)參數(shù)就是AVDictionary迈喉,我們可以在打開碼流前指定各種參數(shù),比如:探測時(shí)間温圆、超時(shí)時(shí)間挨摸、最大延時(shí)、支持的協(xié)議的白名單等等岁歉,例如:

AVDictionary *options = NULL;
av_dict_set(&options, “probesize”, “4096", 0);
av_dict_set(&options, “max_delay”, “5000000”, 0);

AVFormatContext *ic = avformat_alloc_context();
if (avformat_open_input(&ic, url, NULL, &options) < 0) {
    LOGE("could not open source %s", url);
    return -1;
} 

那么得运,我們怎么知道 ffmpeg 的這個(gè) API 支持哪些可配置的參數(shù)呢 ?

我們可以查看 ffmpeg 源碼锅移,比如 avformat_open_input 是結(jié)構(gòu)體 AVFormatContext 提供的 API熔掺,在 libavformat/options_table.h 中定義了 AVFormatContext 所有支持的 options 選項(xiàng),如下所示:doxygen文檔

同理非剃,AVCodec 相關(guān) API 支持的 options 選項(xiàng)則可以在 libavcodec/options_table.h 文件中找到置逻,如下所示:doxygen文檔

3. AVDictionary的源碼學(xué)習(xí)

主要看一下以下幾個(gè)函數(shù)的實(shí)現(xiàn):

  • av_dict_get
  • av_dict_set
  • av_dict_set_int
  • av_dict_copy
  • av_dict_free

3.1 av_dict_get

av_dict_get的邏輯比較簡單,代碼如下所示努潘。

//dict.c
AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
                               const AVDictionaryEntry *prev, int flags)
{
    unsigned int i, j;

    if (!m)
        return NULL;

    if (prev)
        i = prev - m->elems + 1;
    else
        i = 0;

    for (; i < m->count; i++) {
        const char *s = m->elems[i].key;
        if (flags & AV_DICT_MATCH_CASE)
            for (j = 0; s[j] == key[j] && key[j]; j++)
                ;
        else
            for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++)
                ;
        if (key[j])
            continue;
        if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX))
            continue;
        return &m->elems[i];
    }
    return NULL;
}
  • 如果prev不為空诽偷,則從prev之后的條目開始檢索坤学,prev - m->elems + 1為prev的下一個(gè)條目的索引疯坤。
  • 如果flags中包含AV_DICT_MATCH_CASE則直接對(duì)key的每個(gè)字符進(jìn)行比較,否則都轉(zhuǎn)換成大寫的字符進(jìn)行比較深浮。
  • 比較過程中压怠,if (key[j]) continue;表示傳入的key有未匹配完的字符即跟當(dāng)前條目的key不匹配,所以再去跟下一個(gè)條目進(jìn)行匹配飞苇。
  • 當(dāng)if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX)) continue;表示傳入的key是當(dāng)前條目的key的前綴菌瘫,但不是按照AV_DICT_IGNORE_SUFFIX的方式進(jìn)行匹配,即這個(gè)條目與檢索的key是不匹配的布卡,所以再去跟下一個(gè)條目進(jìn)行匹配雨让。

3.2 av_dict_set

av_dict_set邏輯要稍微復(fù)雜一些,源碼如下所示忿等。

//dict.c
int av_dict_set(AVDictionary **pm, const char *key, const char *value,
                int flags)
{
    AVDictionary *m = *pm;
    AVDictionaryEntry *tag = NULL;
    char *oldval = NULL, *copy_key = NULL, *copy_value = NULL;

    if (!(flags & AV_DICT_MULTIKEY)) {
        tag = av_dict_get(m, key, NULL, flags);
    }
    if (flags & AV_DICT_DONT_STRDUP_KEY)
        copy_key = (void *)key;
    else
        copy_key = av_strdup(key);
    if (flags & AV_DICT_DONT_STRDUP_VAL)
        copy_value = (void *)value;
    else if (copy_key)
        copy_value = av_strdup(value);
    if (!m)
        m = *pm = av_mallocz(sizeof(*m));
    if (!m || (key && !copy_key) || (value && !copy_value))
        goto err_out;

    if (tag) {
        if (flags & AV_DICT_DONT_OVERWRITE) {
            av_free(copy_key);
            av_free(copy_value);
            return 0;
        }
        if (flags & AV_DICT_APPEND)
            oldval = tag->value;
        else
            av_free(tag->value);
        av_free(tag->key);
        *tag = m->elems[--m->count];
    } else if (copy_value) {
        AVDictionaryEntry *tmp = av_realloc(m->elems,
                                            (m->count + 1) * sizeof(*m->elems));
        if (!tmp)
            goto err_out;
        m->elems = tmp;
    }
    if (copy_value) {
        m->elems[m->count].key = copy_key;
        m->elems[m->count].value = copy_value;
        if (oldval && flags & AV_DICT_APPEND) {
            size_t len = strlen(oldval) + strlen(copy_value) + 1;
            char *newval = av_mallocz(len);
            if (!newval)
                goto err_out;
            av_strlcat(newval, oldval, len);
            av_freep(&oldval);
            av_strlcat(newval, copy_value, len);
            m->elems[m->count].value = newval;
            av_freep(&copy_value);
        }
        m->count++;
    } else {
        av_freep(&copy_key);
    }
    if (!m->count) {
        av_freep(&m->elems);
        av_freep(pm);
    }

    return 0;

err_out:
    if (m && !m->count) {
        av_freep(&m->elems);
        av_freep(pm);
    }
    av_free(copy_key);
    av_free(copy_value);
    return AVERROR(ENOMEM);
}
  • 如果不支持AV_DICT_MULTIKEY栖忠,則在字典中檢索key是否有對(duì)應(yīng)的條目,保存為變量tag贸街。
    if (!(flags & AV_DICT_MULTIKEY)) {
        tag = av_dict_get(m, key, NULL, flags);
    }
  • 如果支持AV_DICT_DONT_STRDUP_KEY庵寞,則key指向的字符串不進(jìn)行拷貝。
if (flags & AV_DICT_DONT_STRDUP_KEY)
        copy_key = (void *)key;
else
        copy_key = av_strdup(key);
  • 如果傳入的字典為NULL薛匪,則創(chuàng)建一個(gè)AVDictionary捐川。
    if (!m)
        m = *pm = av_mallocz(sizeof(*m));
  • 如果key在字典中已經(jīng)有對(duì)應(yīng)的條目,并且flags中包含AV_DICT_DONT_OVERWRITE選項(xiàng)逸尖,即不覆蓋已有的條目古沥,則不對(duì)字典進(jìn)行修改瘸右,釋放key和value的內(nèi)存。
    if (tag) {
        if (flags & AV_DICT_DONT_OVERWRITE) {
            av_free(copy_key);
            av_free(copy_value);
            return 0;
        }
  • 如果key在字典中已經(jīng)有對(duì)應(yīng)的條目岩齿,并且flags中不包含AV_DICT_DONT_OVERWRITE選項(xiàng)尊浓,如果flags包含AV_DICT_APPEND的選項(xiàng),則把tag->value賦給oldval纯衍,后續(xù)拼接使用栋齿。尋找到的條目是elems數(shù)組的一個(gè)元素,把一項(xiàng)的值賦值為最后一個(gè)條目的值襟诸,即修改的這個(gè)條目出現(xiàn)在elems數(shù)組的最后一個(gè)元素瓦堵。
    if (tag) {
...
        if (flags & AV_DICT_APPEND)
            oldval = tag->value;
        else
            av_free(tag->value);
        av_free(tag->key);
        *tag = m->elems[--m->count];
  • 如果key在字典中沒有對(duì)應(yīng)的條目且value不為NULL,則需要對(duì)原有的elems數(shù)組擴(kuò)容歌亲,增加一項(xiàng)菇用。
    } else if (copy_value) {
        AVDictionaryEntry *tmp = av_realloc(m->elems,
                                            (m->count + 1) * sizeof(*m->elems));
        if (!tmp)
            goto err_out;
        m->elems = tmp;
    }
  • 如果value不為NULL,設(shè)置的key和value放置在elems最后一個(gè)元素陷揪,如果flags包含AV_DICT_APPEND惋鸥,則需要對(duì)oldval和value進(jìn)行拼接。如果value為NULL悍缠,則釋放掉key的內(nèi)存卦绣,即刪除了這個(gè)key匹配到的條目。
    if (copy_value) {
        m->elems[m->count].key = copy_key;
        m->elems[m->count].value = copy_value;
        if (oldval && flags & AV_DICT_APPEND) {
            size_t len = strlen(oldval) + strlen(copy_value) + 1;
            char *newval = av_mallocz(len);
            if (!newval)
                goto err_out;
            av_strlcat(newval, oldval, len);
            av_freep(&oldval);
            av_strlcat(newval, copy_value, len);
            m->elems[m->count].value = newval;
            av_freep(&copy_value);
        }
        m->count++;
    } else {
        av_freep(&copy_key);
    }
  • 如果條目個(gè)數(shù)為0了飞蚓,則釋放elems和AVDictionary的內(nèi)存滤港。
    if (!m->count) {
        av_freep(&m->elems);
        av_freep(pm);
    }

3.3 av_dict_set_int

av_dict_set_int的邏輯很簡單

//dict.c
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
                int flags)
{
    char valuestr[22];
    snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
    flags &= ~AV_DICT_DONT_STRDUP_VAL;
    return av_dict_set(pm, key, valuestr, flags);
}
  • 把int通過snprintf轉(zhuǎn)換成字符串的形式,需要把flags中的AV_DICT_DONT_STRDUP_VAL位抹掉趴拧,因?yàn)関aluestr是一個(gè)局部變量溅漾,需要進(jìn)行拷貝,再調(diào)用av_dict_set把key和value保存在字典中著榴。

3.4 av_dict_copy

//dict.c
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
{
    AVDictionaryEntry *t = NULL;

    while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX))) {
        int ret = av_dict_set(dst, t->key, t->value, flags);
        if (ret < 0)
            return ret;
    }

    return 0;
}
  • 遍歷src字典中的每個(gè)條目添履,然后設(shè)置到dst字典中。

3.5 av_dict_free

void av_dict_free(AVDictionary **pm)
{
    AVDictionary *m = *pm;

    if (m) {
        while (m->count--) {
            av_freep(&m->elems[m->count].key);
            av_freep(&m->elems[m->count].value);
        }
        av_freep(&m->elems);
    }
    av_freep(pm);
}
  • 釋放每個(gè)條目的key和value的內(nèi)存脑又、釋放條目數(shù)組elems的內(nèi)存暮胧、釋放AVDictionary 字典的內(nèi)存。

4. 總結(jié)

AVDictionary是一個(gè)健值對(duì)存儲(chǔ)工具挂谍,內(nèi)部是通過數(shù)組實(shí)現(xiàn)的叔壤。

  • 通過av_dict_set保存一個(gè)key、value對(duì)到字典AVDictionary中口叙,如果條目中沒有對(duì)應(yīng)的key炼绘,則新增一個(gè)條目;如果有則根據(jù)flags決定是否覆蓋妄田;如果value為NULL俺亮,則刪除key匹配的第一個(gè)條目驮捍。
  • 通過av_dict_get獲取key匹配的第一個(gè)條目。
  • av_dict_set和av_dict_get中的flags參數(shù)包含不同的匹配方式和設(shè)置選項(xiàng)脚曾。
    1. AV_DICT_MATCH_CASE:匹配大小寫
    2. AV_DICT_IGNORE_SUFFIX:匹配時(shí)忽略后綴)
    3. AV_DICT_DONT_STRDUP_KEY:不對(duì)key進(jìn)行拷貝
    4. AV_DICT_DONT_STRDUP_VAL:不對(duì)value進(jìn)行拷貝
    5. AV_DICT_DONT_OVERWRITE:不覆蓋現(xiàn)有條目
    6. AV_DICT_APPEND:如果目已經(jīng)存在东且,則value值直接拼接到之前的值的后面。
    7. AV_DICT_MULTIKEY:允許在字典中存儲(chǔ)相等的key本讥。

[2]中提到AVDictionary在實(shí)現(xiàn)上和API上都是低效的珊泳,它不具有伸縮性,使用字典很大時(shí)速度非常慢拷沸,在允許的情況下建議新代碼使用tree容器色查,它使用AVL樹來實(shí)現(xiàn)O(log n)性能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撞芍,一起剝皮案震驚了整個(gè)濱河市秧了,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌序无,老刑警劉巖验毡,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帝嗡,居然都是意外死亡晶通,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門丈探,熙熙樓的掌柜王于貴愁眉苦臉地迎上來录择,“玉大人拔莱,你說我怎么就攤上這事碗降。” “怎么了塘秦?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵讼渊,是天一觀的道長。 經(jīng)常有香客問我尊剔,道長爪幻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任须误,我火速辦了婚禮挨稿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘京痢。我一直安慰自己奶甘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布祭椰。 她就那樣靜靜地躺著臭家,像睡著了一般疲陕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钉赁,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天蹄殃,我揣著相機(jī)與錄音,去河邊找鬼你踩。 笑死诅岩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的带膜。 我是一名探鬼主播按厘,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼钱慢!你這毒婦竟也來了逮京?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤束莫,失蹤者是張志新(化名)和其女友劉穎懒棉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體览绿,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡策严,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饿敲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妻导。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖怀各,靈堂內(nèi)的尸體忽然破棺而出倔韭,到底是詐尸還是另有隱情,我是刑警寧澤瓢对,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布寿酌,位于F島的核電站,受9級(jí)特大地震影響硕蛹,放射性物質(zhì)發(fā)生泄漏醇疼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一法焰、第九天 我趴在偏房一處隱蔽的房頂上張望秧荆。 院中可真熱鬧,春花似錦埃仪、人聲如沸乙濒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琉兜。三九已至凯正,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豌蟋,已是汗流浹背廊散。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梧疲,地道東北人允睹。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像幌氮,于是被迫代替她去往敵國和親缭受。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容