Skip to content

Commit bea31e9

Browse files
committed
FormatContext: add extra openOutput() methods for CustomIO
...and more: - CustomIO output open with Format Options, with/without Format Options and Output Format specification - URI based output open with Output Format specification - Add initOutput() method that wraps avformat_init_outpur()
1 parent 5df0c5e commit bea31e9

2 files changed

Lines changed: 189 additions & 16 deletions

File tree

src/avcpp/formatcontext.cpp

Lines changed: 146 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ void set_uri(AVFormatContext *ctx, string_view uri)
6969
#if AVCPP_API_AVFORMAT_URL
7070
if (ctx->url)
7171
av_free(ctx->url);
72-
ctx->url = av_strdup(uri.data());
72+
ctx->url = av_strndup(uri.data(), uri.size());
7373
#else
7474
av_strlcpy(ctx->filename, uri.data(), std::min<size_t>(sizeof(ctx->filename), uri.size() + 1));
7575
ctx->filename[uri.size()] = '\0';
@@ -606,29 +606,42 @@ Packet FormatContext::readPacket(OptionalErrorCode ec)
606606

607607
void FormatContext::openOutput(const string &uri, OptionalErrorCode ec)
608608
{
609-
return openOutput(uri, OutputFormat(), nullptr, ec);
609+
openOutput(uri, OutputFormat(), nullptr, ec);
610610
}
611611

612612
void FormatContext::openOutput(const string &uri, Dictionary &options, OptionalErrorCode ec)
613613
{
614614
auto ptr = options.release();
615-
try
616-
{
617-
openOutput(uri, OutputFormat(), &ptr, ec);
618-
options.assign(ptr);
619-
}
620-
catch (const Exception&)
621-
{
615+
ScopeOutAction onScopeExit{[ptr, &options] {
622616
options.assign(ptr);
623-
throw;
624-
}
617+
}};
618+
openOutput(uri, OutputFormat(), &ptr, ec);
625619
}
626620

627621
void FormatContext::openOutput(const string &uri, Dictionary &&options, OptionalErrorCode ec)
628622
{
629623
return openOutput(uri, options, ec);
630624
}
631625

626+
void FormatContext::openOutput(const std::string &uri, OutputFormat format, OptionalErrorCode ec)
627+
{
628+
openOutput(uri, format, nullptr, ec);
629+
}
630+
631+
void FormatContext::openOutput(const std::string &uri, Dictionary &options, OutputFormat format, OptionalErrorCode ec)
632+
{
633+
auto ptr = options.release();
634+
ScopeOutAction onScopeExit{[ptr, &options] {
635+
options.assign(ptr);
636+
}};
637+
openOutput(uri, format, &ptr, ec);
638+
}
639+
640+
void FormatContext::openOutput(const std::string &uri, Dictionary &&options, OutputFormat format, OptionalErrorCode ec)
641+
{
642+
openOutput(uri, options, format, ec);
643+
}
644+
632645
void FormatContext::openOutput(const string &uri, OutputFormat format, AVDictionary **options, OptionalErrorCode ec)
633646
{
634647
clear_if(ec);
@@ -693,6 +706,57 @@ void FormatContext::openOutput(const string &uri, OutputFormat format, AVDiction
693706
m_isOpened = true;
694707
}
695708

709+
bool FormatContext::initOutput(Dictionary &options, bool closeOnError, OptionalErrorCode ec)
710+
{
711+
auto dict = options.release();
712+
ScopeOutAction onScopeExit([this, &dict, &options, ec, closeOnError](){
713+
options.assign(dict);
714+
//fflog(AV_LOG_ERROR, "init output.... done with %s\n", (is_error(ec) || std::uncaught_exceptions() > 0) ? "error" : "no error");
715+
if (closeOnError && (is_error(ec) || std::uncaught_exceptions() > 0)) {
716+
close();
717+
}
718+
});
719+
return initOutput(&dict, ec);
720+
}
721+
722+
bool FormatContext::initOutput(AVDictionary **options, OptionalErrorCode ec)
723+
{
724+
clear_if(ec);
725+
726+
if (!isOpened()) {
727+
throws_if(ec, Errors::FormatNotOpened);
728+
return false;
729+
}
730+
731+
if (!isOutput()) {
732+
throws_if(ec, Errors::FormatInvalidDirection);
733+
return false;
734+
}
735+
736+
// just silent it???
737+
if (m_headerWriten) {
738+
return true;
739+
}
740+
741+
resetSocketAccess();
742+
int ret = avformat_init_output(m_raw, options);
743+
ret = checkPbError(ret);
744+
if (ret < 0) {
745+
throws_if(ec, ret, ffmpeg_category());
746+
return false;
747+
}
748+
749+
fflog(AV_LOG_ERROR, "avformat_init_output: ret = %d\n", ret);
750+
751+
switch (ret) {
752+
case AVSTREAM_INIT_IN_INIT_OUTPUT:
753+
return true;
754+
case AVSTREAM_INIT_IN_WRITE_HEADER:
755+
default:
756+
return false;
757+
}
758+
}
759+
696760
void FormatContext::openOutput(CustomIO *io, OptionalErrorCode ec, size_t internalBufferSize)
697761
{
698762
openCustomIOOutput(io, internalBufferSize, ec);
@@ -702,6 +766,66 @@ void FormatContext::openOutput(CustomIO *io, OptionalErrorCode ec, size_t intern
702766
}
703767
}
704768

769+
bool FormatContext::openOutput(CustomIO *io, Dictionary &options, OptionalErrorCode ec, size_t internalBufferSize)
770+
{
771+
openOutput(io, ec, internalBufferSize);
772+
if (!is_error(ec)) {
773+
return initOutput(options, true, ec);
774+
}
775+
return false;
776+
}
777+
778+
bool FormatContext::openOutput(CustomIO *io, Dictionary &&formatOptions, OptionalErrorCode ec, size_t internalBufferSize)
779+
{
780+
openOutput(io, ec, internalBufferSize);
781+
if (!is_error(ec)) {
782+
return initOutput(formatOptions, true, ec);
783+
}
784+
return false;
785+
}
786+
787+
void FormatContext::openOutput(CustomIO *io, OutputFormat format, OptionalErrorCode ec, size_t internalBufferSize)
788+
{
789+
if (format.isNull())
790+
format = outputFormat();
791+
else
792+
setFormat(format);
793+
openOutput(io, ec, internalBufferSize);
794+
}
795+
796+
bool FormatContext::openOutput(CustomIO *io, Dictionary &formatOptions, OutputFormat format, OptionalErrorCode ec, size_t internalBufferSize)
797+
{
798+
openOutput(io, format, ec, internalBufferSize);
799+
if (!is_error(ec)) {
800+
return initOutput(formatOptions, true, ec);
801+
}
802+
return false;
803+
}
804+
805+
bool FormatContext::openOutput(CustomIO *io, Dictionary &&formatOptions, OutputFormat format, OptionalErrorCode ec, size_t internalBufferSize)
806+
{
807+
openOutput(io, format, ec, internalBufferSize);
808+
if (!is_error(ec)) {
809+
return initOutput(formatOptions, true, ec);
810+
}
811+
return false;
812+
}
813+
814+
bool FormatContext::initOutput(OptionalErrorCode ec)
815+
{
816+
return initOutput(nullptr, ec);
817+
}
818+
819+
bool FormatContext::initOutput(Dictionary &options, OptionalErrorCode ec)
820+
{
821+
return initOutput(options, false, ec);
822+
}
823+
824+
bool FormatContext::initOutput(Dictionary &&options, OptionalErrorCode ec)
825+
{
826+
return initOutput(options, false, ec);
827+
}
828+
705829
void FormatContext::writeHeader(OptionalErrorCode ec)
706830
{
707831
writeHeader(nullptr, ec);
@@ -729,6 +853,11 @@ void FormatContext::writeHeader(AVDictionary **options, OptionalErrorCode ec)
729853
{
730854
clear_if(ec);
731855

856+
if (m_headerWriten) {
857+
// TBD: just silent it?
858+
return;
859+
}
860+
732861
if (!isOpened())
733862
{
734863
throws_if(ec, Errors::FormatNotOpened);
@@ -1051,6 +1180,12 @@ void FormatContext::openCustomIO(CustomIO *io, size_t internalBufferSize, bool i
10511180
{
10521181
clear_if(ec);
10531182

1183+
if (!io) {
1184+
fflog(AV_LOG_ERROR, "Open CustomIO with null io context");
1185+
throws_if(ec, Errors::InvalidArgument);
1186+
return;
1187+
}
1188+
10541189
if (!m_raw)
10551190
{
10561191
throws_if(ec, Errors::Unallocated);

src/avcpp/formatcontext.h

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,48 @@ class FormatContext : public FFWrapperPtr<AVFormatContext>, public noncopyable
263263
void openOutput(const std::string& uri, Dictionary &options, OptionalErrorCode ec = throws());
264264
void openOutput(const std::string& uri, Dictionary &&options, OptionalErrorCode ec = throws());
265265

266-
// TBD
267-
//void openOutput(const std::string& uri, OutputFormat format, OptionalErrorCode ec = throws());
268-
//void openOutput(const std::string& uri, Dictionary &options, OutputFormat format, OptionalErrorCode ec = throws());
269-
//void openOutput(const std::string& uri, Dictionary &&options, OutputFormat format, OptionalErrorCode ec = throws());
266+
void openOutput(const std::string& uri, OutputFormat format, OptionalErrorCode ec = throws());
267+
void openOutput(const std::string& uri, Dictionary &options, OutputFormat format, OptionalErrorCode ec = throws());
268+
void openOutput(const std::string& uri, Dictionary &&options, OutputFormat format, OptionalErrorCode ec = throws());
270269

270+
/// @{
271+
/**
272+
* Open Output with Custom IO
273+
*
274+
* Variants with @ref formatOptions internally calls @ref initOutput() with same return value meaning.
275+
*
276+
* @param io
277+
* @param formatOptions
278+
* @param format
279+
* @param ec
280+
* @param internalBufferSize
281+
*/
271282
void openOutput(CustomIO *io, OptionalErrorCode ec = throws(), size_t internalBufferSize = CUSTOM_IO_DEFAULT_BUFFER_SIZE);
283+
bool openOutput(CustomIO *io, Dictionary &formatOptions, OptionalErrorCode ec = throws(), size_t internalBufferSize = CUSTOM_IO_DEFAULT_BUFFER_SIZE);
284+
bool openOutput(CustomIO *io, Dictionary &&formatOptions, OptionalErrorCode ec = throws(), size_t internalBufferSize = CUSTOM_IO_DEFAULT_BUFFER_SIZE);
285+
286+
void openOutput(CustomIO *io, OutputFormat format, OptionalErrorCode ec = throws(), size_t internalBufferSize = CUSTOM_IO_DEFAULT_BUFFER_SIZE);
287+
bool openOutput(CustomIO *io, Dictionary &formatOptions, OutputFormat format, OptionalErrorCode ec = throws(), size_t internalBufferSize = CUSTOM_IO_DEFAULT_BUFFER_SIZE);
288+
bool openOutput(CustomIO *io, Dictionary &&formatOptions, OutputFormat format, OptionalErrorCode ec = throws(), size_t internalBufferSize = CUSTOM_IO_DEFAULT_BUFFER_SIZE);
289+
/// @}
290+
291+
/// @{
292+
/**
293+
* Init output without header writing
294+
*
295+
* If dictionary passed, writeHeader() should not be called with the same dictioary.
296+
*
297+
* @param options format options in the dictionary form
298+
* @param ec holder for the error code. If not-null and error code set return value has not matter
299+
*
300+
* @retval true format inited in avformat_init_output, @see AVSTREAM_INIT_IN_INIT_OUTPUT
301+
* @retval false format inited (will be) in avformat_write_header(), @see AVSTREAM_INIT_IN_WRITE_HEADER
302+
*
303+
*/
304+
bool initOutput(OptionalErrorCode ec = throws());
305+
bool initOutput(Dictionary &options, OptionalErrorCode ec = throws());
306+
bool initOutput(Dictionary &&options, OptionalErrorCode ec = throws());
307+
/// @}
272308

273309
void writeHeader(OptionalErrorCode ec = throws());
274310
void writeHeader(Dictionary &options, OptionalErrorCode ec = throws());
@@ -292,7 +328,9 @@ class FormatContext : public FFWrapperPtr<AVFormatContext>, public noncopyable
292328
private:
293329
void openInput(const std::string& uri, InputFormat format, AVDictionary **options, OptionalErrorCode ec);
294330
void openOutput(const std::string& uri, OutputFormat format, AVDictionary **options, OptionalErrorCode ec);
295-
void writeHeader(AVDictionary **options, OptionalErrorCode ec = throws());
331+
bool initOutput(Dictionary &options, bool closeOnError, OptionalErrorCode ec);
332+
bool initOutput(AVDictionary **options, OptionalErrorCode ec);
333+
void writeHeader(AVDictionary **options, OptionalErrorCode ec);
296334
void writePacket(const Packet &pkt, OptionalErrorCode ec, int(*write_proc)(AVFormatContext *, AVPacket *));
297335
void writeFrame(AVFrame *frame, int streamIndex, OptionalErrorCode ec, int(*write_proc)(AVFormatContext*,int,AVFrame*));
298336

0 commit comments

Comments
 (0)