C# 版 flvmerge:快速合并多个flv文件

系统 1705 0

C# 版 flvmerge:快速合并多个flv文件

 

网上的视频很多都是分片的 flv 文件,怎么把他们合为一体呢? GUI 工具就不考虑了,不适合批量执行,不适合在后台运行。有没有命令行工具或库可以实现呢?

ffmpeg   提供了一个方法:

(1)先把 flv 文件转换成 mpeg

(2)将多个 mpeg 文件合并成 1 个独立的 mpeg 文件(二进制合并即可)

(3)将独立的 mpeg 文件转换成独立的 flv 文件。

 网上搜到的最多的也是这种解决办法。这种方法有两个缺点:

(1)需要两遍转码,非常耗时;

(2)转换后的独立的 mpeg 文件比原视频要短一点点。

 木有办法了,只好另寻他路。有人说有一个 flvmerge.exe  程序可以将多个 flv 合并成一个,可惜的是俺搜了很久,都没找到这个程序,最后还是在一款免费软件里把这个“ flvmerge.exe ”文件给揪出来了,不幸的是,这个“ flvmerge.exe ”得不到正确的结果。

润之同学说过,自己动手,丰衣足食。上  github  上搜“ flvmerge ”,发现两个项目,“ flvmerge ”和“ flvmerger ”,都是 C 写的。前者不依赖于第三方库,后者依赖于第三方库,那么就从第一个开始吧。

看了看它的代码,知道了 flv 文件合并的原理:

(1) flv  文件由 1 header 和若干个 tag 组成;

(2) header 记录了视频的元数据;

(3) tag  是有时间戳的数据;

(4) flv 合并的原理就是把多个文件里的 tag 组装起来,调整各 tag 的时间戳,再在文件起始处按个头部。

下面是我参照  flvmerge  项目,用 linqpad 写的一个 C# 版本的  flvmerge  代码:

 

          
              1
          
          
            void
          
          
             Main()


          
          
              2
          
          
            {


          
          
              3
          
               String path1 = 
          
            "
          
          
            D:\\Videos\\Subtitle\\OutputCache\\1.flv
          
          
            "
          
          
            ;


          
          
              4
          
               String path2 = 
          
            "
          
          
            D:\\Videos\\Subtitle\\OutputCache\\2.flv
          
          
            "
          
          
            ;


          
          
              5
          
               String path3 = 
          
            "
          
          
            D:\\Videos\\Subtitle\\OutputCache\\3.flv
          
          
            "
          
          
            ;


          
          
              6
          
               String output = 
          
            "
          
          
            D:\\Videos\\Subtitle\\OutputCache\\output.flv
          
          
            "
          
          
            ;


          
          
              7
          
          
              8
          
          
            using
          
          (FileStream fs1 = 
          
            new
          
          
             FileStream(path1, FileMode.Open))


          
          
              9
          
          
            using
          
          (FileStream fs2 = 
          
            new
          
          
             FileStream(path2, FileMode.Open))


          
          
             10
          
          
            using
          
          (FileStream fs3 = 
          
            new
          
          
             FileStream(path3, FileMode.Open))


          
          
             11
          
          
            using
          
          (FileStream fsMerge = 
          
            new
          
          
             FileStream(output, FileMode.Create))


          
          
             12
          
          
                {


          
          
             13
          
          
                    Console.WriteLine(IsFLVFile(fs1));


          
          
             14
          
          
                    Console.WriteLine(IsFLVFile(fs2));


          
          
             15
          
          
                    Console.WriteLine(IsFLVFile(fs3));


          
          
             16
          
          
             17
          
          
            if
          
          (IsSuitableToMerge(GetFLVFileInfo(fs1),GetFLVFileInfo(fs2)) == 
          
            false
          
          
             18
          
                       || IsSuitableToMerge(GetFLVFileInfo(fs1),GetFLVFileInfo(fs3)) == 
          
            false
          
          
            )


          
          
             19
          
          
                    {


          
          
             20
          
                       Console.WriteLine(
          
            "
          
          
            Video files not suitable to merge
          
          
            "
          
          
            );


          
          
             21
          
          
                    }


          
          
             22
          
          
             23
          
          
            int
          
           time = Merge(fs1,fsMerge,
          
            true
          
          ,
          
            0
          
          
            );


          
          
             24
          
                   time =  Merge(fs2,fsMerge,
          
            false
          
          
            ,time);


          
          
             25
          
                   time =  Merge(fs3,fsMerge,
          
            false
          
          
            ,time);


          
          
             26
          
                   Console.WriteLine(
          
            "
          
          
            Merge finished
          
          
            "
          
          
            );


          
          
             27
          
          
                }


          
          
             28
          
          
            }


          
          
             29
          
          
             30
          
          
            const
          
          
            int
          
           FLV_HEADER_SIZE = 
          
            9
          
          
            ;


          
          
             31
          
          
            const
          
          
            int
          
           FLV_TAG_HEADER_SIZE = 
          
            11
          
          
            ;


          
          
             32
          
          
            const
          
          
            int
          
           MAX_DATA_SIZE = 
          
            16777220
          
          
            ;


          
          
             33
          
          
             34
          
          
            class
          
          
             FLVContext


          
          
             35
          
          
            {


          
          
             36
          
          
            public
          
          
            byte
          
          
             soundFormat;


          
          
             37
          
          
            public
          
          
            byte
          
          
             soundRate;


          
          
             38
          
          
            public
          
          
            byte
          
          
             soundSize;


          
          
             39
          
          
            public
          
          
            byte
          
          
             soundType;


          
          
             40
          
          
            public
          
          
            byte
          
          
             videoCodecID;


          
          
             41
          
          
            }


          
          
             42
          
          
             43
          
          
            bool
          
          
             IsSuitableToMerge(FLVContext flvCtx1, FLVContext flvCtx2)


          
          
             44
          
          
            {


          
          
             45
          
          
            return
          
           (flvCtx1.soundFormat == flvCtx2.soundFormat) &&


          
             46
          
                 (flvCtx1.soundRate == flvCtx2.soundRate) &&


          
             47
          
                 (flvCtx1.soundSize == flvCtx2.soundSize) &&


          
             48
          
                 (flvCtx1.soundType == flvCtx2.soundType) &&


          
             49
          
                 (flvCtx1.videoCodecID ==
          
             flvCtx2.videoCodecID);


          
          
             50
          
          
            }


          
          
             51
          
          
             52
          
          
            bool
          
          
             IsFLVFile(FileStream fs)


          
          
             53
          
          
            {


          
          
             54
          
          
            int
          
          
             len;


          
          
             55
          
          
            byte
          
          [] buf = 
          
            new
          
          
            byte
          
          
            [FLV_HEADER_SIZE];


          
          
             56
          
               fs.Position = 
          
            0
          
          
            ;


          
          
             57
          
          
            if
          
          ( FLV_HEADER_SIZE != fs.Read(buf,
          
            0
          
          
            ,buf.Length))


          
          
             58
          
          
            return
          
          
            false
          
          
            ;


          
          
             59
          
          
             60
          
          
            if
          
           (buf[
          
            0
          
          ] != 
          
            '
          
          
            F
          
          
            '
          
           || buf[
          
            1
          
          ] != 
          
            '
          
          
            L
          
          
            '
          
           || buf[
          
            2
          
          ] != 
          
            '
          
          
            V
          
          
            '
          
           || buf[
          
            3
          
          ] != 
          
            0x01
          
          
            )


          
          
             61
          
          
            return
          
          
            false
          
          
            ;


          
          
             62
          
          
            else
          
          
             63
          
          
            return
          
          
            true
          
          
            ;


          
          
             64
          
          
            }


          
          
             65
          
          
             66
          
          
            FLVContext GetFLVFileInfo(FileStream fs)


          
          
             67
          
          
            {


          
          
             68
          
          
            bool
          
          
             hasAudioParams, hasVideoParams;


          
          
             69
          
          
            int
          
          
             skipSize, readLen;


          
          
             70
          
          
            int
          
          
             dataSize;


          
          
             71
          
          
            byte
          
          
             tagType;


          
          
             72
          
          
            byte
          
          [] tmp = 
          
            new
          
          
            byte
          
          [FLV_TAG_HEADER_SIZE+
          
            1
          
          
            ];


          
          
             73
          
          
            if
          
           (fs == 
          
            null
          
          ) 
          
            return
          
          
            null
          
          
            ;


          
          
             74
          
          
             75
          
               FLVContext flvCtx = 
          
            new
          
          
             FLVContext();


          
          
             76
          
               fs.Position = 
          
            0
          
          
            ;


          
          
             77
          
               skipSize = 
          
            9
          
          
            ;


          
          
             78
          
               fs.Position +=
          
             skipSize;


          
          
             79
          
               hasVideoParams = hasAudioParams = 
          
            false
          
          
            ;


          
          
             80
          
               skipSize = 
          
            4
          
          
            ;


          
          
             81
          
          
            while
          
           (!hasVideoParams || !
          
            hasAudioParams)


          
          
             82
          
          
                {


          
          
             83
          
                   fs.Position +=
          
             skipSize;


          
          
             84
          
          
             85
          
          
            if
          
           (FLV_TAG_HEADER_SIZE+
          
            1
          
           != fs.Read(tmp,
          
            0
          
          
            ,tmp.Length))


          
          
             86
          
          
            return
          
          
            null
          
          
            ;


          
          
             87
          
          
             88
          
                   tagType = (
          
            byte
          
          )(tmp[
          
            0
          
          ] & 
          
            0x1f
          
          
            );


          
          
             89
          
          
            switch
          
          
             (tagType)


          
          
             90
          
          
                    {


          
          
             91
          
          
            case
          
          
            8
          
          
             :


          
          
             92
          
                       flvCtx.soundFormat = (
          
            byte
          
          )((tmp[FLV_TAG_HEADER_SIZE] & 
          
            0xf0
          
          ) >> 
          
            4
          
          
            ) ;


          
          
             93
          
                       flvCtx.soundRate   = (
          
            byte
          
          )((tmp[FLV_TAG_HEADER_SIZE] & 
          
            0x0c
          
          ) >> 
          
            2
          
          
            ) ;


          
          
             94
          
                       flvCtx.soundSize   = (
          
            byte
          
          )((tmp[FLV_TAG_HEADER_SIZE] & 
          
            0x02
          
          ) >> 
          
            1
          
          
            ) ;


          
          
             95
          
                       flvCtx.soundType   = (
          
            byte
          
          )((tmp[FLV_TAG_HEADER_SIZE] & 
          
            0x01
          
          ) >> 
          
            0
          
          
            ) ;


          
          
             96
          
                       hasAudioParams = 
          
            true
          
          
            ;


          
          
             97
          
          
            break
          
          
            ;


          
          
             98
          
          
            case
          
          
            9
          
          
             :


          
          
             99
          
                       flvCtx.videoCodecID = (
          
            byte
          
          )((tmp[FLV_TAG_HEADER_SIZE] & 
          
            0x0f
          
          
            ));


          
          
            100
          
                       hasVideoParams = 
          
            true
          
          
            ;


          
          
            101
          
          
            break
          
          
            ;


          
          
            102
          
          
            default
          
          
             :


          
          
            103
          
          
            break
          
          
            ;


          
          
            104
          
          
                    }


          
          
            105
          
          
            106
          
                   dataSize = FromInt24StringBe(tmp[
          
            1
          
          ],tmp[
          
            2
          
          ],tmp[
          
            3
          
          
            ]);


          
          
            107
          
                   skipSize = dataSize - 
          
            1
          
           + 
          
            4
          
          
            ;


          
          
            108
          
          
                }


          
          
            109
          
          
            110
          
          
            return
          
          
             flvCtx;


          
          
            111
          
          
            }


          
          
            112
          
          
            113
          
          
            int
          
           FromInt24StringBe(
          
            byte
          
           b0, 
          
            byte
          
           b1, 
          
            byte
          
          
             b2)


          
          
            114
          
          
            {


          
          
            115
          
          
            return
          
           (
          
            int
          
          )((b0<<
          
            16
          
          ) | (b1<<
          
            8
          
          ) |
          
             (b2));


          
          
            116
          
          
            }


          
          
            117
          
          
            118
          
          
            int
          
           GetTimestamp(
          
            byte
          
           b0, 
          
            byte
          
           b1, 
          
            byte
          
           b2, 
          
            byte
          
          
             b3)


          
          
            119
          
          
            {


          
          
            120
          
          
            return
          
           ((b3<<
          
            24
          
          ) | (b0<<
          
            16
          
          ) | (b1<<
          
            8
          
          ) |
          
                (b2));


          
          
            121
          
          
            }


          
          
            122
          
          
            123
          
          
            void
          
           SetTimestamp(
          
            byte
          
          [] data, 
          
            int
          
           idx, 
          
            int
          
          
             newTimestamp)


          
          
            124
          
          
            {


          
          
            125
          
               data[idx + 
          
            3
          
          ] = (
          
            byte
          
          )(newTimestamp>>
          
            24
          
          
            );


          
          
            126
          
               data[idx + 
          
            0
          
          ] = (
          
            byte
          
          )(newTimestamp>>
          
            16
          
          
            );


          
          
            127
          
               data[idx + 
          
            1
          
          ] = (
          
            byte
          
          )(newTimestamp>>
          
            8
          
          
            );


          
          
            128
          
               data[idx + 
          
            2
          
          ] = (
          
            byte
          
          
            )(newTimestamp);


          
          
            129
          
          
            }


          
          
            130
          
          
            131
          
          
            int
          
           Merge(FileStream fsInput, FileStream fsMerge, 
          
            bool
          
           isFirstFile, 
          
            int
          
           lastTimestamp = 
          
            0
          
          
            )


          
          
            132
          
          
            {


          
          
            133
          
          
            int
          
          
             readLen;


          
          
            134
          
          
            int
          
           curTimestamp  = 
          
            0
          
          
            ;


          
          
            135
          
          
            int
          
           newTimestamp = 
          
            0
          
          
            ;


          
          
            136
          
          
            int
          
          
             dataSize;


          
          
            137
          
          
            byte
          
          [] tmp = 
          
            new
          
          
            byte
          
          [
          
            20
          
          
            ];


          
          
            138
          
          
            byte
          
          [] buf = 
          
            new
          
          
            byte
          
          
            [MAX_DATA_SIZE];


          
          
            139
          
          
            140
          
               fsInput.Position = 
          
            0
          
          
            ;


          
          
            141
          
          
            if
          
          
             (isFirstFile)


          
          
            142
          
          
                {


          
          
            143
          
          
            if
          
          (FLV_HEADER_SIZE+
          
            4
          
           == (fsInput.Read(tmp,
          
            0
          
          ,FLV_HEADER_SIZE+
          
            4
          
          
            )))


          
          
            144
          
          
                    {


          
          
            145
          
                       fsMerge.Position = 
          
            0
          
          
            ;


          
          
            146
          
                       fsMerge.Write(tmp,
          
            0
          
          ,FLV_HEADER_SIZE+
          
            4
          
          
            );


          
          
            147
          
          
                    }


          
          
            148
          
          
                }


          
          
            149
          
          
            else
          
          
            150
          
          
                {


          
          
            151
          
                   fsInput.Position = FLV_HEADER_SIZE + 
          
            4
          
          
            ;


          
          
            152
          
          
                }


          
          
            153
          
          
            154
          
          
            while
          
          (fsInput.Read(tmp, 
          
            0
          
          , FLV_TAG_HEADER_SIZE) > 
          
            0
          
          
            )


          
          
            155
          
          
                {


          
          
            156
          
                    dataSize = FromInt24StringBe(tmp[
          
            1
          
          ],tmp[
          
            2
          
          ],tmp[
          
            3
          
          
            ]);


          
          
            157
          
                    curTimestamp = GetTimestamp(tmp[
          
            4
          
          ],tmp[
          
            5
          
          ],tmp[
          
            6
          
          ],tmp[
          
            7
          
          
            ]);


          
          
            158
          
                    newTimestamp = curTimestamp +
          
             lastTimestamp;


          
          
            159
          
                    SetTimestamp(tmp,
          
            4
          
          
            , newTimestamp);


          
          
            160
          
                    fsMerge.Write(tmp,
          
            0
          
          
            ,FLV_TAG_HEADER_SIZE);


          
          
            161
          
          
            162
          
                    readLen = dataSize+
          
            4
          
          
            ;


          
          
            163
          
          
            if
          
           (fsInput.Read(buf,
          
            0
          
          ,readLen) > 
          
            0
          
          
            ) {


          
          
            164
          
                           fsMerge.Write(buf, 
          
            0
          
          
            , readLen);


          
          
            165
          
                       } 
          
            else
          
          
             {


          
          
            166
          
          
            goto
          
          
             failed;


          
          
            167
          
          
                    }


          
          
            168
          
          
                }


          
          
            169
          
          
            170
          
          
            return
          
          
             newTimestamp;


          
          
            171
          
          
            172
          
          
                failed:


          
          
            173
          
          
            throw
          
          
            new
          
           Exception(
          
            "
          
          
            Merge Failed
          
          
            "
          
          
            );


          
          
            174
          
           }
        

 

测试通过,合并速度很快 !

 

不过,这个方法有一个缺点:没有将各个文件里的关键帧信息合并,这个关键帧信息,切分 flv 文件时很重要,合并时就没那么重要了。如果确实需要的话,可以用  flvtool2 来处理。

 

C# 版 flvmerge:快速合并多个flv文件


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论