翻译:QuickTime文件格式规范-概述

译者注:
这是一篇翻译文章,翻译这个资料的目的有两个

  1. 把资料翻译成中文,因为网上大多都是对于这个文档部分的解释或者截图,并且没有说明来源;
  2. 通过翻译,加深自己的理解。
    我们通常知道的mp4的文件结构就是这样的,还有3GP。

翻译正文:

QuickTime文件格式概述

QuickTime影片是存储在磁盘上,使用两个基本结构存储信息:atoms(也被称为simple atomsclassic atoms)和QT atoms。为了了解QuickTime影片的存储,你需要了解本章描述的基本的atoms结构。大多数你在QuickTime文件格式中看到的atoms都是simple 或classic atoms。即便如此,simple atoms和QT atoms,都允许构建任意复杂的分层数据结构,也都允许应用程序忽略不能识别的数据。

媒体描述

QuickTime文件把媒体的描述和媒体数据分开存储。
媒体描述被称为影片资源,影片atom,或简单的影片,包含信息包括:轨道的数量、视频压缩格式和定时信息等。影片资源还包含一个索引,该索引描述了存储所有的媒体数据的位置。
媒体数据是真实的采样点数据,如视频帧和音频样本,在影片中使用的。媒体数据可以存储在同一文件中作为QuickTime影片、或一个单独的文件中、或多个文件中、或替代资源,如数据库或实时流,或这些东西的某种组合。

Atoms

QuickTime文件的基本数据单元是atom。每个atom都包含在其他数据之前的size和type字段。size字段表示atom中的字节总数,包括size和type字段的长度。type字段通过type的含义指定存储在atom中的数据的格式类型。在某些情况下,size和type字段后跟一个version字段和一个flags字段。有这些version和flags字段的atom有时被称为full atom

📝 注:本文中描述的atom,是一个,如ISO规格的MPEG-4和运动JPEG 2000描述的box功能完全相同。一个包括version和flags字段的atom在功能上和这些规范中定义的full box是相同的。

Atom类型是由一个32位无符号整数指定,通常解释为一个四个字符的ASCII码。苹果公司保留所有的四个字符的完全由小写字母组成的代码。除非另有说明,QuickTime影片中所有的数据都以大端字节序存储,也被称为网络字节序,最重要的是第一个字节存储和传输。

实质上atom是分层次的。也就是说,一个atom可以包含其他atoms,这些子atoms依然可以包含其他atoms,等等。这种层次结构有时被描述成一个父atom,子atom,兄弟姐妹atoms,孙子atom,等等。包含其他atom的atom被称为container atomparent atom(父atom)是在层次结构中的一个给定atom的上一个level上的container atom。

例如,一个movie atom包含几个不同种类的atoms,其中包括movie中的每一个track的一个track atom。track atom,反过来,包含一个media atom,以及其他atoms,定义其他track特性。movie atom是track atoms的parent atom(父atom)。track atoms是兄弟姐妹atoms。track atom是media atoms的parent atom(父atom)。movie atom不是media atoms的父,因为它是在层次结构中的位置在超过media atoms一个以上的层。

不包含其他atoms的atom被称为叶atom,通常包含一个或多个字段或表的数据。一些叶atom作为标志或占位符,但是,并没有包含除size和type字段之外的数据。

在一个给定的atom中存储的数据的格式不能总是由atom的type字段单独确定;父atom的类型也可能是重要的。换言之,一个给定的atom类型可以依据它的父atom包含不同类型的信息。例如,一个movie atom内的profile atom包含有关该movie的信息,而在track atom内部的profile atom包含有关该track的信息。这意味着所有的QuickTime文件的阅读者必须考虑的不仅是atom类型,也要考虑atom的层次结构。

Atom Layout

图 1-1 所示的是sample atom的layout。每个atom都有自己的size和type信息,以及它的数据。在整个文档中,Container atom的名称(包含其他atoms的atom,包括其他的container atoms)被打印在一个灰色的框里,叶atom(Leaf atom)的名称(不包括其他atoms的atom)被打印在一个白色的框里。叶atoms包含数据,通常以表格的形式。

图 1-1 A sample atom

一个Leaf atom,如图1-1所示,简单的包含一系列通过位移(offsets)来组合数据字段。

Container atom内的atoms一般不必是在任何特定的顺序,除非这种顺序是专门在本文档中指出。一个这样的例子是处理description atom,它必须在处理数据之前。例如,一个media handler description atom必须在一个media information atom之前,一个data handler description atom必须在一个data information atom之前。

Atom结构

Atoms由一个header,紧跟atom data组成。header包含atom的size和type字段,以字节数给出了原子的size和它的type。它也可能包含一个extended size(扩展size)的字段,用一个64位整型给出一个大的atom的大小。如果extended size字段是有效的,那size字段被设置为1。atom的实际大小不能小于8字节(type和size字段的最小长度)。

一些atoms也包含version和flags字段。这些有时被称为full atom。该flag和version字段在本文档中不被视为atom header的一部分;它们被视为特定于包含它们的每个atom类型的data字段。这样的字段必须始终设置为零,除非另有规定。
Atom header由下列字段组成:

Atom size
  • 一个32位的整数,它表示atom的大小,包括atom的header和atom的内容,包括任何包含的atoms。通常情况下,size字段包含atom的实际大小,以字节为单位,表示为一个32位无符号整数。然而,size字段可以包含特定的值,该值指定决定atom大小的另一种方法。(这些特殊的值通常只用于media data('mdat')atoms。)
    size字段两个有效的特殊值:
  • 0,这只允许在一个顶层atom使用,指定在文件最后的atom,表明原子扩展到文件结尾。
  • 1,这意味着在extended size字段中给定实际大小,extended size字段是一个可选的64位字段,紧跟在type字段。这样就可容纳超过2个32字节的媒media data atoms('mdat')。
  • 图1-2显示了如何计算原子的大小。
Type
  • 一个包含atom类型的32位整数。这通常可以视作一有助记忆的四字符字段,如“moov”(0x6d6f6f76)为movie atom,或“trak”(0x7472616b)对为track atom,但非ASCII值(如0x00000001)也使用。
    知道atom的类型,可以解释它的数据。atom的数据可以被安排成任何字段、表或其他atoms的任意集合。数据结构是特定于atom类型的。一个给定类型的atom有一个定义好的数据结构。
    如果你的程序遇到一个未知类型的atom,就不该试图解释atom的数据,使用atom的size字段跳过这个atom和它所有的内容。这允许一定程度上与扩展了QuickTime文件格式的向前兼容性。

⚠️ 警告 当引入一个新版本的时候,一个给定类型的atom的内部结构可以改变。总是检查版本字段,如果存在的话。绝对不要试图解释由size或extended size字段定义的atom以外的数据的数据。

Extended Size
  • 如果一个atom的size字段被设置为1,type字段后面是一个64位extended size字段,它包含一个atom用64位无符号整数表示的实际大小。当media data atom('mdat')的大小超过2个32字节时使用这个。

当size字段包含atom的实际大小时,extended size字段不存在。这就意味着当一个QuickTime atom通过添加数据修改,修改后大小超过2 ^ 32字节的限制,没有extended size来记录新的atom的大小。因此,在不将其内容复制到一个新atom的前提下,并不总是可能扩展一个atom超过2^32个字节之外的。

为了防止这种不便,media data atoms通常在创建时添加一个64位的占位符atom紧接在movie文件前面。占位符atom有一种kWideAtomPlaceholderType('wide”)类型。

就像一个类型为“free”或“skip”的atom,“wide”atom是保留位,但在这种情况下,保留位是为特定的目的保留。如果“wide”atom直接在第二atom之前,第二atom可以从32-bit大小扩展64-bit大小,简单的通过从atom header的前8字节开始(覆盖‘wide’atom),设置size字段为1,并添加extended size字段。这种方法对样本数据的偏移量,不需要重新计算。

“wide”atom的大小正好是8个字节,仅由它的size和type字段组成。它不包含其他数据。

📝 注:一个常见的错误是认为,“wide”atom包含extended size。“wide”atom只不过是一个,如果必要的话可以被包含extended size字段的atom header覆盖的占位符。

图 1-2 Calculating atom sizes

QT Atoms和Atom Containers

QT atoms是一个增强的数据结构,提供了一种更通用的存储格式和删除一些使用simple atoms时出现的歧义。QT atom有一个扩展的报头;size和type字段后面跟着的是atom的ID和子Atom的数量。

这样允许通过识别ID指定相同类型的多个子atom。也使得它能够解析一个未知类型的QT atom的内容,通过走其子atom的树。

QT atoms通常是包裹在atom的容器中,一个header带有lock count的数据结构。每个atom容器包含一个根atom,QT atom。atom容器不是atom,并且不是不能在构成一个QuickTime movie文件的atom层次结构中发现。atom容器可能被发现作为一些atom内的数据结构,但是。例子包括media input maps和media property atoms。

图1-3 描述了QT atom的layout。每个QT atom从一个QT atom容器header开始,其次是根atom。根atom的类型是QT atom的类型。根atom包含任何其他atom,这些atom是结构的一部分。
每个container atom从一个QT atom header开始,其次是atom的内容。内容要么是子atom或数据,二者只能有一个。如果一个atom包含了子atom,那它也包含了所有的子atom的数据和后代。根atom总是存在,并且绝对没有任何兄弟姐妹atom。

图 1-3 QT atom layout

QT atom container header包含以下数据:

  • Reserved
    10 字节长的元素,设置为0.

  • Lock count
    16-bit 整型值,设置为0.
    每个QT atom header包含以下数据:

  • Size
    32-bit 整型值,表明atom包含的字节数,包含QT atom header和atom的内容的长度。如果atom是个叶atom,则这个字段包含单独atom的大小,container atoms的大小包含所有包含着的atoms,可以走用size和child count字段来遍历atom树。

  • Type
    32-bit 整型值,包含的是atom的类型。如果这是一个根atom,则type的值设置为'sean'.

  • Atom ID
    32-bit 整型值,atom的ID值。这个值在兄弟姐妹atom中必须是唯一的。根atom的ID值总是为1.

  • Reserved
    16-bit 整型值,必须设置为0。

  • Child count
    16-bit 整型值,指定包含的child atoms数量。这个数量只包含直接孩子atom。如果这个字段设置为0,那么该atom是个叶atom,并且只包含数据。

  • Reserved
    32-bit 整型值,必须设置为0.

QT Atom Containers

QuickTime atom container是QuickTime存储信息的基本结构。一个atom container是一个树状层次结构的QT atoms。你可以把一个新创建的QT atom container当作一个没有孩子atom的树结构的根。

atom container是一个容器,而不是一个atom。它有一个reserved字段和一个lock count字段在它的header,而不是一个size字段和type字段。atom container不在QuickTime movie文件的atom层次中,因为他们不是atoms。它们可能被发现在一些atoms内是数据,但是,如media input maps,media property atoms,video effects sample data和tween sample data。

一个QT atom container包含多个QT atoms,如图1-4所示。每个QT atom要么含有数据,要么有其他atoms。如果一个QT atom包含其它atoms,它是一个父atom,并且所包含atoms是孩子atom。每一个父atom的子atom是由它的atom type和atom ID唯一确定的。包含数据的QT atom被称为叶atom。

图 1-4 QT atom container with parent and child atoms

每个QT atom都有一个偏移量用于计算atom在QT atom container中的位置。此外,每个QT atom有一个type和ID,type是代表atom的种类信息。ID是用来区分同一父atom同一类型的子atom;一个给定的父亲和类型的atom的ID必须是唯一的。除了atom ID外,每个atom还有一个一维索引描述其相对于具有相同父亲相同类型的其他子atom的顺序。你可以通过以下三种方式的任意一种来唯一识别一个QT atom:

  • 通过它在QT atom container的偏移量
  • 通过父atom、类型和索引
  • 通过父atom、类型和ID

你可以通过索引、ID或者两者结合来存储和检索QT atom container。例如,使用QT atom container作为一个动态数组或树结构,可以通过索引来存储和检索。使用QT atom container作为一个数据库,你可以通过ID来存储和检索。通过使用ID和索引结合,你可以创建、存储和检索atoms,构建一个任意复杂可扩展的数据结构。

⚠️ 警告 因为QT atoms是数据结构上的偏移量,所以它们可以在对QT atom container进行编辑操作的时候变化,如插入或删除atoms。对于一个给定的atom,编辑子atoms是安全的,但编辑兄弟姐妹或父atoms,atom的偏移量将失效。

📝 注:出于跨平台的目的,所有在QT atom中的数据在应该是大端模式。但是,如果应用程序是自定义的话,叶atom的数据可以是小端。

图1-5显示的是一个包含两个子atom的QT atom container。第一个子atom(offset = 10)是叶atom,类型是"abcd",ID为1000,并且index为1。第二子atom(offset = 20的类型是“abcd”,ID是900,index为2。由于两个子atoms具有相同的类型,所以它们必须有不同的ID。第二个子atom也是一个三个atoms的父atom。

图 1-5 A QT atom container with two child atoms

第一个子atom(offset = 30)的类型为“abcd”,ID是100并且index为1。它没有子atom,也没有数据。第二个子atom(offset = 40)的类型是“word”,ID是100并且index为1。这个atom有数据,所以它是一个叶atom。第二个atom(offset = 40)和第一个atom(offset = 30)具有相同的标识,但不同的类型。第三个子atom(offset = 50)的类型为“abcd”,ID是1000并且index为2。它的类型和ID与另一个不同父结点的atom(偏移量= 10)相同。

📝 注意:如果你使用的是QuickTime API,那就不需要解析QT atom。相反,QT atom函数可以用来创建atom container,在atom container中添加atoms和移除atoms,在atom containers的atoms中检索数据。

大多数的QT atom函数接受两个参数来指定特定的原子:包含指定atom的atom container和指定atom在atom container数据结构中的偏移量。通过QTFindChildByID或者QTFindChildByIndex你可以取得atom的偏移量。如果包含atom的QT atom container被修改,那对应的atom的偏移量可能是无效的。

当调用任何QT atom函数为你指定一个父atom作为参数,你可以传递常量kParentAtomIsContainer作为atom偏移量来表明指定的父atom是atom container本身。例如,你调用QTFindChildByIndex函数,并且传递常量kParentAtomIsContainer给父atom参数,来表明那个请求的子atom是atom container本身的子结点。

QuickTime Movie文件

QuickTime文件格式描述了QuickTime movie文件的特点。QuickTime movie文件包含一个QuickTime movie资源,或者用movie reference指向一个或多个外部源。movie所使用的media sample(如视频帧或音频样本组)可能被包含在movie文件中,或者在movie文件外,在一个或多个文件,流或其他源。

QuickTime movie不仅限于视频和音频;它可以使用任何QuickTime支持的media类型的子集或组合,包括视频、声音、图片、文本、Flash、3D模型和虚拟现实全景图。它同时支持基于时间和非线性互动的媒体。
在支持文件扩展名的文件系统,QuickTime movie文件应该有一个扩展名.mov。在Macintosh平台,QuickTime文件有一个Mac OS文件类型“MooV”。QuickTime movie文件应始终与MIME类型“video/ quicktime”有关,无论这个movie是否包含视频。

📝 注:使用存储QuickTime media的资源fork已经从QuickTime文件格式中移除。下面的信息是用来记录现有的内容,不应该被用于新的开发。

在支持资源fork和数据fork的文件系统中,movie资源可以包含在资源fork中。默认情况下,在所有文件系统中movie资源被包含在数据fork中。如果media sample data包含在movie文件中,那它总在数据fork中。

QuickTime movie文件的结构是atoms的集合,一起成为文件QuickTime movie,描述这个movie的结构,并可能包含播放movie需要的sample data。并不是所有的atoms都是必需的。

该文件格式是可扩展的,偶尔加入新的atom类型。如果你的程序中遇到QuickTime文件中未知atom类型,应该简单地忽略它。这允许在不破坏现有程序的同时扩展文件格式,并提供了一种向前兼容性的方法。因为在任何atom的第一个字段是它的大小,包括任何包含的atom,这样很容易跳转到一个未知的atom类型结束的位置,并继续解析该文件。

⚠️ 重要 一般来说,atom可以以任何顺序出现。不要断定某个atom是不存在的,直到你分析了文件中的所有的atom。

有一个例外是file type atom,通常将文件标识为QuickTime movie。如果存在,这个atom先于任何一个movie atom,movie data,preview,或free space atoms。如果在遇到一个在file type atom之前有其他这些atom类型之一,则可能假设file type atom是不存在的。(这个atom在QuickTime文件格式规范2004中有介绍,而在2004年之前创建的QuickTime movie文件中是不存在的)。

其他的atoms可以是任何顺序,除了这个文件中特别指定的,出于实际的原因,有一个建议你应该使用的顺序,当你创建QuickTime movie文件时。例如,包含movie资源的atom应该先于包含movie样本数据的任何atom。如果你按照这个建议的atom顺序,那就有可能在文件还在下载的过程中,通过网络播放movie。

QuickTime movie文件必须包含一个movie atom,其中包含一个或多个备用的外部movie源的movie结构或参考。一般来说,这些替代源将成为包含movie结构的QuickTime movie文件。

QuickTime movie文件通常包含一个或多个movie data atoms,包含media sample data,如视频和音频采样组。可能在文件中没有movie data atoms,但是,这个movie可能依赖于外部的movie文件的采样数据,如外部数据文件或在互联网上的实时流。一个单一的movie data atom可能包含各种不同的媒体的采样数据。一般来说,一个movie使用的所有的media samples是可能存在于一个单一的movie data atom中的。movie data atom可以是相当大的,有时超过2^32字节。

图1-6显示在QuickTime movie文件中,基本的atom类型。此外,该文件可能包含free space atoms,preview atoms和其他没有列举在这个文件格式规范中的atoms。未知的atom类型应该被忽略。

图 1-6 The structure of a QuickTime movie file

表 1-1 列举了基本的atom类型。

表 1-1 QuickTime文件基础atom类型

Atom类型 使用
'ftyp' File type compatibility——识别文件类型,区别于类似的文件类型,如MPEG-4文件和JPEG文件。
'mood' Movie resource metadata(track的数量和类型,样本数据的位置等)。描述了可以哪里找以及如何解释movie数据。
'meat' Movie sample data——媒体采样,如视频帧和音频采样组。通常这个数据只有通过movie resource才能解释。
'free' Unused space available in file.
'skip' Unused space available in file.
'wide' 预留位——如果接下来的atom长度超过2^32字节,则将被extended size字段覆盖,而无需修改后面atom的内容。
'pnot' 参考movie preview data。

下面的部分详细描述了这些基本atom类型(除了movie atom),包括每个基本atom可能包含的其他atom的描述。movie atom在Movie Atoms中单独描述。

The File Type Compatibility Atom

文件类型兼容atom(The file type compatibility atom),也被称为文件类型atom,允许读者确定是否这是一种读者理解的类型的文件。具体地说,文件类型atom识别与之兼容的文件类型规范。这让读者能够区分密切相关的文件类型,如QuickTime movie文件,MPEG-4,和JPEG-2000文件(所有中可能包含的file type atoms,movie atoms和movie data atoms)。

当一个文件与多个规范兼容时,file type atom列出所有兼容类型,并指出兼容类型中的首选分支(brand)或最佳类型。例如,一个使用QuickTime兼容的文件格式的音乐播放器可以识别文件的最佳播放文件类型为音乐文件,但是还可以识别它为QuickTime movie文件。

file type atom提供进一步的区分同一类型不同版本或规范的目的,允许它传达比单独使用文件扩展名或MIME类型更多的信息。file type atom还具有对文件内部的优势,它比一个文件扩展名或MIME类型更不受偶然的改变。

📝 注:这里所描述的file type atom与文件类型框在MPEG-4和JPEG-2000 ISO规范中定义的功能相同。

file type atom是可选的,但强烈推荐。如果存在,它必须是文件中的第一个重要的原子,在movie atom的前面(和任何free space atoms,preview atom,或movie data atoms)。
file type atom的atom类型值是‘ftyp’并包含以下字段:

  • Size
    32位无符号整数,它指定在这个atom中的字节数。
  • Type
    32位无符号整数,确定atom类型,通常表示为一四个字符的代码;这字段必须设置为“ftyp”。
  • Major_Brand
    32位无符号整数,QuickTime movie文件应设置为“qt ”(注意尾部2个ASCII空格字符)。如果一个文件是多分支兼容,所有分支都列在Compatible_Brands字段,和Major_Brand标识的首选分支或最佳。
  • Minor_Version
    指示文件格式规范版本的32-bit字段。对于QuickTime movie文件,这需要四个二进制编码的十进制值,指示QuickTime文件格式规范的世纪,年,月,后面跟着的是一个二进制编码的十进制零。例如,在六月2004次版本,这个字段设置为BCD值20 04 06 00。
  • Compatible_brands [ ]
    一系列无符号的32位整数列表兼容的文件格式。主要分支必须出现在兼容品牌的列表中。一个或多个“placeholder”条目的值为零,是允许的;这样的条目应该被忽略。

如果没有的Compatible_Brands字段设置为“qt ”,那么该文件不是一个符合对应规范的QuickTime movie文件。程序应该返回错误,并关闭该文件,否则调用一个文件导入器,以适当的指定的brand之一,最好是 major brand。对于一个尝试打开文件类型,文件扩展名,或MIME类型标识为QuickTime movie的文件,但其file type atom不包括‘qt ’的,QuickTime目前返回一个错误。

📝 :此错误的常见来源是MPEG-4文件的扩展名不正确的命名为.mov,或MIME类型不正确的设置为”video/quicktime”。只有通过使用Mac OS的文件类型,文件扩展名或MIME类型正确识别为MPEG-4时, MPEG-4文件才会被QuickTime自动导入。

如果你正在创建一个文件类型是完全兼容QuickTime格式的文件,Compatible_Brand字段中的一个必须设置为“qt ”;否则将不会被识别为QuickTime movie文件。

Free Space Atoms

free和skip atoms这两个都指的是在movie data文件中指定未使用的空间。这些atoms由只有一个atom header(size和type字段),紧跟由适当字节数的未使用空间。读QuickTime movie时,您的程序可以放心的跳过这些atom。当写入或更新一个movie时,您可能会重新使用这些atom类型关联的空间。

wide atom通常在movie data atom之前。wide atom只由一个type和size的字段组成。这占据了8个字节——足够的空间来添加一个extended size字段到atom header下,而不取代atom的内容。如果一个atom的大小超过2 ^ 32字节,它的前面有一个wide atom,你可以创建一个新的覆盖现有的atom header和前面的wide atom含有一个extended size字段的atom header。

Movie Data Atoms

和free和skip atoms一样,movie data atom的结构非常简单。它由一个atom header(size和type字段),紧跟movie的media data。你的程序可以通过使用存储在movie atom中的元数据来理解这个atom中的数据。这个atom可以是相当大的,可能超过2^32字节,在这种情况下,size字段将被设置为1,而header将包含一个64位extended size字段。

Preview Atoms

preview atom包含的信息可以让你找到一个和QuickTime movie相关的预览图像。这张预览图,或海报,是一个有代表性的图像,适合于显示给用户,例如,打开对话框。图1-7描述了preview atom的。

图 1-7 The layout of a preview atom

preview atom的atom类型值为'not',在其atom header下,包含以下字段:

  • Size
    32位整数,指定在这个preview atom中的字节数。
  • Type
    32位整数,标识atom类型;该字段必须设置为'pnot'。
  • Modification date
    32位无符号整数,包含一个表示上次更新时的日期。数据使用的是标准的Macintosh格式。
  • Version number
    16位的整数,必须设置为0。
  • Atom type
    32位的整数,它表示包含预览数据的atom的类型。通常,这是设置为“PICT”来表示一个QuickDraw图片。
  • Atom index
    16位的整数,标识指定类型的atom被用作预览。通常情况下,此字段设置为1,以指示您应该使用atom类型字段中指定的类型的第一个atom。

📝 :本规范定义了主要用于向后兼容性的preview atom。目前的做法通常是通过把信息在movie header atom定义movie预览。更多请看Movie Header Atoms

The End

译者注:
第一次翻译英文文档,纯手工翻译,难免出现错误,欢迎指正!感谢!
资料链接:[英文原文][Overview of QTFF]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容