@@ -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 ' ;
@@ -195,10 +195,10 @@ void FormatContext::close()
195195 m_headerWriten = false ;
196196
197197 // To prevent free not out custom IO, e.g. setted via raw pointer access
198- if (m_customIO) {
198+ if (m_customIO && avio ) {
199199 // Close custom IO
200200 av_freep (&avio->buffer );
201- av_freep (&avio);
201+ avio_context_free (&avio);
202202 m_customIO = false ;
203203 }
204204 }
@@ -606,29 +606,42 @@ Packet FormatContext::readPacket(OptionalErrorCode ec)
606606
607607void FormatContext::openOutput (const string &uri, OptionalErrorCode ec)
608608{
609- return openOutput (uri, OutputFormat (), nullptr , ec);
609+ openOutput (uri, OutputFormat (), nullptr , ec);
610610}
611611
612612void 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
627621void 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+
632645void 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+
696760void 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+
705829void 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);
@@ -1067,26 +1202,24 @@ void FormatContext::openCustomIO(CustomIO *io, size_t internalBufferSize, bool i
10671202
10681203 AVIOContext *ctx = nullptr ;
10691204 // Note: buffer must be allocated only with av_malloc() and friends
1070- uint8_t *internalBuffer = (uint8_t *)av_mallocz (internalBufferSize);
1071- if (!internalBuffer)
1072- {
1205+ auto internalBuffer = av::mallocz<uint8_t >(internalBufferSize);
1206+ if (!internalBuffer) {
10731207 throws_if (ec, ENOMEM , std::system_category ());
10741208 return ;
10751209 }
10761210
1077- ctx = avio_alloc_context (internalBuffer, internalBufferSize, isWritable, (void *)(io), custom_io_read, custom_io_write, custom_io_seek);
1078- if (ctx)
1079- {
1211+ ctx = avio_alloc_context (internalBuffer.get (), internalBufferSize, isWritable, (void *)(io), custom_io_read, custom_io_write, custom_io_seek);
1212+ if (ctx) {
10801213 ctx->seekable = io->seekable ();
10811214 m_raw->flags |= AVFMT_FLAG_CUSTOM_IO ;
10821215 m_customIO = true ;
1083- }
1084- else
1085- {
1216+ } else {
10861217 throws_if (ec, ENOMEM , std::system_category ());
10871218 return ;
10881219 }
10891220
1221+ internalBuffer.release (); // drop owning
1222+
10901223 m_raw->pb = ctx;
10911224}
10921225
0 commit comments