salsaman / LiVES

LiVES is a feature rich application which combines elements of VJ and video editing software. The current version runs on Linux / BSD. Check_out_the_new_discussion_area https://github.com/salsaman/LiVES/discussions
http://lives-video.com
GNU General Public License v3.0
90 stars 11 forks source link

Direct stream copy - editing without reencoding #32

Open VVD opened 3 years ago

VVD commented 3 years ago

ffmpeg support this via -vcodec copy -acodec copy options. Example: ffmpeg -i INFILE.mkv -vcodec copy -acodec copy -ss 00:01:00.000 -t 00:00:10.000 OUTFILE.mkv

It can be used for crop video from begin and from end, cut parts from middle. From end video can be cut on every frame, but at begin on keyframes only. If user need to crop video at begin and not on keyframe - he/she must reencode this part. Some codecs can produce video tracks with all frames are keyframes.

Advanced possibility: concatenate different video files (if video streams are compatible - same codec, resolution and framerate).

P.S. Sorry for my poor English.

salsaman commented 3 years ago

I am not sure it is so simple - generally there is metadata at the start of the video which might need re-encoding. For example the clip duration would likely need updating.

E.g libav has the functions avformat_write_header() and av_write_trailer() which need to be used for some formats.

Regarding the header, I believe this depends on the container format used, which then has to passed to the codec context, e.g:

if (oformat->flags & AVFMT_GLOBALHEADER) codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

so you can already see one problem which is that the encoder may be continuously updating the header. it may be that ffmpeg is doing some kind of internal short cut where it runs the encoder but then copies the actual frame data internally, in which case it may. be impossible to replicate

Anyway I will try some experiments when I have time.

VVD commented 3 years ago

Ofc it isn't just cut of a file. It's create a new file with header and copy frames without reencoding.

salsaman commented 3 years ago

Sure. What I need to check is if there is an API in libav for that. Normally one would read packets and send them to the decoder and get frames back. Then when encoding you do the reverse, push frames to the encoder and get packets back. When you push the frame to the encoder, it most likely updates the header or maintains some internal state which eventually gets written at the end. So you cannot simply take packets from the decode stream and insert them in the encode stream. Also this is most likely specific to the particular codec / format. For example you take packets from one stream, without examining them you dont know how many frames are contained. The point being, ffmpeg probably isn't really doing a blind copy, it probably parses the data between reading it and writing it, (using the codec context), then passes this on to the format context.

For some specific codec / format combinations, you can simply concatenate unencoded chunks and it should still work, I believe that is possible with mpeg2, but I know for a fact that mkv doesnt work that way, you would need to parse and update the EBML format in the header data blocks at least.

Just to give you idea look at the mkv decoder which pulls metadata from mkv and webm containers. https://github.com/salsaman/LiVES/blob/master/lives-plugins/plugins/decoders/mkv_decoder.c https://github.com/salsaman/LiVES/blob/master/lives-plugins/plugins/decoders/mkv_decoder.h

Almost all of that code is there just to implement 2 functions: get_clip_data and get_frame. Now if I delve into that code it might be possible to do what you say, but it would be specific to a single container format, i.e mkv.