How to join split flv files?

0

I'm in my 3rd day of trying to download one 4-minute video. It's a Flash FLV that's split into three parts, the first two are about 5MB, the third about 3MB.

Only the first part has normal FLV headers, the next two have mostly just an FLV at the start. I haven't resorted to trying to write something myself, just downloaded and tried a couple hundred megs of junky Windows software that doesn't actually do it.

As it turns out there's no need to download the video parts, you can pull them out of your browser's cache once you've played it through once. I've tried CamStudio to capture the video from the screen as it's being played, but my fastest computer isn't fast enough.

I can't do this realtime. I'd like to be doing this from OpenBSD but I've got one machine booted into Windows because there's no Flash for OpenBSD. I can play it with MPlayer (Windows or OpenBSD), trying to do a simple join of the parts using MEncoder yields a video that stops at the first split. Tried FFmpeg, too. I'd like to convert it to anything more normal, like MP4 or AVI.

The 10.1 spec looks a lot different from 10.0 (hotlink to PDF)

The three FLVs in MC viewer (picture); the first is quite different:

link

Alan Corey

Posted 2016-03-22T15:40:04.437

Reputation: 9

Have you checked to see if it's literally not one file in 3 chunks? Like with cat chuck1 chuck2 chunk3 > file.flv – infixed – 2016-03-22T15:46:19.533

btw, ffmpeg can take a .flv video as a container format. When I was transcoding for a crap netbook without good h264 support (but OK mpeg2 support), I used to use things like ffmpeg -i input.flv -acodec libmp3lame -vcodec mpeg2video -qscale 5 -y out.mkv – infixed – 2016-03-22T15:51:52.123

Yes, cat was about the first thing I tried but it's not a simple split. If I look at the files with the viewer in mc, each part has fields like video_format, start_time, video_codec. Which I think are the viewer interpreting them because I don't see this in the raw bytes of the file. But only the first part is acceptable to mplayer,etc as an flv and plays. – Alan Corey – 2016-03-22T16:04:22.140

I've used mencoder more than ffmpeg. Interesting about the container. I think if I try to write something I need to maybe parse the first header and pass it along then probably copy the payloads and concatenate them. In each header is a start time and I think a duration so I can get them in the right order and not rely on external file dates. – Alan Corey – 2016-03-22T16:50:38.493

I've used ffmpeg to join files with different codecs even before. try something like ffmpeg -i file1.flv -i file2.flv -i file3.flv -filter_complex concat=n=3:v=1:a=1 -acodec libmp3lame -vcodec mpeg2video -qscale 5 -y out.mkv Sorry I can't test to see if that's completely right – infixed – 2016-03-22T16:51:35.557

I get "stream discovered after head already parsed", then it sees an h264 video and aac audio – Alan Corey – 2016-03-22T17:43:39.037

I get "stream discovered after head already parsed", then it sees an h264 video and aac audio stream. Then "missing picture", "no frame", etc. But it finds the streams in all 3 files, I see framerates, h264/aac codecs. Says I should increase analyzeduration and probesize but those aren't in the man page. – Alan Corey – 2016-03-22T17:49:46.710

Tried up to probesize 20000 and analyzeduration 5000000 after Googling. Still missing picture then "error configuring filters" at the end. – Alan Corey – 2016-03-22T17:59:08.273

https://ffmpeg.org/pipermail/ffmpeg-user/2013-March/014297.html seems to discuss those. – infixed – 2016-03-22T17:59:54.193

try using ffmpeg to convert the .flv files to .ts files. Transport stream muxing is supposed to allow you to combine fragments by concating. Unless it starts complaining about timestamps. I think that maybe problematic – infixed – 2016-03-22T18:03:36.167

Dumping to stream doesn't work because it only opens the first file correctly, tried that with mencoder too. I had my probesize and analyzeduration at almost the whole file size. Put a big messy log at http://devio.us/~ab1jx/log4a.txt

– Alan Corey – 2016-03-22T19:12:08.740

unfortunately I am at a place where looking very odd places on the net gets flagged. I was hoping that when you said "it finds streams in all files" that it could extract each stream in isolation. If transcoded to TS, then you should be able to simply cat the files. But not much more I can do for you now – infixed – 2016-03-22T19:17:57.120

devio's just a free shell account hosted on an OpenBSD machine , maybe they're odd. Looking at the contents of the flv files in mc's viewer, the first one is very different: there's actually readable text in there. Words like copyleft, deadzone, decimate, constrained anyway. Not in the later files, only the signature FLV in the 1st 3 bytes. I did get a ts file from the first one. The second gave a 0 byte ts file and ffmpeg apparently quit there. – Alan Corey – 2016-03-22T21:57:16.277

flv can have actual flash commands embedded in it. Most movie sites just use as a container, so transcoding works. I actually feel safer transcoding flv into another container, because who knows if someone can figure out how to put malware flash in a flv. But they could be trying something fancy. Maybe they have flash in part one that grabs the part 2 file – infixed – 2016-03-22T22:08:33.373

Malware's part of why I don't normally use Windows or Flash. I'm guessing it's just a continuation. The total run time is 4:34 and the first file runs 1:49. The 3 files total 14.49 megs, the first is 5.6, so it's 38% by time and by size. I have put therm together with Andy's FLV joiner http://www.videohelp.com/software/Andys-FLV-Joiner but it's not quite right, every conversion to another format dies at the first joint. mplayer plays all the way through it but shows the wrong run time.

– Alan Corey – 2016-03-22T22:27:07.520

I just uncompiled the swf that was loading this with a free online decompiler at ShowMyCode. And I'm reading an ActionScript tutorial. – Alan Corey – 2016-03-24T04:00:10.663

Trying gnash after reading this post, still compiling it. I'm under OpenBSD most of the time, which has no Flash environment available. Gnash happens to be in ports. http://stackoverflow.com/questions/20194270/convert-compressed-swf-to-mp4

– Alan Corey – 2016-03-24T16:48:39.083

Looks like the 2nd and 3rd files aren't valid standalone FLVs. You should be able to cat them, but you will have to iterate through removing the first n bytes i.e. cat(flv1, flv2 - first n bytes, flv3 - n bytes). My guess is the first 32 bytes. Also, your ffmpeg is old. Current git head is 79xxx – Gyan – 2016-03-24T17:34:07.287

Interesting puzzle. I'm thinking they're valid but in Adobe's spec it talks about interleaved blocks of audio and video data with pointers (back pointers actually) like a linked list. If the data isn't where the pointer points then it breaks everything from there on. I'm still trying to make sense of the 9 byte header, Googling beyond the Adobe spec helped. I think the first has extra metadata like a TIFF or JPEG can. By some Windows program this video is Flash 9 so I'll stick with the ffmpeg in OpenBSD ports, it's safer that way. Gnash is abandonware, too old. – Alan Corey – 2016-03-25T15:07:31.300

Stumbled across flvmeta, a nice little utility that can check, dump, edit metadata in flv files. These files all show errors and warnings which is why I was confused trying to write a program to deal with them following Adobe's spec. They wrote their own player, the files don't have to be standard. The first tag starts at byte 13 in all cases but in the first file it's of type scriptData and contains just metadata. Tags can be audio, video or script. http://www.flvmeta.com/

– Alan Corey – 2016-03-25T22:17:02.640

Answers

0

Not a complete answer yet but FLVMeta and a partial reading of Adobe's spec are beginning to shine light on things. From an FLVMeta full dump the tags or sections of data look like this:

    --- 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

So you could read the header into one file, put all the tags into 1 file each, then reconstruct however many input files into however many output files you wanted. Each "tag" I'd call a block, but it's a chunk of data. You don't have to manipulate them in real time. Each has a timestamp, you just have to put them together in that order and don't split a tag across files.

I wish FLVMeta had more useful output for moving things around under program control like tab or comma-delimited data. Maybe even create an SQLite database for each project, put all the audio tags in one table, video in another, script in another. Maybe I'll do that yet since it's open source and on Github. It'd be simpler if flvs weren't big-endian and I'm on a little-endian machine. All integers are big-endian, like on a Mac.

Alan Corey

Posted 2016-03-22T15:40:04.437

Reputation: 9

0

Done finally. I ended up using a C program I wrote to concatenate them once I solved the bug that EOF on the first input file ended up as an FF or -1 in the output file, which stopped players and converters at that point.

flvmeta still gave warnings on the output of this but I was able to convert it to an mp4 using:

    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;
    }

Alan Corey

Posted 2016-03-22T15:40:04.437

Reputation: 9