最简单的基于FFMPEG的封装格式转换器(无编解码)
https://blog.csdn.net/leixiaohua1020/article/details/25422685

=====================================================

最简单的基于FFmpeg的封装格式处理系列文章列表:

最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)

最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)

最简单的基于FFMPEG的封装格式处理:封装格式转换(remuxer)

=====================================================

简介

本文介绍一个基于FFMPEG的封装格式转换器。所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(对应.avi,.flv,.mkv,.mp4文件)。需要注意的是,本程序并不进行视音频的编码和解码工作。而是直接将视音频压缩码流从一种封装格式文件中获取出来然后打包成另外一种封装格式的文件。传统的转码程序工作原理如下图所示:

上图例举了一个举例:FLV(视频:H.264,音频:AAC)转码为AVI(视频:MPEG2,音频MP3)的例子。可见视频转码的过程通俗地讲相当于把视频和音频重新“录”了一遍。
本程序的工作原理如下图所示:

由图可见,本程序并不进行视频和音频的编解码工作,因此本程序和普通的转码软件相比,有以下两个特点:
处理速度极快。视音频编解码算法十分复杂,占据了转码的绝大部分时间。因为不需要进行视音频的编码和解码,所以节约了大量的时间。

视音频质量无损。因为不需要进行视音频的编码和解码,所以不会有视音频的压缩损伤。

流程(2014.9.29更新)

下面附上基于FFmpeg的Remuxer的流程图。图中使用浅红色标出了关键的数据结构,浅蓝色标出了输出视频数据的函数。可见成个程序包含了对两个文件的处理:读取输入文件(位于左边)和写入输出文件(位于右边)。中间使用了一个avcodec_copy_context()拷贝输入的AVCodecContext到输出的AVCodecContext。

简单介绍一下流程中关键函数的意义:

输入文件操作:

avformat_open_input():打开输入文件,初始化输入视频码流的AVFormatContext。

av_read_frame():从输入文件中读取一个AVPacket。

输出文件操作:

avformat_alloc_output_context2():初始化输出视频码流的AVFormatContext。

avformat_new_stream():创建输出码流的AVStream。

avcodec_copy_context():拷贝输入视频码流的AVCodecContex的数值t到输出视频的AVCodecContext。

avio_open():打开输出文件。

avformat_write_header():写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。

av_interleaved_write_frame():将AVPacket(存储视频压缩码流数据)写入文件。

av_write_trailer():写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS)。

代码

贴上代码,代码是从FFmpeg的例子改编的,平台是VC2010。

[cpp] view plain copy
  1. /*
  2. *最简单的基于FFmpeg的封装格式转换器
  3. *Simplest FFmpeg Remuxer
  4. *
  5. *雷霄骅 Lei Xiaohua
  6. *leixiaohua1020@126.com
  7. *中国传媒大学/数字电视技术
  8. *Communication University of China / Digital TV Technology
  9. *http://blog.csdn.net/leixiaohua1020
  10. *
  11. *本程序实现了视频封装格式之间的转换。
  12. *需要注意的是本程序并不改变视音频的编码格式。
  13. *
  14. * This software converts a media file from one container format
  15. * to another container format without encoding/decoding video files.
  16. */
  17. #include "stdafx.h"
  18. extern "C"
  19. {
  20. #include "libavformat/avformat.h"
  21. };
  22. int _tmain(int argc, _TCHAR* argv[])
  23. {
  24. AVOutputFormat *ofmt = NULL;
  25. //输入对应一个AVFormatContext,输出对应一个AVFormatContext
  26. //(Input AVFormatContext and Output AVFormatContext)
  27. AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
  28. AVPacket pkt;
  29. const char *in_filename, *out_filename;
  30. int ret, i;
  31. if (argc < 3) {
  32. printf("usage: %s input output\n"
  33. "Remux a media file with libavformat and libavcodec.\n"
  34. "The output format is guessed according to the file extension.\n"
  35. "Modified by Lei Xiaohua, leixiaohua1020@126.com\n"
  36. "Communication University of China / Digital TV Technology\n"
  37. "http://blog.csdn.net/leixiaohua1020", argv[0]);
  38. return 1;
  39. }
  40. in_filename  = argv[1];//输入文件名(Input file URL)
  41. out_filename = argv[2];//输出文件名(Output file URL)
  42. av_register_all();
  43. //输入(Input)
  44. if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
  45. printf( "Could not open input file.");
  46. goto end;
  47. }
  48. if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
  49. printf( "Failed to retrieve input stream information");
  50. goto end;
  51. }
  52. av_dump_format(ifmt_ctx, 0, in_filename, 0);
  53. //输出(Output)
  54. avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
  55. if (!ofmt_ctx) {
  56. printf( "Could not create output context\n");
  57. ret = AVERROR_UNKNOWN;
  58. goto end;
  59. }
  60. ofmt = ofmt_ctx->oformat;
  61. for (i = 0; i < ifmt_ctx->nb_streams; i++) {
  62. //根据输入流创建输出流(Create output AVStream according to input AVStream)
  63. AVStream *in_stream = ifmt_ctx->streams[i];
  64. AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
  65. if (!out_stream) {
  66. printf( "Failed allocating output stream\n");
  67. ret = AVERROR_UNKNOWN;
  68. goto end;
  69. }
  70. //复制AVCodecContext的设置(Copy the settings of AVCodecContext)
  71. ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
  72. if (ret < 0) {
  73. printf( "Failed to copy context from input to output stream codec context\n");
  74. goto end;
  75. }
  76. out_stream->codec->codec_tag = 0;
  77. if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
  78. out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
  79. }
  80. //输出一下格式------------------
  81. av_dump_format(ofmt_ctx, 0, out_filename, 1);
  82. //打开输出文件(Open output file)
  83. if (!(ofmt->flags & AVFMT_NOFILE)) {
  84. ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
  85. if (ret < 0) {
  86. printf( "Could not open output file '%s'", out_filename);
  87. goto end;
  88. }
  89. }
  90. //写文件头(Write file header)
  91. ret = avformat_write_header(ofmt_ctx, NULL);
  92. if (ret < 0) {
  93. printf( "Error occurred when opening output file\n");
  94. goto end;
  95. }
  96. int frame_index=0;
  97. while (1) {
  98. AVStream *in_stream, *out_stream;
  99. //获取一个AVPacket(Get an AVPacket)
  100. ret = av_read_frame(ifmt_ctx, &pkt);
  101. if (ret < 0)
  102. break;
  103. in_stream  = ifmt_ctx->streams[pkt.stream_index];
  104. out_stream = ofmt_ctx->streams[pkt.stream_index];
  105. /* copy packet */
  106. //转换PTS/DTS(Convert PTS/DTS)
  107. pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  108. pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  109. pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
  110. pkt.pos = -1;
  111. //写入(Write)
  112. ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
  113. if (ret < 0) {
  114. printf( "Error muxing packet\n");
  115. break;
  116. }
  117. printf("Write %8d frames to output file\n",frame_index);
  118. av_free_packet(&pkt);
  119. frame_index++;
  120. }
  121. //写文件尾(Write file trailer)
  122. av_write_trailer(ofmt_ctx);
  123. end:
  124. avformat_close_input(&ifmt_ctx);
  125. /* close output */
  126. if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
  127. avio_close(ofmt_ctx->pb);
  128. avformat_free_context(ofmt_ctx);
  129. if (ret < 0 && ret != AVERROR_EOF) {
  130. printf( "Error occurred.\n");
  131. return -1;
  132. }
  133. return 0;
  134. }

调试的时候,只需要“右键工程->调试->命令行参数”里面设置输入的文件名和输出的文件名就可以了。

结果

下图显示了一个测试的输入文件的视音频参数。

下图显示了输出文件的视音频参数。可以看出除了视频的封装格式从flv转换成了mp4,其他有关视音频编码的参数没有任何变化。

下载

simplest ffmpeg format

项目主页

SourceForge:https://sourceforge.net/projects/simplestffmpegformat/

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_format

开源中国:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_format

CSDN下载:
http://download.csdn.net/detail/leixiaohua1020/8005317

工程中包含4个例子:

simplest_ffmpeg_demuxer_simple:视音频分离器(简化版)。

simplest_ffmpeg_demuxer:视音频分离器。

simplest_ffmpeg_muxer:视音频复用器。

simplest_ffmpeg_remuxer:封装格式转换器。

更新-1.1==================================================

修复了以下问题:
(1)Release版本下的运行问题
(2)simplest_ffmpeg_muxer封装H.264裸流的时候丢失声音的错误

CSDN下载地址:

http://download.csdn.net/detail/leixiaohua1020/8284309

更新-1.2 (2015.2.13)=========================================

这次考虑到了跨平台的要求,调整了源代码。经过这次调整之后,源代码可以在以下平台编译通过:

VC++:打开sln文件即可编译,无需配置。

cl.exe:打开compile_cl.bat即可命令行下使用cl.exe进行编译,注意可能需要按照VC的安装路径调整脚本里面的参数。编译命令如下。

[plain] view plain copy
  1. ::VS2010 Environment
  2. call "D:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
  3. ::include
  4. @set INCLUDE=include;%INCLUDE%
  5. ::lib
  6. @set LIB=lib;%LIB%
  7. ::compile and link
  8. cl simplest_ffmpeg_remuxer.cpp /link avcodec.lib avformat.lib avutil.lib ^
  9. avdevice.lib avfilter.lib postproc.lib swresample.lib swscale.lib /OPT:NOREF

MinGW:MinGW命令行下运行compile_mingw.sh即可使用MinGW的g++进行编译。编译命令如下。

[plain] view plain copy
  1. g++ simplest_ffmpeg_remuxer.cpp -g -o simplest_ffmpeg_remuxer.exe \
  2. -I /usr/local/include -L /usr/local/lib -lavformat -lavcodec -lavutil

GCC:Linux或者MacOS命令行下运行compile_gcc.sh即可使用GCC进行编译。编译命令如下。

[plain] view plain copy
  1. gcc simplest_ffmpeg_remuxer.cpp -g -o simplest_ffmpeg_remuxer.out -I /usr/local/include -L /usr/local/lib \
  2. -lavformat -lavcodec -lavutil

PS:相关的编译命令已经保存到了工程文件夹中

CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/8445303

SourceForge上已经更新。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leixiaohua1020/article/details/25422685
文章标签: ffmpeg 封装格式 转换 转码
个人分类: FFMPEG 我的开源项目
所属专栏: FFmpeg
  • wonder_q 2018-03-02 09:36:54 #37楼
    怀念大神

  • FanTasyCC 2018-01-24 17:49:55 #36楼
    一路走好

  • yinqigui2823 2017-11-16 14:16:57 #35楼
    一路走好

  • royson520 2017-11-16 10:17:18 #34楼
    谢谢资料,愿一路走好

  • Leo-007 2017-05-15 18:09:54 #33楼
    一路走好

ffmpeg h264转avi

将h264转换到avi格式:ffmpeg -i input.264 -s 640x480 output.avi-s : 为重新设置分辨率-r  : 为帧率设置...

t1234xy4

2016-06-13 10:47:35

阅读数:398

使用ffmpeg开源库将h264封装为mp4格式

近一直在做使用ffmpeg关于读取标准h264格式内存如何封装为mp4格式文件,在经过一周的持续奋战之后在网上找了一些代码,特别的雷神的博客让我获益匪浅,开始不知道如何持续读取发送来的内存块,如何边...

huangyifei_1111

2015-07-19 15:11:58

阅读数:5350

视频格式转换ffmpeg的使用 - CSDN博客

由于需要在各种平台有播放视频的需要,我们经常需要将视频转化成各种各样的格式,网上类似的工具很多但这些工具都是基于ffmpeg开发的,我们下面简单的用一个python程序来...

2018-4-17

FFMpeg 常用命令格式转换,视频合成 - CSDN博客

举报内容: FFMpeg 常用命令格式转换,视频合成 举报原因: 色情 政治 抄袭 广告 招聘 骂人 其他 原文地址: 原因补充: 最多只允许输入30个字加入...

2018-5-2

广告

ffmpeg h264实时流如何录像成Avi

h264一帧一帧的数据如何 赋值给av_interleaved_write_frame 函数进行写文件呢?

smilestone322

2014-01-04 16:56:55

阅读数:4109

ffmpeg视频格式转换 - CSDN博客

最近下了点小视频,上传到百度网盘上被识别了md5重复后秒传了,然后就和谐了,于是想着把视频转换格式重新上传到隐藏空间。先建个文件夹,把视频文件,newfiles文件...

2018-5-9

ffmpeg视频格式转换

ffmpeg,视频格式转换,Linux下FFmpeg编译,支持大部分主流视频编码格式... ffmpeg,视频格式转换,Linux下FFmpeg编译,支持大部分主流视频编码格式 综合评分:4 收藏评论(7)举...

2018-5-7

H264 数据avi文件封装和拆解

为了提高H264的保存效率,抛弃了FFmpeg库的avi封装,直接才源码的方式封装avi文件,源码来源于网络,经改造回馈网络。废话不多说,直接上干货。...

zhujinghao09

2015-03-19 15:27:39

阅读数:4246

音视频(H264+G711)打包AVI文件

1.简单分析avi格式使用ultraedit打开Avi文件,二进制显示如下: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 012345678901234...

edw200

2016-08-11 09:14:37

阅读数:2836

windows下利用ffmpeg进行视频格式转换 - CSDN博客

windows下利用ffmpeg进行视频格式转换原创 2016年05月04日 00:30:10 标签: 2518 编辑 删除 本文写作时只是直接下载了已经编译好的ffmpeg.exe来进行相关操作,没有...

2018-4-5

Java 调用FFMPEG命令进行视频格式转换 (windows环境)

} /** * 视频转换 * @param video_path * @return */ public static String convertCommand(String video_path,String videoFileName) { //D:/ffmpeg.exe ...

2017-6-20

ffmpeg封装H264成MP4、AVI视频格式,及提取出png、jpg格式图片

2017年08月15日 19.75MB下载

同事月薪三千却开豪车,原来他能这样赚钱 大集网络科技 · 顶新

FFmpeg格式转换

FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。

2018-5-9

ffmpeg 视频格式转换 - CSDN博客

在进行图形图像分析的时候,我们往往需要把视频转换为yuv 格式或者单通道灰度图像,ffmpeg 就显得很方便了 以下我将示范几个用法用法1. mp4 转换为 gray ,单通道的...

2017-12-3

FLV视频直播系统-----利用ffmpeg+ffserver搭建最简单的FLV视频直播系统(ubuntu)

FFmpeg FLV 视频直播 ffserver flv ffmpegffplay

CSSEIKOCS

2016-01-27 18:06:54

阅读数:3736

ffmpeg转换flv至mpeg

原贴:http://linuxdesktop.cn/2007/07/25/ffmpeg-convert-flv-to-mpeg 用ffmpeg转换flv至mpeg 2007-07-25 13:50 |...

chinalinuxzend

2007-10-17 00:51:00

阅读数:8078

FFMPEG封装格式转换(remuxer) - CSDN博客

本文主要分析通过FFMPEG函数将音视频容器格式转换成另一种格式。在转换中涉及到h264_mp4toannexb的转换,本文会针对此种情况重点说明下,先上带解析的源代码。

2018-4-17

undefined

记录一下,金山云基于ffmpeg支持hevc flv的支持patch

如题,具体如下https://github.com/ksvc/FFmpeg/wiki/instructionshttps://github.com/ksvc/FFmpeg/wiki...

defence006

2017-06-19 19:00:22

阅读数:660

使用ffmpeg进行视频文件转换成FLV整理

本系列文章导航Windows下FFmpeg快速入门ffmpeg参数解释mencoder和ffmpeg参数详解(Java处理视频)Java 生成视频缩略图(ffmpeg)使用ffmpeg进行视频文件转换...

hemingwang0902

2009-07-26 22:23:00

阅读数:11151

安装和使用ffmpeg转换视频为flv文件(windows和linux)

1、环境winxp-sp2下:从 http://ffdshow.faireal.net/mirror/ffmpeg/ 下载新版本的 FFMpeg.exe直接用就行(须rar解压)。 以下的东西是为对...

TomyGuan

2007-08-14 09:06:00

阅读数:3156

ffmpeg flv直播发送的一点感悟

时间戳一定要对。如果各个流数据都在同时生成,就用 av_interleaved_write_frame如果各个流的数据 有时有 有时没有,就用 av_write_frame原因是 ,av_...

lanxiaziyi

2016-12-31 16:03:13

阅读数:410

flv封装ffmpeg编码的视音频笔记(一)

宏观上看,FLV包括文件头(FileHeader)和文件体(File Body)两部分。文件体由一系列的标签组成,标签又可以分成三类:音频标签、视频标签、脚本标签,且每个标签只能包含一种类型的数据。...

Enmenglian

2016-03-21 13:59:15

阅读数:1108

使用ffmpeg转换文件格式,及ffmpeg参数说明

转换文件test.avi到test.flvffmpeg -i test.avi -ab 56 -ar 22050 -b 500 -r 29.97 -s 320x240 test.flv对文件抓缩微图:...

sunbingzibo

2007-06-12 14:35:00

阅读数:25696

视频格式转换之ffmpeg的使用

由于需要在各种平台有播放视频的需要,我们经常需要将视频转化成各种各样的格式,网上类似的工具很多但这些工具都是基于ffmpeg开发的,我们下面简单的用一个python程序来调用ffmpeg.exe来实现...

qq_21400315

2016-12-09 15:48:24

阅读数:1818

ffmpeg 视频格式转换和宽高转换 制作自己想要的数据格式

命令如下: ffmpeg -y -i Titanic.mkv -s 640*480 out.h264 运行效果: 一般的 使用 ffmpeg -y -i 原材料视频 -s 宽*高 输出的目的视...

u011046042

2017-03-16 19:55:30

阅读数:3345

ffmpeg到opencv的格式转换

首先通过ffmpeg的sws_scale函数可以将原视频格式转换为YUV格式,保存在AVPicture结构体里,而AVPicture结构体里的data成员即储存着视频数据,下面通过一段代码就可以将YU...

guozhihao12345

2015-12-23 17:42:34

阅读数:739

ffmpeg 常用命令行 (视频->转码)

http://blog.csdn.net/lius1984/article/details/4367150 整理常用的ffmpeg命令,便于大家查找。 1. AVI转FLV  ...

wenzhihui_2010

2014-09-22 11:52:24

阅读数:12230

最简单的基于FFMPEG的封装格式转换器相关推荐

  1. 最简单的基于FFMPEG的封装格式转换器(无编解码)

    2019独角兽企业重金招聘Python工程师标准>>> 本文介绍一个基于FFMPEG的封装格式转换器.所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(对应. ...

  2. 最简单的基于FFMPEG的封装格式转换器(C++Qt 版)

    最简单的基于FFMPEG的封装格式转换器(C++Qt 版) 这篇博客是我上篇博客的延续.建议大家先看看我上篇博客: https://blog.csdn.net/liyuanbhu/article/de ...

  3. 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  4. 最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  5. 基于FFMPEG的封装格式转换器

    简介 本文介绍一个基于FFMPEG的封装格式转换器.所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(对应.avi,.flv,.mkv,.mp4文件).需要注意的是,本程序并不 ...

  6. 基于FFmpeg的封装格式MP4(TS)

    一. 封装MP4原理: 每一帧音频或视频都有一个持续时间:duration: 采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数. .正常人听觉的频率范围大约在20Hz~20kHz之 ...

  7. 【开源项目】基于FFmpeg的封装格式转换

    /* * 一笑奈何 * cn-yixiaonaihe.blog.csdn.net */#include <iostream> #include <thread> extern ...

  8. 最简单的基于FFMPEG 4.2的封装格式转换器(无编解码MP4转FLV)

    文章目录 最简单的基于FFMPEG 4.2的封装格式转换器(无编解码) 配置 代码 结果 关键函数说明 avformat_open_input avformat_find_stream_info av ...

  9. 最简单的基于FFmpeg的推流器(以推送RTMP为例)

    ===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...

最新文章

  1. 使用NLTK进行英文分词
  2. 外网访问XAMPP失败 解决方案
  3. kali 设置中文字体
  4. 【渝粤题库】陕西师范大学163204 旅游规划学
  5. wsadata wsadata;为什么不通过_注册公司之公司名称核准,知道为什么你的核名一直不通过吗?...
  6. 百度定位---适配8.0限制后台定位
  7. 网页视频之H5+Mse
  8. SQL server 2008 T-sql 总结
  9. 树莓派安装rtl8192eu无线网卡驱动
  10. 信息安全概论复习笔记
  11. font-style字体设置
  12. 计算机技术专业求职简历,计算机技术专业求职简历模板
  13. 如何在高通平台新建项目
  14. win10服务器显示图标,Win10专业版桌面图标消失的三种情况及相应解决方法
  15. 信创项目基础软件都包括哪些?你要了解
  16. Task2 数据分析 (1)
  17. layui快速上手教程
  18. procast2021学习笔记
  19. 斯坦福大学(吴恩达) 机器学习课后习题详解 第三周 正则化
  20. 第一个OpenDayLight项目:HelloWorld

热门文章

  1. mysql日期函数TO_DAYS()函数
  2. Ubuntu: 查看图像像素坐标
  3. 关于《半小时漫画经济学》
  4. ssh 远程连接方式总结
  5. Table ‘ecology.e9_para_group_concat_max_len‘ doesn‘t exist
  6. css水平居中:使用absolute+transform
  7. shell mysql中单引号_Shell脚本中单引号(‘)和双引号(“)的使用区别
  8. 向超级中央计算机迈进--智能汽车电子构架变革迎接数字化重塑...
  9. 为什么企业需要社会化媒体营销?
  10. 「大话设计模式 - 解读」5 大作业