分享
 
 
 

简单的jpeg转成avi的类

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

这是笔者写的一个小的类,用于把一系列jpeg文件转换为avi。

首先把源码帖出来:

//AviFormat.h

#ifndef _AVI_FORMAT_H_

#define _AVI_FORMAT_H_

#include <iostream>

using namespace std;

/* 4 bytes */

typedef int WORD;

typedef unsigned int DWORD;

/* for use in AVI_avih.flags */

const DWORD AVIF_HASINDEX = 0x00000010; /* index at end of file */

const DWORD AVIF_MUSTUSEINDEX = 0x00000020;

const DWORD AVIF_ISINTERLEAVED = 0x00000100;

const DWORD AVIF_TRUSTCKTYPE = 0x00000800;

const DWORD AVIF_WASCAPTUREFILE = 0x00010000;

const DWORD AVIF_COPYRIGHTED = 0x00020000;

struct AVI_avih

{

DWORD usec_per_frame; //* frame display rate (or 0L) */

DWORD max_bytes_per_sec; //* max. transfer rate */

DWORD padding; //* pad to multiples of this size; */

/* normally 2K */

DWORD flags;

DWORD tot_frames; //* # frames in file */

DWORD init_frames;

DWORD streams;

DWORD buff_sz;

DWORD width;

DWORD height;

DWORD reserved[4];

AVI_avih () {}

AVI_avih (DWORD usec, DWORD max, DWORD pad, DWORD flags, DWORD tot, DWORD init, DWORD str, DWORD buff, DWORD w, DWORD h, DWORD* re = NULL)

:usec_per_frame (usec), max_bytes_per_sec (max), padding (pad), tot_frames (tot)

,init_frames (init), streams (str), buff_sz (buff), width (w), height (h) {

if (re != NULL)

for (int i = 0; i < 4; ++i)

reserved[i] = re[i];

else

for (int i = 0; i < 4; ++i)

reserved[i] = 0;

}

AVI_avih (AVI_avih const& avih) {

usec_per_frame = avih.usec_per_frame;

max_bytes_per_sec = avih.max_bytes_per_sec;

padding = avih.padding;

flags = avih.flags;

tot_frames = avih.tot_frames;

init_frames = avih.init_frames;

streams = avih.streams;

buff_sz = avih.buff_sz;

width = avih.width;

height = avih.height;

for (int i; i < 4; ++i)

reserved[i] = avih.reserved[i];

}

~AVI_avih (){}

friend ostream& operator << (ostream& out, AVI_avih const& avih) {

out << avih.usec_per_frame << avih.max_bytes_per_sec << avih.padding << avih.flags << avih.tot_frames << avih.init_frames;

out << avih.streams << avih.buff_sz << avih.width << avih.height;

out << avih.reserved[0] << avih.reserved[1] << avih.reserved[2] << avih.reserved[3];

return out;

}

};

struct AVI_strh

{

unsigned char type[4]; ///* stream type */

unsigned char handler[4];

DWORD flags;

DWORD priority;

DWORD init_frames; ///* initial frames (???) */

DWORD scale;

DWORD rate;

DWORD start;

DWORD length;

DWORD buff_sz; ///* suggested buffer size */

DWORD quality;

DWORD sample_sz;

AVI_strh () {}

AVI_strh (char const* t, char const* h, DWORD f, DWORD p, DWORD in, DWORD sc, DWORD r, DWORD st, DWORD l, DWORD bs, DWORD q, DWORD ss)

: flags (f), priority (p), init_frames (in), scale (sc)

, rate (r), start (st), length (l), buff_sz (bs)

, quality (q) ,sample_sz (ss) {

for (int i = 0; i < 4; ++i) {

type[i] = t[i];

handler[i] = h[i];

}

}

AVI_strh (AVI_strh const& strh) {

flags = strh.flags;

priority = strh.priority;

init_frames = strh.init_frames;

scale = strh.scale;

rate = strh.rate;

start = strh.start;

length = strh.length;

buff_sz = strh.buff_sz;

quality = strh.quality;

sample_sz = strh.sample_sz;

for (int i = 0; i < 4; ++i) {

type[i] = strh.type[i];

handler[i] = strh.handler[i];

}

}

~AVI_strh () {}

friend ostream& operator << (ostream& out, AVI_strh const& strh) {

out << strh.type[0] << strh.type[1] << strh.type[2] << strh.type[3];

out << strh.handler[0] << strh.handler[1] << strh.handler[2] << strh.handler[3];

out << strh.flags << strh.priority << strh.init_frames << strh.scale << strh.rate;

out << strh.start << strh.length << strh.buff_sz << strh.quality << strh.sample_sz;

return out;

}

};

struct AVI_strf

{

DWORD sz;

DWORD width;

DWORD height;

DWORD planes_bit_cnt;

unsigned char compression[4];

DWORD image_sz;

DWORD xpels_meter;

DWORD ypels_meter;

DWORD num_colors; // used colors

DWORD imp_colors; // important colors

/*

may be more for some codecs

*/

AVI_strf () {}

AVI_strf (DWORD s, DWORD w, DWORD h, DWORD p, char const* c, DWORD i, DWORD x, DWORD y, DWORD n, DWORD imp)

:sz (s), width (w), height (h), planes_bit_cnt (p), image_sz (i)

,xpels_meter (x), ypels_meter (y), num_colors (n), imp_colors (imp) {

for (int i = 0; i < 4; ++i)

compression[i] = c[i];

}

AVI_strf (AVI_strf const& strf) {

sz = strf.sz;

width = strf.width;

height = strf.height;

planes_bit_cnt = strf.planes_bit_cnt;

image_sz = strf.image_sz;

xpels_meter = strf.xpels_meter;

ypels_meter = strf.ypels_meter;

num_colors = strf.num_colors;

imp_colors = strf.imp_colors;

for (int i = 0; i < 4; ++i)

compression[i] = strf.compression[i];

}

~AVI_strf () {}

friend ostream& operator << (ostream& out, AVI_strf const& strf) {

out << strf.sz << out << strf.width << strf.height << strf.planes_bit_cnt;

out << strf.compression[0] << strf.compression[1] << strf.compression[2] << strf.compression[3];

out << strf.image_sz << strf.xpels_meter << strf.ypels_meter << strf.num_colors << strf.imp_colors;

return out;

}

};

/*

AVI_list_hdr

spc: a very ubiquitous AVI struct, used in list structures

to specify type and length

*/

struct AVI_list_hdr

{

unsigned char id[4]; /* "LIST" */

DWORD sz; /* size of owning struct minus 8 */

unsigned char type[4]; /* type of list */

AVI_list_hdr () {}

AVI_list_hdr (char const* list, DWORD d, char const* value) {

sz = d;

for (int i = 0; i < 4; ++i) {

id[i] = list[i];

type[i] = value[i];

}

}

AVI_list_hdr (AVI_list_hdr const& hdr) {

for (int i = 0; i < 4; ++i) {

id[i] = hdr.id[i];

type[i] = hdr.type[i];

}

sz = hdr.sz;

}

~AVI_list_hdr () {}

friend ostream& operator<< (ostream& out, AVI_list_hdr const& hdr) {

out << hdr.id[0] << hdr.id[1] << hdr.id[3] << hdr.id[4] << hdr.sz << hdr.type[0] << hdr.type[1] << hdr.type[2] << hdr.type[3];

return out;

}

};

struct AVI_list_odml

{

struct AVI_list_hdr list_hdr;

unsigned char id[4];

DWORD sz;

DWORD frames;

AVI_list_odml () {}

AVI_list_odml (char const* l1, DWORD d1, char const* v1, char const* l2, DWORD d2, DWORD f)

:list_hdr (l1, d1, v1), sz (d2), frames (f) {

for (int i = 0; i < 4; ++i)

id[i] = l2[i];

}

AVI_list_odml (AVI_list_hdr const hdr, char const* v, DWORD d2, DWORD f)

: list_hdr (hdr), sz (d2), frames (f) {

for (int i = 0; i < 4; ++i)

id[i] = v[i];

}

AVI_list_odml (AVI_list_odml const& odml)

:list_hdr (odml.list_hdr), sz (odml.sz), frames (odml.frames) {

for (int i = 0; i < 4; ++i)

id[i] = odml.id[i];

}

~AVI_list_odml () {}

friend ostream& operator << (ostream& out, AVI_list_odml const& odml){

out << odml.list_hdr << odml.id[0] << odml.id[1] << odml.id[2] << odml.id[3];

out << odml.sz << odml.frames;

return out;

}

};

struct AVI_list_strl

{

struct AVI_list_hdr list_hdr;

/* chunk strh */

unsigned char strh_id[4];

DWORD strh_sz;

struct AVI_strh strh;

/* chunk strf */

unsigned char strf_id[4];

DWORD strf_sz;

struct AVI_strf strf;

/* list odml */

struct AVI_list_odml list_odml;

};

struct AVI_list_hdrl

{

struct AVI_list_hdr list_hdr;

/* chunk avih */

unsigned char avih_id[4];

DWORD avih_sz;

struct AVI_avih avih;

/* list strl */

struct AVI_list_hdr strl_hdr;

/* chunk strh */

unsigned char strh_id[4];

DWORD strh_sz;

struct AVI_strh strh;

/* chunk strf */

unsigned char strf_id[4];

DWORD strf_sz;

struct AVI_strf strf;

/* list odml */

struct AVI_list_odml list_odml;

AVI_list_hdrl (DWORD width = 0, DWORD height = 0, DWORD jpg_sz = 1, DWORD per_usec = 1, DWORD frames = 1)

:list_hdr ("LIST", sizeof (struct AVI_list_hdrl) - 8, "hdrl")

//* chunk avih */

,avih_sz (sizeof (struct AVI_avih))

,avih (per_usec, 1000000 * (jpg_sz/frames) / per_usec, (0)

,AVIF_HASINDEX, frames, 0, 1, 0, width, height)

// list strl

,strl_hdr ("LIST", sizeof (struct AVI_list_strl) - 8, "strl")

// chunk strh

,strh_sz (sizeof (struct AVI_strh))

,strh ("vids", "MJPG", 0, 0, 0, per_usec, 1000000

, 0, frames, 0, 0, 0)

// chunk strf

,strf_sz (sizeof (AVI_strf))

,strf (sizeof (struct AVI_strf), width, height, 1 + 24*256*256

,"MJPG", width * height * 3, 0, 0, 0, 0)

// list odml

,list_odml ("LIST", 16, "odml", "dmlh", 4, frames) {

avih_id[0] = 'a'; avih_id[1] = 'v'; avih_id[2] = 'i'; avih_id[3] = 'h';

strh_id[0] = 's'; strh_id[1] = 't'; strh_id[2] = 'r'; strh_id[3] = 'h';

strf_id[0] = 's'; strf_id[1] = 't'; strf_id[2] = 'r'; strf_id[3] = 'f';

}

~AVI_list_hdrl (){}

friend ostream& operator << (ostream& out, AVI_list_hdrl const& hdrl) {

out << hdrl.list_hdr << hdrl.avih_id[0] << hdrl.avih_id[1] << hdrl.avih_id[2] << hdrl.avih_id[3];

out << hdrl.avih_sz << hdrl.strl_hdr;

out << hdrl.strh_id[0] << hdrl.strh_id[1] << hdrl.strh_id[2] << hdrl.strh_id[3];

out << hdrl.strh_sz << hdrl.strh;

out << hdrl.strf_id[0] << hdrl.strf_id[1] << hdrl.strf_id[2] << hdrl.strf_id[3];

out << hdrl.strf_sz << hdrl.strf << hdrl.list_odml;

return out;

}

};

#endif //_AVI_FORMAT_H_

//AviGenerator.h

#ifndef _AVI_GENERATOR_H_

#define _AVI_GENERATOR_H_

#define DEBUG_VERSION

#include <stdio.h>

#include <string>

#include <vector>

#include "AviFormat.h"

using namespace std;

/* 4 bytes */

typedef int WORD;

typedef unsigned int DWORD;

/* 1 byte */

typedef unsigned char BYTE;

class AviGenerator

{

public:

AviGenerator(void);

~AviGenerator(void);

void set_avi_file (string const& file);

void set_fps (int fps);

int add_frame (string const& file);

void set_avi_size (int w, int h);

int generate_avi ();

private:

int file_size (string const& file);

int files_size ();

int initalize_header ();

void print_quartet (FILE* file, DWORD i);

public:

static DWORD const MAX_RIFF_SZ = 2147483648LL; /*Max avi file size, 2 GB limit*/

static DWORD const JPEG_DATA_SZ = sizeof(DWORD) * 2;

struct Jpeg_Data

{

DWORD size;

DWORD offset;

string name; /* i.e. variable length structure */

Jpeg_Data () {}

~Jpeg_Data () {}

friend bool operator< (Jpeg_Data const& a, Jpeg_Data const& o) {

return a.name < o.name;

}

static bool lestthan (Jpeg_Data const* a, Jpeg_Data const* o) {

return a->name < o->name;

}

};

protected:

string avi_name_;

WORD fps_;

WORD frames_;

WORD usec_per_frame;

//file structure

AVI_list_hdrl list_hdrl;

//file list

vector <Jpeg_Data*> jpeg_list;

//option

DWORD width;

DWORD height;

DWORD frames;

unsigned int fps;

long jpg_sz;

size_t jpg_sz_64;

size_t riff_sz_64;

DWORD riff_sz;

};

#endif

//AviGenerator.cpp

#include "AviGenerator.h"

#include <iostream>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <algorithm>

#ifdef _WIN32

#include <io.h>

#include <errno.h>

#else

#include <sys/param.h>

#include <unistd.h>

#endif

using namespace std;

AviGenerator::AviGenerator(void)

:fps (15) ,frames (1), jpg_sz (1), width (320), height (240)

{

usec_per_frame = 1000000 / fps;

}

AviGenerator::~AviGenerator(void)

{

for (vector<Jpeg_Data*>::iterator iter = this->jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {

Jpeg_Data* p = *iter;

delete p;

}

this->jpeg_list.clear ();

}

void AviGenerator::set_avi_file (string const& file)

{

this->avi_name_ = file;

}

void AviGenerator::set_fps (int fps)

{

this->fps_ = fps;

this->usec_per_frame = 1000000 / fps;

}

void AviGenerator::set_avi_size (int w, int h)

{

this->width = w;

this->height = h;

}

int AviGenerator::file_size (string const& file)

{

int ret;

#ifdef _WIN32

struct __stat64 result;

if (-1 == _stat64 (file.c_str (), &result))

return -1;

ret = result.st_size;

#else

struct stat s;

if (-1 == stat(file.c_str (), &s))

return -1;

ret = s.st_size;

#endif

#ifdef DEBUG_VERSION

cerr << file.c_str () << " size is " << ret << endl;

#endif

return ret;

}

int AviGenerator::files_size ()

{

int ret = 0;

int tmp, it;

for (vector<Jpeg_Data*>::iterator iter = jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {

it = (*iter)->size;

tmp = it != 0?it:file_size ((*iter)->name.c_str ());

ret += tmp;

ret += (4 - (tmp % 4)) % 4;

}

return ret;

}

int AviGenerator::add_frame (string const& file)

{

int size = file_size (file);

if (size <= 0)

return -1;

struct Jpeg_Data* jpeg= new Jpeg_Data ();

jpeg->name = file;

jpeg->size = size;

jpeg->offset = 0;

this->jpeg_list.insert (jpeg_list.begin (), jpeg);

return 0;

}

void AviGenerator::print_quartet (FILE* file, DWORD i)

{

for (int j = 0; j < 4; ++j) {

fputc (i % 0x0100, file);

i /= 0x100;

}

}

int AviGenerator::initalize_header ()

{

frames = this->jpeg_list.size ();

if (frames <= 0)

return -1;

/* getting image, and hence, riff sizes */

jpg_sz_64 = this->files_size ();

if (-1 == jpg_sz_64) {

cerr << "couldn't determine size of images" << endl;

return -2;

}

riff_sz_64 = sizeof (struct AVI_list_hdrl) + 4 + 4 + jpg_sz_64 + 8 * frames + 8 + 8 + 16 * frames;

if (riff_sz_64 >= MAX_RIFF_SZ) {

cerr << "RIFF would exceed 2 Gb limit" << endl;

return -3;

}

jpg_sz = (long) jpg_sz_64;

riff_sz = (DWORD) riff_sz_64;

//update the struct AVI_list_hdrl

this->list_hdrl.avih.usec_per_frame = LILEND4(usec_per_frame);

this->list_hdrl.avih.max_bytes_per_sec = LILEND4((int)1000000 * (jpg_sz / frames) / usec_per_frame);

this->list_hdrl.avih.flags = LILEND4(AVIF_HASINDEX);

this->list_hdrl.avih.tot_frames = LILEND4(frames);

this->list_hdrl.avih.width = LILEND4(width);

this->list_hdrl.avih.height = LILEND4(height);

this->list_hdrl.strh.scale = LILEND4(usec_per_frame);

this->list_hdrl.strh.rate = LILEND4(1000000);

this->list_hdrl.strh.length = LILEND4(frames);

this->list_hdrl.strf.width = LILEND4(width);

this->list_hdrl.strf.height = LILEND4(height);

this->list_hdrl.strf.image_sz = LILEND4(width * height * 3);

this->list_hdrl.list_odml.frames = LILEND4(frames);

return 0;

}

int AviGenerator::generate_avi ()

{

if (this->initalize_header () != 0)

return -1;

//open the file

FILE* fdest = fopen (this->avi_name_.c_str (), "wb");

if (NULL == fdest) {

cerr << "Can't create a new file to write (" << this->avi_name_ << ")!" << endl;

return -2;

}

//fwrite (&list_hdrl.avih.max_bytes_per_sec, 4, 1, fdest);

long nbr;

long nbw;

long tnbw = 0;

long mfsz;

long remnant;

char buff[512];

//write file header

fwrite ("RIFF", 4, 1, fdest);

print_quartet (fdest, riff_sz);

fwrite ("AVI ", 4, 1, fdest);

fwrite (&list_hdrl, sizeof (struct AVI_list_hdrl), 1, fdest);

//sort the list by file name

sort (this->jpeg_list.begin (), this->jpeg_list.end (), AviGenerator::Jpeg_Data::lestthan);

// list movi

size_t offset = 4;

fwrite ("LIST", 4, 1, fdest);

print_quartet (fdest, jpg_sz + 8 * frames + 4);

fwrite ("movi", 4, 1, fdest);

//write video data

for (vector <Jpeg_Data*>::iterator iter = this->jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {

#ifdef DEBUG_VERSION

cout << "dealing with " << (*iter)->name << endl;

#endif

fwrite ("00db", 4, 1, fdest);

mfsz = (*iter)->size;

remnant = (4 - (mfsz % 4)) % 4;

print_quartet (fdest, mfsz + remnant);

(*iter)->size += remnant;

(*iter)->offset = offset;

offset += (*iter)->size + 8;

int fd;

#ifdef _WIN32

fd = open ((*iter)->name.c_str (), O_RDONLY | O_BINARY);

#else

fd = open ((*iter)->name.c_str (), O_RDONLY);

#endif

if (fd < 0) {

cerr << "couldn't open file (" << (*iter)->name << ")!" << endl;

fclose (fdest);

return -3;

}

nbw = 0;

if ((nbr = read (fd, buff, 6)) != 6) {

cerr << "reading error" << endl;

fclose (fdest);

close (fd);

return -4;

}

fwrite (buff, nbr, 1, fdest);

read (fd, buff, 4);

fwrite ("AVI1", 4, 1, fdest);

nbw = 10;

while ((nbr = read (fd, buff, 512)) > 0){

#ifdef DEBUG_VERSION

//cout << "read " << nbr << " bytes from " << (*iter)->name << endl;

#endif

fwrite (buff, nbr, 1, fdest);

nbw += nbr;

}

if (remnant > 0) {

fwrite (buff, remnant, 1, fdest);

nbw += remnant;

}

tnbw += nbw;

close (fd);

}

if (tnbw != jpg_sz) {

cerr << "error writing images (wrote " << tnbw << " bytes, expected " << jpg_sz << " bytes)" << endl;

fclose (fdest);

return -5;

}

/* indices */

fwrite ("idx1", 4, 1, fdest);

print_quartet (fdest, 16 * frames);

for (vector <Jpeg_Data*>::iterator iter = this->jpeg_list.begin (); iter != jpeg_list.end (); ++iter) {

fwrite ("00db", 4, 1, fdest);

print_quartet (fdest, 18);

print_quartet (fdest, (*iter)->offset);

print_quartet (fdest, (*iter)->size);

}

//this->jpeg_list.clear ();

fclose (fdest);

return 0;

}

//main.cpp 测试文件

// tmp.cpp : 定义控制台应用程序的入口点。

//

#include <iostream>

#include <fstream>

#include "AviGenerator.h"

using namespace std;

int main(int argc, char* argv[])

{

//ofstream fout ("temp.txt", ios::out);

//fout.close ();

AviGenerator generator;

for (int i = 1; i <= 38; ++i) {

char c[32];

sprintf (c, "mao%02d", i);//加入jpeg文件,我有mao01~38.jpg文件

strcat (c, ".jpg");

cout << c << endl;

generator.add_frame (c);

}

cout << "generating avi file......" << endl;

if (argc >=2)

generator.set_avi_file (argv[1]);

else

generator.set_avi_file ("mao.avi");

generator.set_fps (15);

generator.set_avi_size (230, 100);

generator.generate_avi ();

//system ("pause");

return 0;

}

Makefile文件就不作了,只有两个.cpp文件,对于大家编译应该没有什么问题吧。

笔者在原有的基础上把原来的C代码改写成了一个类,便于使用(如果不喜欢完全可以去找“原版”的C代码),并加入了Win32平台的支持(其实对于笔者来说没什么用——笔者的程序是在Linux下运行的)。

笔者在VC2003、VC2005 beta1编译,以及用g++、c++都是没有问题的,生成的avi文件用media player正常播放,但是因为没有进行压缩,所以个头有点大(有空我会考虑进行改进的^_^),但是比个别程序的生成方式还是有优势的。存储和传输的时候大家可以用winrar压缩(作个免费广告,压缩率大得惊人)。

另外,重载了<<,没用上,因为笔者对标准库不熟悉,没有找到可以写入二进制的办法,所以回到了调用c函数的路上。如果你有办法可以告诉笔者吗?

不断学习中……,欢迎email交流。

darkstar21cn@hotmail.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有