Commit Graph

124 Commits

Author SHA1 Message Date
Anton Khirnov 2178ff2162 fftools/ffmpeg: move do_streamcopy() to ffmpeg_mux
do_streamcopy() is muxing code, so this is a more appropriate place for
this. The last uses of InputStream in it will be removed in following
commits.
2023-04-17 12:01:40 +02:00
Anton Khirnov a34f483291 fftools/ffmpeg: add muxer-input codec parameters to OutputStream
It stores codec parameters of the stream submitted to the muxer, which
may be different from the codec parameters in AVStream due to bitstream
filtering.

This avoids the confusing back and forth synchronisation between the
encoder, bitstream filters, and the muxer, now information flows only in
one direction. It also reduces the need for non-muxing code to access
AVStream.
2023-04-17 12:01:40 +02:00
Anton Khirnov a064aed4c3 fftools/ffmpeg: store stream media type in OutputStream
Reduces access to a deeply nested muxer property
OutputStream.st->codecpar->codec_type for this fundamental and immutable
stream property.

Besides making the code shorter, this will allow making the AVStream
(OutputStream.st) private to the muxer in the future.
2023-04-17 12:01:40 +02:00
Anton Khirnov 0288951174 fftools/ffmpeg_mux: make data_size_mux private to ffmpeg_mux
It is no longer used outside of this file.
2023-04-13 15:11:56 +02:00
Anton Khirnov 37b118096a fftools/ffmpeg: rewrite printing the final output sizes
Current code in print_final_stats(), printing the final summary such as
  video:8851kB audio:548kB subtitle:0kB other streams:0kB global headers:20kB muxing overhead: 0.559521%
was written with a single output file in mind and makes very little
sense otherwise.

Print this information in mux_final_stats() instead, one line per output
file. Use the correct filesize, if available.
2023-04-13 15:11:56 +02:00
Anton Khirnov 6b2e222a45 fftools/ffmpeg_mux: log final stats to muxer context 2023-04-13 15:11:56 +02:00
Anton Khirnov c1764d067d fftools/ffmpeg_mux: reindent 2023-04-13 15:11:56 +02:00
Anton Khirnov 3b6b0d1afb fftools/ffmpeg: move printing verbose muxing stats to ffmpeg_mux
This is a more appropriate place for this.
2023-04-13 15:11:56 +02:00
Anton Khirnov 79e136f14b fftools/ffmpeg: factorize checking whether any output was written
This is currently done in two places:
* at the end of print_final_stats(), which merely prints a warning if
  the total size of all written packets is zero
* at the end of transcode() (under a misleading historical 'close each
  encoder' comment), which instead checks the packet count to implement
  -abort_on empty_output[_stream]

Consolidate both of these blocks into a single function called from
of_write_trailer(), which is a more appropriate place for this. Also,
return an error code rather than exit immediately, which ensures all
output files are properly closed.
2023-04-13 15:11:56 +02:00
Anton Khirnov 5cf81bed88 fftools/ffmpeg: eliminate the main_return_code global
Properly pass muxing return codes through the call stack instead.
Slightly changes behavior in case of errors:
* the output IO stream is closed even if writing the trailer returns an
  error, which should be more correct
* all files get properly closed with -xerror, even if one of them fails
2023-04-13 15:11:56 +02:00
Anton Khirnov 87ae84e4af fftools/ffmpeg: move OutputStream.sq_frame to Encoder
It is audio/video encoding-only and does not need to be visible outside
of ffmpeg_enc.c
2023-04-13 15:11:56 +02:00
Anton Khirnov f30b620e98 fftools/ffmpeg: add encoder private data
Start by moving OutputStream.last_frame to it. In the future it will
hold other encoder-internal state.
2023-04-09 15:47:45 +02:00
Anton Khirnov 090950f832 fftools/sync_queue: use timebase from input frames/packets
They are always properly set now. Avoid a separate timebase-setting
call, which duplicates the knowledge of the timebase being used.
2023-04-09 15:47:45 +02:00
Anton Khirnov b40856c905 fftools/ffmpeg_mux: distinguish between sync queue and muxer EOF
Individual streams should be terminated in the former case, the whole
muxing process in the latter.

Reported-by: Gyan Doshi
2023-02-10 11:01:11 +01:00
Anton Khirnov 42a0dd6e7e fftools/ffmpeg: add an option for writing pre-muxing stats
Analogous to -enc_stats*, but happens right before muxing. Useful
because bitstream filters and the sync queue can modify packets after
encoding and before muxing. Also has access to the muxing timebase.
2023-02-09 15:24:15 +01:00
Anton Khirnov 6d4f3ae116 fftools/ffmpeg: store output packet timebases in the packet
Useful to keep track of what timebase the packet's timestamps are in.
2023-02-09 15:24:15 +01:00
Anton Khirnov 9b5036fabd fftools/ffmpeg: add an AVClass to MuxStream/OutputStream
Use it for logging. This makes log messages related to this output
stream more consistent.
2023-01-29 09:12:22 +01:00
Anton Khirnov d2c983c213 fftools/ffmpeg: add an AVClass to Muxer/OutputFile
Use it for logging. This makes log messages related to this output file
more consistent.
2023-01-29 09:10:57 +01:00
Anton Khirnov 425b2c4a56 fftools/ffmpeg: add options for writing encoding stats
Similar to -vstats, but more flexible:
- works for audio as well as video
- frame and/or packet information
- user-specifiable format
2023-01-29 09:09:59 +01:00
Anton Khirnov 2fa2e146cc fftools/ffmpeg: avoid storing full forced keyframe spec
It is not needed after the spec is parsed. Also avoids ugly string
comparisons for each video frame.
2022-11-28 10:28:14 +01:00
Anton Khirnov 334e52e094 fftools/ffmpeg: parse forced keyframes in of_open()
Allows to remove the ugly of_get_chapters() wrapper.
2022-11-28 10:28:14 +01:00
Anton Khirnov b1143330c8 fftools/ffmpeg: move force-keyframe-related vars to a separate struct
There are 8 of them and they are typically used together. Allows to pass
just this struct to forced_kf_apply(), which makes it clear that the
rest of the OutputStream is not accessed there.
2022-11-28 10:28:14 +01:00
Anton Khirnov 95af0bcc34 fftools/ffmpeg_mux_init: postpone matching -disposition to streams
Do it in set_dispositions() rather than during stream creation.

Since at this point all other stream information is known, this allows
setting disposition based on metadata, which implements #10015. This
also avoids an extra allocated string in OutputStream that was unused
after of_open().
2022-11-23 10:36:23 +01:00
Anton Khirnov 0fb7d111e8 fftools/ffmpeg: move OutputStream.max_frames to MuxStream
It no longer needs to be visible outside of the muxing code.
2022-11-17 10:52:58 +01:00
Anton Khirnov 874a6f2090 fftools/ffmpeg: set thread names 2022-10-24 02:00:31 +02:00
Anton Khirnov c5d7b6f49b fftools/ffmpeg_mux: move muxing queue fields from OutputStream to MuxStream
They are private to the muxer and do not need to be visible outside of
it.
2022-10-18 14:19:11 +02:00
Anton Khirnov f0cd68eea0 fftools/ffmpeg_mux: move bsf_ctx from OutputStream to MuxStream
It is private to the muxer and does not need to be visible outside of
it.
2022-10-18 14:19:11 +02:00
Anton Khirnov 2266e04834 fftools/ffmpeg_mux: embed OutputStream in a MuxStream
This is now possible since OutputStream is a child of OutputFile and the
code allocating it can access MuxStream. Avoids the overhead and extra
complexity of allocating two objects instead of one.

Similar to what was previously done for OutputFile/Muxer.
2022-10-18 14:19:11 +02:00
Anton Khirnov 709b47f8a4 fftools/ffmpeg: free output streams in of_close()
Output streams are now children of OutputFile, so it makes more sense to
free them there.
2022-10-18 14:19:11 +02:00
Anton Khirnov 7ef7a22251 fftools/ffmpeg: remove the output_streams global
Replace it with an array of streams in each OutputFile. This is a more
accurate reflection of the actual relationship between OutputStream and
OutputFile. This is easier to handle and will allow further
simplifications in future commits.
2022-10-18 13:57:43 +02:00
Anton Khirnov 9f9bf8703b fftools/ffmpeg: move init_output_bsfs() to ffmpeg_mux
Bitstream filtering is done as a part of muxing, so this is the more
proper place for this.
2022-10-18 13:57:43 +02:00
Anton Khirnov ee0a900e58 fftools/ffmpeg_mux: move sq_mux from OutputFile to Muxer
It is internal to ffmpeg_mux* and does not need to be visible to other
code.
2022-10-18 13:57:43 +02:00
Anton Khirnov d6195c88e2 fftools/ffmpeg_mux: inline mux_free() into of_close()
mux_free() is no longer called from anywhere else.
2022-10-18 13:57:43 +02:00
Anton Khirnov 36ce335d46 fftools/ffmpeg_mux: inline of_muxer_init() into of_open()
A separate muxer init is no longer necessary, now that of_open() has
access to Muxer.
2022-10-18 13:57:43 +02:00
Anton Khirnov a55ca682e2 fftools/ffmpeg_mux: allocate sq_pkt in setup_sync_queues()
This is now possible since setup_sync_queues() can interact with Muxer.
2022-10-18 13:57:43 +02:00
Anton Khirnov 65d106933a fftools/ffmpeg_mux: embed OutputFile in a Muxer
This is now possible since the code allocating OutputFile can see
sizeof(Muxer). Avoids the overhead and extra complexity of allocating
two objects instead of one.

Similar to what is done e.g. for AVStream/FFStream in lavf.
2022-10-18 13:57:43 +02:00
Anton Khirnov 24098c6c8d fftools/ffmpeg_mux: move Muxer and MuxStream to a new header
This will allow ffmpeg_mux_init.c to work with these structs.
2022-10-18 13:57:43 +02:00
Anton Khirnov 965bff37b6 fftools/ffmpeg: move some stream initialization code to ffmpeg_mux
The code in question is muxing-specific and so belongs there. This will
allow make some objects private to the muxer in future commits.
2022-10-18 13:57:42 +02:00
Anton Khirnov 731246ae8f fftools/ffmpeg_mux: drop the of_ prefix from of_submit_packet()
This function is now static.
2022-10-18 13:57:42 +02:00
Anton Khirnov a7028d7fa8 fftools/ffmpeg_mux: rename submit_packet() to thread_submit_packet()
This is more descriptive, and the submit_packet() name will be reused in
following commits.
2022-10-18 13:57:42 +02:00
Anton Khirnov d579a70291 fftools/ffmpeg: move output_packet() to ffmpeg_mux
This function is common to both transcoding and streamcopy, so it
properly belongs into the muxing code.
2022-10-18 13:57:42 +02:00
Anton Khirnov 072e3f710e fftools/ffmpeg_mux: do not unref a NULL packet
The packet submitted to of_submit_packet() may be NULL to signal EOF.
2022-10-18 13:57:42 +02:00
Anton Khirnov 3d86a13b47 fftools/ffmpeg: drop the -async option
It has been deprecated in favor of the aresample filter for almost 10
years.

Another thing this option can do is drop audio timestamps and have them
generated by the encoding code or the muxer, but
- for encoding, this can already be done with the setpts filter
- for muxing this should almost never be done as timestamp generation by
  the muxer is deprecated, but people who really want to do this can use
  the setts bitstream filter
2022-10-04 11:55:03 +02:00
Anton Khirnov 4fce3bab64 fftools/ffmpeg: use a separate counter for encoded packet data size
update_video_stats() currently uses OutputStream.data_size to print the
total size of the encoded stream so far and the average bitrate.
However, that field is updated in the muxer thread, right before the
packet is sent to the muxer. Not only is this racy, but the numbers may
not match even if muxing was in the main thread due to bitstream
filters, filesize limiting, etc.

Introduce a new counter, data_size_enc, for total size of the packets
received from the encoder and use that in update_video_stats(). Rename
data_size to data_size_mux to indicate its semantics more clearly.

No synchronization is needed for data_size_mux, because it is only read
in the main thread in print_final_stats(), which runs after the muxer
threads are terminated.
2022-08-29 15:42:11 +02:00
Anton Khirnov ee2092ddec fftools/ffmpeg_mux: avoid leaking pkt on errors 2022-08-13 12:41:05 +02:00
Anton Khirnov d6cbc04229 fftools/ffmpeg_mux: move some functions closer to their only callers 2022-07-28 16:37:16 +02:00
Anton Khirnov c2f2dd0296 fftools/ffmpeg: stop accessing the encoder context unnecessarily
The same information is available from AVStream.codecpar. This will
allow to stop allocating an encoder unless encoding is actually
performed.
2022-07-28 16:37:16 +02:00
Anton Khirnov 2d924b3a63 fftools/ffmpeg: move each muxer to a separate thread 2022-07-23 11:53:19 +02:00
Anton Khirnov 33f5cacb1d fftools/ffmpeg_mux: do not call exit_program() in print_sdp()
Return an error instead, as is already done in other places in this
function.
2022-07-23 11:53:19 +02:00
Anton Khirnov 9fc64574e1 fftools/ffmpeg_mux: return errors from write_packet()
Do not call exit_program(), as that would conflict with moving this code
into a separate thread.
2022-07-23 11:53:19 +02:00
Anton Khirnov 279214dd51 fftools/ffmpeg_mux: return errors from submit_packet()
Do not call exit_program(), as that would conflict with moving this code
into a separate thread.
2022-07-23 11:53:19 +02:00
Anton Khirnov 52bc8a842e fftools/ffmpeg_mux: return errors from of_submit_packet()
Do not call exit_program(), as that would conflict with moving this code
into a separate thread.
2022-07-23 11:53:19 +02:00
Anton Khirnov ff593c6c88 fftools/ffmpeg: make the muxer AVFormatContext private to ffmpeg_mux.c
Since the muxer will operate in a separate thread in the future, the
muxer context should not be accessed from the outside.
2022-07-23 11:53:19 +02:00
Anton Khirnov 4403851ca9 fftools/ffmpeg: only set OutputStream.frame_number for video encoding
It is unused otherwise.

Rename the field to vsync_frame_number to better reflect its current
purpose.
2022-07-23 11:53:19 +02:00
Anton Khirnov 587081a179 fftools/ffmpeg: use the sync queues to handle -frames
Same issues apply to it as to -shortest.

Changes the results of the following tests:
- matroska-flac-extradata-update
  The test reencodes two input FLAC streams into three output FLAC
  streams. The last output stream is limited to 8 frames. The current
  code results in the first two output streams having 12 frames, after
  this commit all three streams have 8 frames and are the same length.
  This new result is better, since it is predictable.
- mkv-1242
  The test streamcopies one video and one audio stream, video is limited
  to 11 frames. The new result shortens the audio stream so that it is
  not longer than the video.
2022-07-23 11:53:19 +02:00
Anton Khirnov 919638ff5c fftools/ffmpeg_mux: reindent 2022-07-23 11:53:19 +02:00
Anton Khirnov 4740fea7dd fftools/ffmpeg: rework -shortest implementation
The -shortest option (which finishes the output file at the time the
shortest stream ends) is currently implemented by faking the -t option
when an output stream ends. This approach is fragile, since it depends
on the frames/packets being processed in a specific order. E.g. there
are currently some situations in which the output file length will
depend unpredictably on unrelated factors like encoder delay. More
importantly, the present work aiming at splitting various ffmpeg
components into different threads will make this approach completely
unworkable, since the frames/packets will arrive in effectively random
order.

This commit introduces a "sync queue", which is essentially a collection
of FIFOs, one per stream. Frames/packets are submitted to these FIFOs
and are then released for further processing (encoding or muxing) when
it is ensured that the frame in question will not cause its stream to
get ahead of the other streams (the logic is similar to libavformat's
interleaving queue).

These sync queues are then used for encoding and/or muxing when the
-shortest option is specified.

A new option – -shortest_buf_duration – controls the maximum number of
queued packets, to avoid runaway memory usage.

This commit changes the results of the following tests:
- copy-shortest[12]: the last audio frame is now gone. This is
  correct, since it actually outlasts the last video frame.
- shortest-sub: the video packets following the last subtitle packet are
  now gone. This is also correct.
2022-07-23 11:53:19 +02:00
Anton Khirnov d02ae31fb2 fftools/ffmpeg: use pre-BSF DTS for choosing next output
The following commits will add a new buffering stage after bitstream
filters, which should not be taken into account for choosing next
output.

OutputStream.last_mux_dts is also used by the muxing code to make up
missing DTS values - that field is now moved to the muxer-private
MuxStream object.
2022-07-23 11:53:19 +02:00
Anton Khirnov 52fee96ae9 fftools/ffmpeg: move output file opts into private context
It is private to the muxer, no reason to access it from outside.
2022-07-23 11:53:19 +02:00
Anton Khirnov ec00b005f9 fftools/ffmpeg_mux: split of_write_packet()
It is currently called from two places:
- output_packet() in ffmpeg.c, which submits the newly available output
  packet to the muxer
- from of_check_init() in ffmpeg_mux.c after the header has been
  written, to flush the muxing queue

Some packets will thus be processed by this function twice, so it
requires an extra parameter to indicate the place it is called from and
avoid modifying some state twice.

This is fragile and hard to follow, so split this function into two.
Also rename of_write_packet() to of_submit_packet() to better reflect
its new purpose.
2022-07-23 11:53:19 +02:00
Anton Khirnov 6999a3cb18 fftools/ffmpeg_mux: split queuing packets into a separate function 2022-07-23 11:53:19 +02:00
Anton Khirnov 9c2b800203 fftools/ffmpeg: move the mux queue into muxer private data
The muxing queue currently lives in OutputStream, which is a very large
struct storing the state for both encoding and muxing. The muxing queue
is only used by the code in ffmpeg_mux, so it makes sense to restrict it
to that file.

This makes the first step towards reducing the scope of OutputStream.
2022-07-23 11:53:19 +02:00
Anton Khirnov 48989efb76 fftools/ffmpeg: access output file chapters through a wrapper
Avoid accessing the muxer context directly, as this will become
forbidden in future commits.
2022-07-23 11:53:19 +02:00
Anton Khirnov cc1cc2c65e fftools/ffmpeg: move closing the file into of_write_trailer()
The current code postpones closing the files until after printing the
final report, which accesses the output file size. Deal with this by
storing the final file size before closing the file.
2022-07-23 11:53:19 +02:00
Anton Khirnov cc49646077 fftools/ffmpeg: write the header for stream-less outputs when initializing the muxer
There is no reason to delay this.
2022-07-23 11:53:19 +02:00
Anton Khirnov 12e9e50219 fftools/ffmpeg: set want_sdp when initializing the muxer
Allows making the variable local to ffmpeg_mux.
2022-07-23 11:53:19 +02:00
Anton Khirnov d8e944c238 fftools/ffmpeg: refactor limiting output file size with -fs
Move the file size checking code to ffmpeg_mux. Use the recently
introduced of_filesize(), making this code consistent with the size
shown by print_report().
2022-07-23 11:53:19 +02:00
Anton Khirnov 9fe62a545f fftools/ffmpeg: add a helper function to access output file size
Stop accessing muxer internals from outside of ffmpeg_mux.
2022-07-23 11:53:19 +02:00
Anton Khirnov 6a23be92d2 fftools/ffmpeg_mux: add private muxer context
Move header_written into it, which is not (and should not be) used by
any code outside of ffmpeg_mux.

In the future this context will contain more muxer-private state that
should not be visible to other code.
2022-07-23 11:53:19 +02:00
Gyan Doshi 09c53a04c5 ffmpeg: add option fps_mode
fps_mode sets video sync per output stream. Overrides vsync for matching
streams.

vsync is deprecated.
2022-06-11 09:47:27 +05:30
Anton Khirnov b033913d1c fftools/ffmpeg: move processing AV_PKT_DATA_QUALITY_STATS to do_video_stats()
This is a more appropriate place for this code, since the values we read
from AV_PKT_DATA_QUALITY_STATS side data are primarily written into
video stats. This ensures that the values written into stats actually
apply to the right packet.

Rename the function to update_video_stats() to better reflect its new
purpose.
2022-05-24 13:46:57 +02:00
Anton Khirnov 5c66ee6351 fftools/ffmpeg: move freeing the output file to ffmpeg_mux.c 2022-04-13 12:07:54 +02:00
Anton Khirnov 5bc644ea8a fftools/ffmpeg: move writing the trailer to ffmpeg_mux.c 2022-04-13 12:07:54 +02:00
Anton Khirnov 288aa37387 fftools/ffmpeg: move some muxing-related code into a separate file
This is a first step towards making muxers more independent from the
rest of the code.
2022-04-13 12:07:54 +02:00