这是我尝试下载一段 4 分钟的视频的第三天。这是一个 Flash FLV,分为三部分,前两部分约 5MB,第三部分约 3MB。
只有第一部分有正常的 FLV 标头,接下来的两部分开头大多只有一个 FLV。我没有尝试自己编写一些东西,只是下载并尝试了几百兆的垃圾 Windows 软件,但实际上并没有这样做。
事实证明,无需下载视频部分,播放完一次后即可将其从浏览器缓存中取出。我曾尝试使用 CamStudio 从屏幕上捕捉正在播放的视频,但我最快的电脑速度不够快。
我无法实时执行此操作。我想从 OpenBSD 执行此操作,但我有一台机器启动到 Windows,因为 OpenBSD 没有 Flash。我可以用 MPlayer(Windows 或 OpenBSD)播放它,尝试使用 MEncoder 对各部分进行简单的连接会产生在第一次分割处停止的视频。也试过 FFmpeg。我想将其转换为更普通的格式,例如 MP4 或 AVI。
10.1 规范与 10.0 有很大不同(PDF 热链接)
MC viewer 中的三个 FLV(图片);第一个完全不同:
答案1
虽然还没有完整的答案,但 FLVMeta 和对 Adobe 规范的部分解读开始揭示一些问题。从 FLVMeta 完整转储来看,标签或数据部分如下所示:
--- Tag #1019 at 0xCBEB5 (835253) ---
Tag type: audio
Body length: 213
Timestamp: 124957
* Sound type: stereo
* Sound size: 16
* Sound rate: 44
* Sound format: AAC
Previous tag size: 224
--- Tag #1020 at 0xCBF99 (835481) ---
Tag type: video
Body length: 1201
Timestamp: 124960
* Video codec: AVC
* Video frame type: inter frame
Previous tag size: 1212
--- Tag #1021 at 0xCC459 (836697) ---
Tag type: audio
Body length: 225
Timestamp: 124980
* Sound type: stereo
* Sound size: 16
* Sound rate: 44
* Sound format: AAC
Previous tag size: 236
--- Tag #1022 at 0xCC549 (836937) ---
Tag type: video
Body length: 542
Timestamp: 125000
* Video codec: AVC
* Video frame type: inter frame
Previous tag size: 553
因此,您可以将标头读入一个文件,将所有标签分别放入 1 个文件中,然后将任意数量的输入文件重建为任意数量的输出文件。我将每个“标签”称为一个块,但它是一块数据。您不必实时操作它们。每个标签都有一个时间戳,您只需按该顺序将它们放在一起,不要将标签拆分到多个文件中。
我希望 FLVMeta 有更多有用的输出,以便在程序控制下移动制表符或逗号分隔的数据等内容。甚至可以为每个项目创建一个 SQLite 数据库,将所有音频标签放在一个表中,将视频放在另一个表中,将脚本放在另一个表中。也许我会这样做,因为它是开源的,而且在 Github 上。如果 flvs 不是大端的,而我在一台小端的机器上,那就更简单了。所有整数都是大端的,就像在 Mac 上一样。
答案2
终于完成了。我解决了第一个输入文件的 EOF 在输出文件中最终变成 FF 或 -1 的错误,从而停止了播放器和转换器,最后我使用我编写的 C 程序将它们连接起来。
flvmeta 仍然对此输出发出警告,但我能够使用以下命令将其转换为 mp4:
ffmpeg -i out4.flv -vcodec copy -acodec copy out4.mp4
/*
My flv concat, a single-use program
*/
#include <stdio.h> // don't need most of these headers
#include <stdlib.h>
#include <string.h>
#include <endian.h> // FLVs have big endian values
#include <unistd.h>
#include <fcntl.h>
#include <inttypes.h>
FILE *opf;
void docopy(char *fn, uint ofs) {
FILE *ipf;
unsigned char ch;
ipf = fopen(fn,"r");
if (ipf == NULL) {
printf("Failed to open %s\n",fn);
fclose(opf);
exit(1);
}
fseek(ipf,ofs,SEEK_SET); // jump to passed in offset
while (!feof(ipf)) { // not super efficient
ch = fgetc(ipf);
// this DOES have an effect, it stops the -1 from being written
if (!feof(ipf))
fputc(ch,opf);
}
printf("outfile now at %x\n",(unsigned int) ftell(opf));
fclose(ipf);
}
void outhdr(void) { // write boilerplate flv header
opf = fopen("out4.flv","w");
if (opf == NULL) {
printf("Error creating new output file.\n");
exit(1);
}
fprintf(opf,"FLV%c%c%c%c%c%c",1,5,0,0,0,9); // audio and video enabled
// This becomes the first PreviousTagSize:
fprintf(opf,"%c%c%c%c",0,0,0,0); // flvmeta seems to approve
}
int main(void) {
outhdr(); // write a vanilla header
docopy("media1.flv", 13); // copy, starting at byte 13
docopy("media2.flv", 13);
docopy("media3.flv", 13);
fclose(opf);
return 0;
}