Re: [FFmpeg-devel] [PATCH 2/2] Add fate test for hls metadata update.
Le jeu. 11 avr. 2024 à 09:17, Andreas Rheinhardt < andreas.rheinha...@outlook.com> a écrit : > Romain Beauxis: > > This patch adds a FATE test for the new HLS metadata update. The fate > > sample consists of a two segment AAC hls stream. The first segment has > > test title 1 as title metadata while the second has test title 2. > > > > In the log, we can see that test title 2 is reported for the stream, > > indicating that the metadata was updated with the second segment. > > > > Romain > > --- > > tests/fate/demux.mak | 3 + > > tests/ref/fate/hls-adts-meta-demux | 124 + > > 2 files changed, 127 insertions(+) > > create mode 100644 tests/ref/fate/hls-adts-meta-demux > > > > diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak > > index d9b9045f0b..7243c2c163 100644 > > --- a/tests/fate/demux.mak > > +++ b/tests/fate/demux.mak > > @@ -160,6 +160,9 @@ fate-ts-demux: CMD = ffprobe_demux > $(TARGET_SAMPLES)/ac3/mp3ac325-4864-small.ts > > FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-timed-id3-demux > > fate-ts-timed-id3-demux: CMD = ffprobe_demux > $(TARGET_SAMPLES)/mpegts/id3.ts > > > > +FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-hls-adts-meta-demux > > +fate-fate-hls-adts-meta-demux: CMD = ffprobe_demux > $(TARGET_SAMPLES)/hls-adts-meta/stream.m3u8 > > + > > FATE_SAMPLES_DEMUX += $(FATE_SAMPLES_DEMUX-yes) > > FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_DEMUX) > > FATE_FFPROBE_DEMUX += $(FATE_FFPROBE_DEMUX-yes) > > diff --git a/tests/ref/fate/hls-adts-meta-demux > b/tests/ref/fate/hls-adts-meta-demux > > new file mode 100644 > > index 00..ab944695fc > > --- /dev/null > > +++ b/tests/ref/fate/hls-adts-meta-demux > > @@ -0,0 +1,124 @@ > > > +packet|codec_type=audio|stream_index=0|pts=3416400|pts_time=37.96|dts=3416400|dts_time=37.96|duration=2090|duration_time=0.023222|size=368|pos=0|flags=K__|data_hash=CRC32:c371b0d9 > > > +packet|codec_type=audio|stream_index=0|pts=3418490|pts_time=37.983222|dts=3418490|dts_time=37.983222|duration=2090|duration_time=0.023222|size=390|pos=368|flags=K__|data_hash=CRC32:950c52b2 > > > +packet|codec_type=audio|stream_index=0|pts=3420580|pts_time=38.006444|dts=3420580|dts_time=38.006444|duration=2090|duration_time=0.023222|size=357|pos=758|flags=K__|data_hash=CRC32:3e672212 > > > +packet|codec_type=audio|stream_index=0|pts=3422669|pts_time=38.029656|dts=3422669|dts_time=38.029656|duration=2090|duration_time=0.023222|size=426|pos=1115|flags=K__|data_hash=CRC32:817b6e4c > > > +packet|codec_type=audio|stream_index=0|pts=3424759|pts_time=38.052878|dts=3424759|dts_time=38.052878|duration=2090|duration_time=0.023222|size=368|pos=1541|flags=K__|data_hash=CRC32:c4c6e1ed > > > +packet|codec_type=audio|stream_index=0|pts=3426849|pts_time=38.076100|dts=3426849|dts_time=38.076100|duration=2090|duration_time=0.023222|size=389|pos=1909|flags=K__|data_hash=CRC32:67cb6dd9 > > > +packet|codec_type=audio|stream_index=0|pts=3428939|pts_time=38.099322|dts=3428939|dts_time=38.099322|duration=2090|duration_time=0.023222|size=352|pos=2298|flags=K__|data_hash=CRC32:7a56ff53 > > > +packet|codec_type=audio|stream_index=0|pts=3431029|pts_time=38.122544|dts=3431029|dts_time=38.122544|duration=2090|duration_time=0.023222|size=378|pos=2650|flags=K__|data_hash=CRC32:f8d5ef58 > > > +packet|codec_type=audio|stream_index=0|pts=3433118|pts_time=38.145756|dts=3433118|dts_time=38.145756|duration=2090|duration_time=0.023222|size=384|pos=3028|flags=K__|data_hash=CRC32:73a4fb1c > > > +packet|codec_type=audio|stream_index=0|pts=3435208|pts_time=38.168978|dts=3435208|dts_time=38.168978|duration=2090|duration_time=0.023222|size=353|pos=3412|flags=K__|data_hash=CRC32:4ea999b5 > > > +packet|codec_type=audio|stream_index=0|pts=3437298|pts_time=38.192200|dts=3437298|dts_time=38.192200|duration=2090|duration_time=0.023222|size=417|pos=3765|flags=K__|data_hash=CRC32:4540aec8 > > > +packet|codec_type=audio|stream_index=0|pts=3439388|pts_time=38.215422|dts=3439388|dts_time=38.215422|duration=2090|duration_time=0.023222|size=361|pos=4182|flags=K__|data_hash=CRC32:635a04f4 > > > +packet|codec_type=audio|stream_index=0|pts=3441478|pts_time=38.238644|dts=3441478|dts_time=38.238644|duration=2090|duration_time=0.023222|size=399|pos=4543|flags=K__|data_hash=CRC32:94583c18 > > > +packet|codec_type=audio|stream_index=0|pts=3443567|pts_time=38.261856|dts=3443567|dts_time=38.261856|duration=2090|duration_time=0.023222|size=384|pos=4942|flags=K__|data_hash=CRC32:21070d79 > > > +packet|codec_type=audio|stream_index=0|pts=3445657|pts_time=38.285078|dts=3445657|dts_time=38.285078|duration=2090|duration_ti
Re: [FFmpeg-devel] [PATCH 1/2] libavformat/hls.c: support in-stream ID3 metadata update.
Hi all, Le dim. 7 avr. 2024 à 09:46, Romain Beauxis a écrit : > > > Le dim. 7 avr. 2024 à 05:44, Steven Liu a > écrit : > >> Romain Beauxis 于2024年3月26日周二 08:58写道: >> > >> > This patch adds support for updating HLS metadata passed as ID3 frames. >> > >> > This seems like a pretty straight-forward improvement. Updating the >> > metadaata of the first stream seems to be the mechanism is other places >> > in the code and works as expected. >> >> Would it be possible to get this patch committed? My understanding is that it has been reviewed so this should be the next step? The second patch adding FATE tests could be committed separately if it causes issues. The samples for it are here: https://www.dropbox.com/scl/fo/1x74ztoa6yo9q49ignfnt/h?rlkey=xvg5nhgjr515gm6b375evm8n4=0 and should be placed into a $FATE_SAMPLES/hls-adts-meta directory. Thanks! > > --- >> > libavformat/hls.c | 54 --- >> > 1 file changed, 32 insertions(+), 22 deletions(-) >> > >> > diff --git a/libavformat/hls.c b/libavformat/hls.c >> > index f6b44c2e35..ba6634d57a 100644 >> > --- a/libavformat/hls.c >> > +++ b/libavformat/hls.c >> > @@ -93,6 +93,12 @@ enum PlaylistType { >> > PLS_TYPE_VOD >> > }; >> > >> > +#define ID3_PRIV_OWNER_TS >> "com.apple.streaming.transportStreamTimestamp" >> > +#define ID3_PRIV_OWNER_AUDIO_SETUP >> "com.apple.streaming.audioDescription" >> > + >> > +#define ID3v2_PRIV_OWNER_TS ID3v2_PRIV_METADATA_PREFIX >> ID3_PRIV_OWNER_TS >> > +#define ID3v2_PRIV_OWNER_AUDIO_SETUP ID3v2_PRIV_METADATA_PREFIX >> ID3_PRIV_OWNER_AUDIO_SETUP >> > + >> > /* >> > * Each playlist has its own demuxer. If it currently is active, >> > * it has an open AVIOContext too, and potentially an AVPacket >> > @@ -150,9 +156,7 @@ struct playlist { >> > int64_t id3_offset; /* in stream original tb */ >> > uint8_t* id3_buf; /* temp buffer for id3 parsing */ >> > unsigned int id3_buf_size; >> > -AVDictionary *id3_initial; /* data from first id3 tag */ >> > -int id3_found; /* ID3 tag found at some point */ >> > -int id3_changed; /* ID3 tag data has changed at some point */ >> > +AVDictionary *last_id3; /* data from the last id3 tag */ >> > ID3v2ExtraMeta *id3_deferred_extra; /* stored here until >> subdemuxer is opened */ >> > >> > HLSAudioSetupInfo audio_setup_info; >> > @@ -270,7 +274,7 @@ static void free_playlist_list(HLSContext *c) >> > av_freep(>main_streams); >> > av_freep(>renditions); >> > av_freep(>id3_buf); >> > -av_dict_free(>id3_initial); >> > +av_dict_free(>last_id3); >> > ff_id3v2_free_extra_meta(>id3_deferred_extra); >> > av_freep(>init_sec_buf); >> > av_packet_free(>pkt); >> > @@ -1083,15 +1087,13 @@ static void parse_id3(AVFormatContext *s, >> AVIOContext *pb, >> >AVDictionary **metadata, int64_t *dts, >> HLSAudioSetupInfo *audio_setup_info, >> >ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta >> **extra_meta) >> > { >> > -static const char id3_priv_owner_ts[] = >> "com.apple.streaming.transportStreamTimestamp"; >> > -static const char id3_priv_owner_audio_setup[] = >> "com.apple.streaming.audioDescription"; >> > ID3v2ExtraMeta *meta; >> > >> > ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); >> > for (meta = *extra_meta; meta; meta = meta->next) { >> > if (!strcmp(meta->tag, "PRIV")) { >> > ID3v2ExtraMetaPRIV *priv = >data.priv; >> > -if (priv->datasize == 8 && !av_strncasecmp(priv->owner, >> id3_priv_owner_ts, 44)) { >> > +if (priv->datasize == 8 && !av_strncasecmp(priv->owner, >> ID3_PRIV_OWNER_TS, strlen(ID3_PRIV_OWNER_TS))) { >> > /* 33-bit MPEG timestamp */ >> > int64_t ts = AV_RB64(priv->data); >> > av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp >> %"PRId64"\n", ts); >> > @@ -1099,7 +1101,9 @@ static void parse_id3(AVFormatContext *s, >> AVIOContext *pb, >> > *dts = ts; >> > else >> >
Re: [FFmpeg-devel] Query from Reuters on XZ, open source, and Microsoft
Le mar. 9 avr. 2024 à 18:46, Paul B Mahol a écrit : > On Tue, Apr 9, 2024 at 10:57 PM Romain Beauxis > wrote: > > > [Apologies for continuing the conversation, Rémi] > > > > Le mar. 9 avr. 2024 à 14:05, Tomas Härdin a écrit : > > > > > mån 2024-04-08 klockan 13:13 -0500 skrev Romain Beauxis: > > > > On Wed, Apr 3, 2024, 11:39 Kieran Kunhya via ffmpeg-devel < > > > > ffmpeg-devel@ffmpeg.org> wrote: > > > > > > > > > Hi Raphael, > > > > > > > > > > I was the author of the tweet and I gave a short talk about this > > > > > topic at > > > > > Demuxed at a video conference last year: > > > > > https://m.youtube.com/watch?v=OIyOEuQQsCQ=930s > > > > > > > > > > That said this is a community project and it would be best to > > > > > continue the > > > > > discussion on this mailing list unless agreed otherwise. > > > > > > > > > > > > > Thank you for sharing your talk. It's indeed unfortunate that large > > > > companies are not more generous with the projects they depend on > > > > _heavily_ > > > > > > > > I would like to offer a constructive feedback really not intended as > > > > trolling. I believe that supporting a more modern development > > > > workflow such > > > > as the GitHub PR or gitlab MR would go very long way in helping > > > > onboarding > > > > new developers. > > > > > > Considering which company owns GitHub and which company was the target > > > of Kieran's criticism, this seems ill-adviced > > > > > > > Would you mind explaining what you mean exactly? I want to respond but > I'm > > not sure if I fully understand your point here. > > > > > Kieran's criticism is trolling, as Kieran and rest of FFmpeg devs use > regularly and passionately Various Big Corpo products all the time. > > Kieran's criticism is unfounded one. As I, originally 'volunteered' in that > now 'famous' ticket about Certain Big Corpo bug report and kindly replied > in friendly manner to bug reporter and give reporter free support, me still > see no issues in that mine action. > > I strictly do make difference between collective and single specific > person. > Thanks for the clarification, that's a level of nuance I did not grasp. > > > > Also as someone who had to maintain a Gitlab instance at uni for a > > > couple of years, I agree with Rémi's points > > > > > > > My initial contribution was motivated by the argument presented in the > > original talk that bringing new blood is critical to the survival of the > > project. > > > > Projects go and die, and new ones rise up, all the time. > > > > > > If so, then I do believe that there must be a compromise to be made > between > > being easier to join for new developers and changing the existing > workflow. > > I'm also aware that changing the existing workflow has been discussed > > before. > > > > I don't think that media is not cool anymore, as argued in the talk. I > see > > a _lot_ of interested developers in my other projects and all over the > open > > source landscape. That's why I believe that it's also important to > consider > > other reasons than the talk's argument. > > > > Being someone actually trying to contribute, with years of developers > > experience and involvement in other communities, I was thinking that I > may > > be able to bring in more new context to the topic. > > > > If there's interest in continuing the discussion, could you or Rémi be > > willing to explain what kind of burden gitlab would add? > > > > Infrastructure maintenance, no volunteers for gitlab repo admin. > Extra steps to setup account and X-factor authentication. > > You have a little bit of a bias issue here I believe. :-) If you restrict the contributors only to people who can do git send-email and irc then, of course, you won't find many volunteers to maintain a gitlab repo. And, of course, the majority of the people voicing their opinion will be in favor of what they're already familiar with. There's always a learning curve to adopting new tools. Matter of fact, I'm old enough to remember myself complaining about git when it was taking over SVN.. > > > > Also, Rémi said this would make it harder to join the project, in which > way > > exactly? > > > > Otherwise, I'm happy to let this die and return to trying to get my patch > > com
Re: [FFmpeg-devel] Query from Reuters on XZ, open source, and Microsoft
[Apologies for continuing the conversation, Rémi] Le mar. 9 avr. 2024 à 14:05, Tomas Härdin a écrit : > mån 2024-04-08 klockan 13:13 -0500 skrev Romain Beauxis: > > On Wed, Apr 3, 2024, 11:39 Kieran Kunhya via ffmpeg-devel < > > ffmpeg-devel@ffmpeg.org> wrote: > > > > > Hi Raphael, > > > > > > I was the author of the tweet and I gave a short talk about this > > > topic at > > > Demuxed at a video conference last year: > > > https://m.youtube.com/watch?v=OIyOEuQQsCQ=930s > > > > > > That said this is a community project and it would be best to > > > continue the > > > discussion on this mailing list unless agreed otherwise. > > > > > > > Thank you for sharing your talk. It's indeed unfortunate that large > > companies are not more generous with the projects they depend on > > _heavily_ > > > > I would like to offer a constructive feedback really not intended as > > trolling. I believe that supporting a more modern development > > workflow such > > as the GitHub PR or gitlab MR would go very long way in helping > > onboarding > > new developers. > > Considering which company owns GitHub and which company was the target > of Kieran's criticism, this seems ill-adviced > Would you mind explaining what you mean exactly? I want to respond but I'm not sure if I fully understand your point here. > Also as someone who had to maintain a Gitlab instance at uni for a > couple of years, I agree with Rémi's points > My initial contribution was motivated by the argument presented in the original talk that bringing new blood is critical to the survival of the project. If so, then I do believe that there must be a compromise to be made between being easier to join for new developers and changing the existing workflow. I'm also aware that changing the existing workflow has been discussed before. I don't think that media is not cool anymore, as argued in the talk. I see a _lot_ of interested developers in my other projects and all over the open source landscape. That's why I believe that it's also important to consider other reasons than the talk's argument. Being someone actually trying to contribute, with years of developers experience and involvement in other communities, I was thinking that I may be able to bring in more new context to the topic. If there's interest in continuing the discussion, could you or Rémi be willing to explain what kind of burden gitlab would add? Also, Rémi said this would make it harder to join the project, in which way exactly? Otherwise, I'm happy to let this die and return to trying to get my patch committed.. Thanks, -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] Query from Reuters on XZ, open source, and Microsoft
On Wed, Apr 3, 2024, 11:39 Kieran Kunhya via ffmpeg-devel < ffmpeg-devel@ffmpeg.org> wrote: > Hi Raphael, > > I was the author of the tweet and I gave a short talk about this topic at > Demuxed at a video conference last year: > https://m.youtube.com/watch?v=OIyOEuQQsCQ=930s > > That said this is a community project and it would be best to continue the > discussion on this mailing list unless agreed otherwise. > Thank you for sharing your talk. It's indeed unfortunate that large companies are not more generous with the projects they depend on _heavily_ I would like to offer a constructive feedback really not intended as trolling. I believe that supporting a more modern development workflow such as the GitHub PR or gitlab MR would go very long way in helping onboarding new developers. I have been trying to contribute to the project for perhaps 18 months and, while I think I'm getting better at it, I still find it incredibly complex and hard to ramp up to. The other open source community that I am involved with, the OCaml compiler, moved to GitHub maybe 5/6 years ago and this has really done wonders bringing in new contributors. And, you know, this is a niche compiler that is also not getting much attention from AI/Machine Learning people. > Regards, > Kieran Kunhya > > On Wed, 3 Apr 2024, 16:52 Satter, Raphael (Reuters) via ffmpeg-devel, < > ffmpeg-devel@ffmpeg.org> wrote: > > > Dear FFMPEG community, > > > > This is Raphael Satter, a journalist with Reuters. I saw your thread on X > > about your experience with Microsoft in the context of the XZ story and > > would love to follow up with a few questions. > > > > Is there a good person to talk to? I’m reachable using the details below > > or on Signal/WhatsApp at +1 202 430 9389. > > > > Raphael > > > > raphael.sat...@tr.com > > raphaelsatter.com > > reuters.com/authors/raphael-satter > > > > Thomson Reuters > > 1333 H Street NW > > Washington, DC 20005 > > > > ☎️ +1 202 843-6302 > > > > ___ > > ffmpeg-devel mailing list > > ffmpeg-devel@ffmpeg.org > > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > > > To unsubscribe, visit link above, or email > > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > > > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/2] libavformat/hls.c: support in-stream ID3 metadata update.
Le dim. 7 avr. 2024 à 05:44, Steven Liu a écrit : > Romain Beauxis 于2024年3月26日周二 08:58写道: > > > > This patch adds support for updating HLS metadata passed as ID3 frames. > > > > This seems like a pretty straight-forward improvement. Updating the > > metadaata of the first stream seems to be the mechanism is other places > > in the code and works as expected. > > > > --- > > libavformat/hls.c | 54 --- > > 1 file changed, 32 insertions(+), 22 deletions(-) > > > > diff --git a/libavformat/hls.c b/libavformat/hls.c > > index f6b44c2e35..ba6634d57a 100644 > > --- a/libavformat/hls.c > > +++ b/libavformat/hls.c > > @@ -93,6 +93,12 @@ enum PlaylistType { > > PLS_TYPE_VOD > > }; > > > > +#define ID3_PRIV_OWNER_TS "com.apple.streaming.transportStreamTimestamp" > > +#define ID3_PRIV_OWNER_AUDIO_SETUP > "com.apple.streaming.audioDescription" > > + > > +#define ID3v2_PRIV_OWNER_TS ID3v2_PRIV_METADATA_PREFIX ID3_PRIV_OWNER_TS > > +#define ID3v2_PRIV_OWNER_AUDIO_SETUP ID3v2_PRIV_METADATA_PREFIX > ID3_PRIV_OWNER_AUDIO_SETUP > > + > > /* > > * Each playlist has its own demuxer. If it currently is active, > > * it has an open AVIOContext too, and potentially an AVPacket > > @@ -150,9 +156,7 @@ struct playlist { > > int64_t id3_offset; /* in stream original tb */ > > uint8_t* id3_buf; /* temp buffer for id3 parsing */ > > unsigned int id3_buf_size; > > -AVDictionary *id3_initial; /* data from first id3 tag */ > > -int id3_found; /* ID3 tag found at some point */ > > -int id3_changed; /* ID3 tag data has changed at some point */ > > +AVDictionary *last_id3; /* data from the last id3 tag */ > > ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer > is opened */ > > > > HLSAudioSetupInfo audio_setup_info; > > @@ -270,7 +274,7 @@ static void free_playlist_list(HLSContext *c) > > av_freep(>main_streams); > > av_freep(>renditions); > > av_freep(>id3_buf); > > -av_dict_free(>id3_initial); > > +av_dict_free(>last_id3); > > ff_id3v2_free_extra_meta(>id3_deferred_extra); > > av_freep(>init_sec_buf); > > av_packet_free(>pkt); > > @@ -1083,15 +1087,13 @@ static void parse_id3(AVFormatContext *s, > AVIOContext *pb, > >AVDictionary **metadata, int64_t *dts, > HLSAudioSetupInfo *audio_setup_info, > >ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta > **extra_meta) > > { > > -static const char id3_priv_owner_ts[] = > "com.apple.streaming.transportStreamTimestamp"; > > -static const char id3_priv_owner_audio_setup[] = > "com.apple.streaming.audioDescription"; > > ID3v2ExtraMeta *meta; > > > > ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); > > for (meta = *extra_meta; meta; meta = meta->next) { > > if (!strcmp(meta->tag, "PRIV")) { > > ID3v2ExtraMetaPRIV *priv = >data.priv; > > -if (priv->datasize == 8 && !av_strncasecmp(priv->owner, > id3_priv_owner_ts, 44)) { > > +if (priv->datasize == 8 && !av_strncasecmp(priv->owner, > ID3_PRIV_OWNER_TS, strlen(ID3_PRIV_OWNER_TS))) { > > /* 33-bit MPEG timestamp */ > > int64_t ts = AV_RB64(priv->data); > > av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp > %"PRId64"\n", ts); > > @@ -1099,7 +1101,9 @@ static void parse_id3(AVFormatContext *s, > AVIOContext *pb, > > *dts = ts; > > else > > av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio > timestamp %"PRId64"\n", ts); > > -} else if (priv->datasize >= 8 && > !av_strncasecmp(priv->owner, id3_priv_owner_audio_setup, 36)) { > > +} else if (priv->datasize >= 8 && > > + !av_strncasecmp(priv->owner, > ID3_PRIV_OWNER_AUDIO_SETUP, 36) && > > + audio_setup_info) { > > ff_hls_senc_read_audio_setup_info(audio_setup_info, > priv->data, priv->datasize); > > } > > } else if (!strcmp(meta->tag, "APIC") && apic) > > @@ -1113,9 +1117,10 @@ static int id3_has_changed_values(struct playlist > *pls, AVDictionary *metadata, &g
Re: [FFmpeg-devel] [PATCH 1/2] libavformat/hls.c: support in-stream ID3 metadata update.
On Sun, Mar 31, 2024, 12:46 Romain Beauxis wrote: > > > On Sun, Mar 31, 2024, 05:52 Liu Steven wrote: > >> >> >> > On Mar 29, 2024, at 06:51, Romain Beauxis wrote: >> > >> > On Mon, Mar 25, 2024, 19:58 Romain Beauxis >> wrote: >> > >> >> This patch adds support for updating HLS metadata passed as ID3 frames. >> >> >> >> This seems like a pretty straight-forward improvement. Updating the >> >> metadaata of the first stream seems to be the mechanism is other places >> >> in the code and works as expected. >> >> >> > >> > >> > Hello! >> > >> > Any interest in reviewing this? >> >> Patchset looks good to me, looks better than before patch. >> > > Great! Happy to provide the fate samples too. > > Hi! Any update on this? Let me know if I can do anything to help! > > --- >> >> libavformat/hls.c | 54 --- >> >> 1 file changed, 32 insertions(+), 22 deletions(-) >> >> >> >> diff --git a/libavformat/hls.c b/libavformat/hls.c >> >> index f6b44c2e35..ba6634d57a 100644 >> >> --- a/libavformat/hls.c >> >> +++ b/libavformat/hls.c >> >> @@ -93,6 +93,12 @@ enum PlaylistType { >> >> PLS_TYPE_VOD >> >> }; >> >> >> >> +#define ID3_PRIV_OWNER_TS >> "com.apple.streaming.transportStreamTimestamp" >> >> +#define ID3_PRIV_OWNER_AUDIO_SETUP >> "com.apple.streaming.audioDescription" >> >> + >> >> +#define ID3v2_PRIV_OWNER_TS ID3v2_PRIV_METADATA_PREFIX >> ID3_PRIV_OWNER_TS >> >> +#define ID3v2_PRIV_OWNER_AUDIO_SETUP ID3v2_PRIV_METADATA_PREFIX >> >> ID3_PRIV_OWNER_AUDIO_SETUP >> >> + >> >> /* >> >> * Each playlist has its own demuxer. If it currently is active, >> >> * it has an open AVIOContext too, and potentially an AVPacket >> >> @@ -150,9 +156,7 @@ struct playlist { >> >> int64_t id3_offset; /* in stream original tb */ >> >> uint8_t* id3_buf; /* temp buffer for id3 parsing */ >> >> unsigned int id3_buf_size; >> >> -AVDictionary *id3_initial; /* data from first id3 tag */ >> >> -int id3_found; /* ID3 tag found at some point */ >> >> -int id3_changed; /* ID3 tag data has changed at some point */ >> >> +AVDictionary *last_id3; /* data from the last id3 tag */ >> >> ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer >> >> is opened */ >> >> >> >> HLSAudioSetupInfo audio_setup_info; >> >> @@ -270,7 +274,7 @@ static void free_playlist_list(HLSContext *c) >> >> av_freep(>main_streams); >> >> av_freep(>renditions); >> >> av_freep(>id3_buf); >> >> -av_dict_free(>id3_initial); >> >> +av_dict_free(>last_id3); >> >> ff_id3v2_free_extra_meta(>id3_deferred_extra); >> >> av_freep(>init_sec_buf); >> >> av_packet_free(>pkt); >> >> @@ -1083,15 +1087,13 @@ static void parse_id3(AVFormatContext *s, >> >> AVIOContext *pb, >> >> AVDictionary **metadata, int64_t *dts, >> >> HLSAudioSetupInfo *audio_setup_info, >> >> ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta >> >> **extra_meta) >> >> { >> >> -static const char id3_priv_owner_ts[] = >> >> "com.apple.streaming.transportStreamTimestamp"; >> >> -static const char id3_priv_owner_audio_setup[] = >> >> "com.apple.streaming.audioDescription"; >> >> ID3v2ExtraMeta *meta; >> >> >> >> ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); >> >> for (meta = *extra_meta; meta; meta = meta->next) { >> >> if (!strcmp(meta->tag, "PRIV")) { >> >> ID3v2ExtraMetaPRIV *priv = >data.priv; >> >> -if (priv->datasize == 8 && !av_strncasecmp(priv->owner, >> >> id3_priv_owner_ts, 44)) { >> >> +if (priv->datasize == 8 && !av_strncasecmp(priv->owner, >> >> ID3_PRIV_OWNER_TS, strlen(ID3_PRIV_OWNER_TS))) { >> >> /* 33-bit MPEG timestamp */ >> >> int64_t ts = AV_RB64(priv->data); >> >>
Re: [FFmpeg-devel] [PATCH 1/2] libavformat/hls.c: support in-stream ID3 metadata update.
On Sun, Mar 31, 2024, 05:52 Liu Steven wrote: > > > > On Mar 29, 2024, at 06:51, Romain Beauxis wrote: > > > > On Mon, Mar 25, 2024, 19:58 Romain Beauxis wrote: > > > >> This patch adds support for updating HLS metadata passed as ID3 frames. > >> > >> This seems like a pretty straight-forward improvement. Updating the > >> metadaata of the first stream seems to be the mechanism is other places > >> in the code and works as expected. > >> > > > > > > Hello! > > > > Any interest in reviewing this? > > Patchset looks good to me, looks better than before patch. > Great! Happy to provide the fate samples too. > --- > >> libavformat/hls.c | 54 --- > >> 1 file changed, 32 insertions(+), 22 deletions(-) > >> > >> diff --git a/libavformat/hls.c b/libavformat/hls.c > >> index f6b44c2e35..ba6634d57a 100644 > >> --- a/libavformat/hls.c > >> +++ b/libavformat/hls.c > >> @@ -93,6 +93,12 @@ enum PlaylistType { > >> PLS_TYPE_VOD > >> }; > >> > >> +#define ID3_PRIV_OWNER_TS > "com.apple.streaming.transportStreamTimestamp" > >> +#define ID3_PRIV_OWNER_AUDIO_SETUP > "com.apple.streaming.audioDescription" > >> + > >> +#define ID3v2_PRIV_OWNER_TS ID3v2_PRIV_METADATA_PREFIX > ID3_PRIV_OWNER_TS > >> +#define ID3v2_PRIV_OWNER_AUDIO_SETUP ID3v2_PRIV_METADATA_PREFIX > >> ID3_PRIV_OWNER_AUDIO_SETUP > >> + > >> /* > >> * Each playlist has its own demuxer. If it currently is active, > >> * it has an open AVIOContext too, and potentially an AVPacket > >> @@ -150,9 +156,7 @@ struct playlist { > >> int64_t id3_offset; /* in stream original tb */ > >> uint8_t* id3_buf; /* temp buffer for id3 parsing */ > >> unsigned int id3_buf_size; > >> -AVDictionary *id3_initial; /* data from first id3 tag */ > >> -int id3_found; /* ID3 tag found at some point */ > >> -int id3_changed; /* ID3 tag data has changed at some point */ > >> +AVDictionary *last_id3; /* data from the last id3 tag */ > >> ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer > >> is opened */ > >> > >> HLSAudioSetupInfo audio_setup_info; > >> @@ -270,7 +274,7 @@ static void free_playlist_list(HLSContext *c) > >> av_freep(>main_streams); > >> av_freep(>renditions); > >> av_freep(>id3_buf); > >> -av_dict_free(>id3_initial); > >> +av_dict_free(>last_id3); > >> ff_id3v2_free_extra_meta(>id3_deferred_extra); > >> av_freep(>init_sec_buf); > >> av_packet_free(>pkt); > >> @@ -1083,15 +1087,13 @@ static void parse_id3(AVFormatContext *s, > >> AVIOContext *pb, > >> AVDictionary **metadata, int64_t *dts, > >> HLSAudioSetupInfo *audio_setup_info, > >> ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta > >> **extra_meta) > >> { > >> -static const char id3_priv_owner_ts[] = > >> "com.apple.streaming.transportStreamTimestamp"; > >> -static const char id3_priv_owner_audio_setup[] = > >> "com.apple.streaming.audioDescription"; > >> ID3v2ExtraMeta *meta; > >> > >> ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); > >> for (meta = *extra_meta; meta; meta = meta->next) { > >> if (!strcmp(meta->tag, "PRIV")) { > >> ID3v2ExtraMetaPRIV *priv = >data.priv; > >> -if (priv->datasize == 8 && !av_strncasecmp(priv->owner, > >> id3_priv_owner_ts, 44)) { > >> +if (priv->datasize == 8 && !av_strncasecmp(priv->owner, > >> ID3_PRIV_OWNER_TS, strlen(ID3_PRIV_OWNER_TS))) { > >> /* 33-bit MPEG timestamp */ > >> int64_t ts = AV_RB64(priv->data); > >> av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp > >> %"PRId64"\n", ts); > >> @@ -1099,7 +1101,9 @@ static void parse_id3(AVFormatContext *s, > >> AVIOContext *pb, > >> *dts = ts; > >> else > >> av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio > >> timestamp %"PRId64"\n", ts); > >> -} else if (priv->datasize >=
Re: [FFmpeg-devel] [PATCH 1/2] libavformat/hls.c: support in-stream ID3 metadata update.
On Mon, Mar 25, 2024, 19:58 Romain Beauxis wrote: > This patch adds support for updating HLS metadata passed as ID3 frames. > > This seems like a pretty straight-forward improvement. Updating the > metadaata of the first stream seems to be the mechanism is other places > in the code and works as expected. > Hello! Any interest in reviewing this? --- > libavformat/hls.c | 54 --- > 1 file changed, 32 insertions(+), 22 deletions(-) > > diff --git a/libavformat/hls.c b/libavformat/hls.c > index f6b44c2e35..ba6634d57a 100644 > --- a/libavformat/hls.c > +++ b/libavformat/hls.c > @@ -93,6 +93,12 @@ enum PlaylistType { > PLS_TYPE_VOD > }; > > +#define ID3_PRIV_OWNER_TS "com.apple.streaming.transportStreamTimestamp" > +#define ID3_PRIV_OWNER_AUDIO_SETUP "com.apple.streaming.audioDescription" > + > +#define ID3v2_PRIV_OWNER_TS ID3v2_PRIV_METADATA_PREFIX ID3_PRIV_OWNER_TS > +#define ID3v2_PRIV_OWNER_AUDIO_SETUP ID3v2_PRIV_METADATA_PREFIX > ID3_PRIV_OWNER_AUDIO_SETUP > + > /* > * Each playlist has its own demuxer. If it currently is active, > * it has an open AVIOContext too, and potentially an AVPacket > @@ -150,9 +156,7 @@ struct playlist { > int64_t id3_offset; /* in stream original tb */ > uint8_t* id3_buf; /* temp buffer for id3 parsing */ > unsigned int id3_buf_size; > -AVDictionary *id3_initial; /* data from first id3 tag */ > -int id3_found; /* ID3 tag found at some point */ > -int id3_changed; /* ID3 tag data has changed at some point */ > +AVDictionary *last_id3; /* data from the last id3 tag */ > ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer > is opened */ > > HLSAudioSetupInfo audio_setup_info; > @@ -270,7 +274,7 @@ static void free_playlist_list(HLSContext *c) > av_freep(>main_streams); > av_freep(>renditions); > av_freep(>id3_buf); > -av_dict_free(>id3_initial); > +av_dict_free(>last_id3); > ff_id3v2_free_extra_meta(>id3_deferred_extra); > av_freep(>init_sec_buf); > av_packet_free(>pkt); > @@ -1083,15 +1087,13 @@ static void parse_id3(AVFormatContext *s, > AVIOContext *pb, >AVDictionary **metadata, int64_t *dts, > HLSAudioSetupInfo *audio_setup_info, >ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta > **extra_meta) > { > -static const char id3_priv_owner_ts[] = > "com.apple.streaming.transportStreamTimestamp"; > -static const char id3_priv_owner_audio_setup[] = > "com.apple.streaming.audioDescription"; > ID3v2ExtraMeta *meta; > > ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); > for (meta = *extra_meta; meta; meta = meta->next) { > if (!strcmp(meta->tag, "PRIV")) { > ID3v2ExtraMetaPRIV *priv = >data.priv; > -if (priv->datasize == 8 && !av_strncasecmp(priv->owner, > id3_priv_owner_ts, 44)) { > +if (priv->datasize == 8 && !av_strncasecmp(priv->owner, > ID3_PRIV_OWNER_TS, strlen(ID3_PRIV_OWNER_TS))) { > /* 33-bit MPEG timestamp */ > int64_t ts = AV_RB64(priv->data); > av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp > %"PRId64"\n", ts); > @@ -1099,7 +1101,9 @@ static void parse_id3(AVFormatContext *s, > AVIOContext *pb, > *dts = ts; > else > av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio > timestamp %"PRId64"\n", ts); > -} else if (priv->datasize >= 8 && > !av_strncasecmp(priv->owner, id3_priv_owner_audio_setup, 36)) { > +} else if (priv->datasize >= 8 && > + !av_strncasecmp(priv->owner, > ID3_PRIV_OWNER_AUDIO_SETUP, 36) && > + audio_setup_info) { > ff_hls_senc_read_audio_setup_info(audio_setup_info, > priv->data, priv->datasize); > } > } else if (!strcmp(meta->tag, "APIC") && apic) > @@ -1113,9 +1117,10 @@ static int id3_has_changed_values(struct playlist > *pls, AVDictionary *metadata, > { > const AVDictionaryEntry *entry = NULL; > const AVDictionaryEntry *oldentry; > + > /* check that no keys have changed values */ > while ((entry = av_dict_iterate(metadata, entry))) { > -oldentry = av_dict_get(pls->id3_initial, entry->key, NULL, > AV_DICT_MATCH_CASE); > +oldentry = av_dict_get(pls->last_id3, entry-
[FFmpeg-devel] [PATCH 2/2] Add fate test for hls metadata update.
This patch adds a FATE test for the new HLS metadata update. The fate sample consists of a two segment AAC hls stream. The first segment has test title 1 as title metadata while the second has test title 2. In the log, we can see that test title 2 is reported for the stream, indicating that the metadata was updated with the second segment. Romain --- tests/fate/demux.mak | 3 + tests/ref/fate/hls-adts-meta-demux | 124 + 2 files changed, 127 insertions(+) create mode 100644 tests/ref/fate/hls-adts-meta-demux diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index d9b9045f0b..7243c2c163 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -160,6 +160,9 @@ fate-ts-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/ac3/mp3ac325-4864-small.ts FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-timed-id3-demux fate-ts-timed-id3-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/mpegts/id3.ts +FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-hls-adts-meta-demux +fate-fate-hls-adts-meta-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/hls-adts-meta/stream.m3u8 + FATE_SAMPLES_DEMUX += $(FATE_SAMPLES_DEMUX-yes) FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_DEMUX) FATE_FFPROBE_DEMUX += $(FATE_FFPROBE_DEMUX-yes) diff --git a/tests/ref/fate/hls-adts-meta-demux b/tests/ref/fate/hls-adts-meta-demux new file mode 100644 index 00..ab944695fc --- /dev/null +++ b/tests/ref/fate/hls-adts-meta-demux @@ -0,0 +1,124 @@ +packet|codec_type=audio|stream_index=0|pts=3416400|pts_time=37.96|dts=3416400|dts_time=37.96|duration=2090|duration_time=0.023222|size=368|pos=0|flags=K__|data_hash=CRC32:c371b0d9 +packet|codec_type=audio|stream_index=0|pts=3418490|pts_time=37.983222|dts=3418490|dts_time=37.983222|duration=2090|duration_time=0.023222|size=390|pos=368|flags=K__|data_hash=CRC32:950c52b2 +packet|codec_type=audio|stream_index=0|pts=3420580|pts_time=38.006444|dts=3420580|dts_time=38.006444|duration=2090|duration_time=0.023222|size=357|pos=758|flags=K__|data_hash=CRC32:3e672212 +packet|codec_type=audio|stream_index=0|pts=3422669|pts_time=38.029656|dts=3422669|dts_time=38.029656|duration=2090|duration_time=0.023222|size=426|pos=1115|flags=K__|data_hash=CRC32:817b6e4c +packet|codec_type=audio|stream_index=0|pts=3424759|pts_time=38.052878|dts=3424759|dts_time=38.052878|duration=2090|duration_time=0.023222|size=368|pos=1541|flags=K__|data_hash=CRC32:c4c6e1ed +packet|codec_type=audio|stream_index=0|pts=3426849|pts_time=38.076100|dts=3426849|dts_time=38.076100|duration=2090|duration_time=0.023222|size=389|pos=1909|flags=K__|data_hash=CRC32:67cb6dd9 +packet|codec_type=audio|stream_index=0|pts=3428939|pts_time=38.099322|dts=3428939|dts_time=38.099322|duration=2090|duration_time=0.023222|size=352|pos=2298|flags=K__|data_hash=CRC32:7a56ff53 +packet|codec_type=audio|stream_index=0|pts=3431029|pts_time=38.122544|dts=3431029|dts_time=38.122544|duration=2090|duration_time=0.023222|size=378|pos=2650|flags=K__|data_hash=CRC32:f8d5ef58 +packet|codec_type=audio|stream_index=0|pts=3433118|pts_time=38.145756|dts=3433118|dts_time=38.145756|duration=2090|duration_time=0.023222|size=384|pos=3028|flags=K__|data_hash=CRC32:73a4fb1c +packet|codec_type=audio|stream_index=0|pts=3435208|pts_time=38.168978|dts=3435208|dts_time=38.168978|duration=2090|duration_time=0.023222|size=353|pos=3412|flags=K__|data_hash=CRC32:4ea999b5 +packet|codec_type=audio|stream_index=0|pts=3437298|pts_time=38.192200|dts=3437298|dts_time=38.192200|duration=2090|duration_time=0.023222|size=417|pos=3765|flags=K__|data_hash=CRC32:4540aec8 +packet|codec_type=audio|stream_index=0|pts=3439388|pts_time=38.215422|dts=3439388|dts_time=38.215422|duration=2090|duration_time=0.023222|size=361|pos=4182|flags=K__|data_hash=CRC32:635a04f4 +packet|codec_type=audio|stream_index=0|pts=3441478|pts_time=38.238644|dts=3441478|dts_time=38.238644|duration=2090|duration_time=0.023222|size=399|pos=4543|flags=K__|data_hash=CRC32:94583c18 +packet|codec_type=audio|stream_index=0|pts=3443567|pts_time=38.261856|dts=3443567|dts_time=38.261856|duration=2090|duration_time=0.023222|size=384|pos=4942|flags=K__|data_hash=CRC32:21070d79 +packet|codec_type=audio|stream_index=0|pts=3445657|pts_time=38.285078|dts=3445657|dts_time=38.285078|duration=2090|duration_time=0.023222|size=378|pos=5326|flags=K__|data_hash=CRC32:bd5beb97 +packet|codec_type=audio|stream_index=0|pts=3447747|pts_time=38.308300|dts=3447747|dts_time=38.308300|duration=2090|duration_time=0.023222|size=362|pos=5704|flags=K__|data_hash=CRC32:8bb15fb7 +packet|codec_type=audio|stream_index=0|pts=3449837|pts_time=38.331522|dts=3449837|dts_time=38.331522|duration=2090|duration_time=0.023222|size=365|pos=6066|flags=K__|data_hash=CRC32:a1801ece +packet|codec_type=audio|stream_index=0|pts=3451927|pts_time=38.354744|dts=3451927|dts_time=38.354744|duration=2090|duration_time=0.023222|size=390|pos=6431|flags=K__|data_hash=CRC32:8eb3880b
[FFmpeg-devel] [PATCH 1/2] libavformat/hls.c: support in-stream ID3 metadata update.
This patch adds support for updating HLS metadata passed as ID3 frames. This seems like a pretty straight-forward improvement. Updating the metadaata of the first stream seems to be the mechanism is other places in the code and works as expected. --- libavformat/hls.c | 54 --- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index f6b44c2e35..ba6634d57a 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -93,6 +93,12 @@ enum PlaylistType { PLS_TYPE_VOD }; +#define ID3_PRIV_OWNER_TS "com.apple.streaming.transportStreamTimestamp" +#define ID3_PRIV_OWNER_AUDIO_SETUP "com.apple.streaming.audioDescription" + +#define ID3v2_PRIV_OWNER_TS ID3v2_PRIV_METADATA_PREFIX ID3_PRIV_OWNER_TS +#define ID3v2_PRIV_OWNER_AUDIO_SETUP ID3v2_PRIV_METADATA_PREFIX ID3_PRIV_OWNER_AUDIO_SETUP + /* * Each playlist has its own demuxer. If it currently is active, * it has an open AVIOContext too, and potentially an AVPacket @@ -150,9 +156,7 @@ struct playlist { int64_t id3_offset; /* in stream original tb */ uint8_t* id3_buf; /* temp buffer for id3 parsing */ unsigned int id3_buf_size; -AVDictionary *id3_initial; /* data from first id3 tag */ -int id3_found; /* ID3 tag found at some point */ -int id3_changed; /* ID3 tag data has changed at some point */ +AVDictionary *last_id3; /* data from the last id3 tag */ ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer is opened */ HLSAudioSetupInfo audio_setup_info; @@ -270,7 +274,7 @@ static void free_playlist_list(HLSContext *c) av_freep(>main_streams); av_freep(>renditions); av_freep(>id3_buf); -av_dict_free(>id3_initial); +av_dict_free(>last_id3); ff_id3v2_free_extra_meta(>id3_deferred_extra); av_freep(>init_sec_buf); av_packet_free(>pkt); @@ -1083,15 +1087,13 @@ static void parse_id3(AVFormatContext *s, AVIOContext *pb, AVDictionary **metadata, int64_t *dts, HLSAudioSetupInfo *audio_setup_info, ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta **extra_meta) { -static const char id3_priv_owner_ts[] = "com.apple.streaming.transportStreamTimestamp"; -static const char id3_priv_owner_audio_setup[] = "com.apple.streaming.audioDescription"; ID3v2ExtraMeta *meta; ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta); for (meta = *extra_meta; meta; meta = meta->next) { if (!strcmp(meta->tag, "PRIV")) { ID3v2ExtraMetaPRIV *priv = >data.priv; -if (priv->datasize == 8 && !av_strncasecmp(priv->owner, id3_priv_owner_ts, 44)) { +if (priv->datasize == 8 && !av_strncasecmp(priv->owner, ID3_PRIV_OWNER_TS, strlen(ID3_PRIV_OWNER_TS))) { /* 33-bit MPEG timestamp */ int64_t ts = AV_RB64(priv->data); av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp %"PRId64"\n", ts); @@ -1099,7 +1101,9 @@ static void parse_id3(AVFormatContext *s, AVIOContext *pb, *dts = ts; else av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio timestamp %"PRId64"\n", ts); -} else if (priv->datasize >= 8 && !av_strncasecmp(priv->owner, id3_priv_owner_audio_setup, 36)) { +} else if (priv->datasize >= 8 && + !av_strncasecmp(priv->owner, ID3_PRIV_OWNER_AUDIO_SETUP, 36) && + audio_setup_info) { ff_hls_senc_read_audio_setup_info(audio_setup_info, priv->data, priv->datasize); } } else if (!strcmp(meta->tag, "APIC") && apic) @@ -1113,9 +1117,10 @@ static int id3_has_changed_values(struct playlist *pls, AVDictionary *metadata, { const AVDictionaryEntry *entry = NULL; const AVDictionaryEntry *oldentry; + /* check that no keys have changed values */ while ((entry = av_dict_iterate(metadata, entry))) { -oldentry = av_dict_get(pls->id3_initial, entry->key, NULL, AV_DICT_MATCH_CASE); +oldentry = av_dict_get(pls->last_id3, entry->key, NULL, AV_DICT_MATCH_CASE); if (!oldentry || strcmp(oldentry->value, entry->value) != 0) return 1; } @@ -1143,35 +1148,40 @@ static void handle_id3(AVIOContext *pb, struct playlist *pls) ID3v2ExtraMetaAPIC *apic = NULL; ID3v2ExtraMeta *extra_meta = NULL; int64_t timestamp = AV_NOPTS_VALUE; +// Only set audio_setup_info on first id3 chunk. +HLSAudioSetupInfo *audio_setup_info = pls->last_id3 ? NULL : >audio_setup_info; -parse_id3(pls->ctx, pb, , , >audio_setup_info, , _meta); +parse_id3(pls->ctx, pb, , , audio_setup_info, , _meta); -if (timestamp != AV_NOPTS_VALUE) { +if (pls->id3_mpegts_timestamp == AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) { pls->id3_mpegts_timestamp = timestamp; pls->id3_offset = 0;
Re: [FFmpeg-devel] [PATCH] Set native order for wav channel layouts up until 8 channels.
Le sam. 24 févr. 2024 à 19:27, Michael Niedermayer a écrit : > > On Fri, Feb 23, 2024 at 02:41:06PM -0600, Romain Beauxis wrote: > > The new default channel layout for the various RIFF/WAV decoders is not > > backward compatible. > > > > Historically, most decoders will expect the channel layouts to follow > > the native layout up-to a reasonable number of channels. > > > > Additionally, non-native layouts are causing troubles with filters > > chaining. > > > > This PR changes the default channel layout reported by RIFF/WAV decoders > > to default to the native layout when the number of channels is up-to 8. > > > > The logic for these changes is the same as the logic for the vorbis/opus > > decoders. > > > > Romain > > breaks fate > make -j32 fate-flcl1905 > TESTflcl1905 > --- ./tests/ref/fate/flcl1905 2024-02-09 03:32:32.540199565 +0100 > +++ tests/data/fate/flcl19052024-02-25 02:26:51.079111678 +0100 > @@ -1,192 +1,192 @@ > > packet|codec_type=audio|stream_index=0|pts=0|pts_time=0.00|dts=0|dts_time=0.00|duration=22528|duration_time=0.510839|size=4092|pos=56|flags=K__ > -frame|media_type=audio|stream_index=0|key_frame=1|pts=N/A|pts_time=N/A|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=N/A|best_effort_timestamp_time=N/A|pkt_duration=22528|pkt_duration_time=0.510839|duration=22528|duration_time=0.510839|pkt_pos=56|pkt_size=4092|sample_fmt=fltp|nb_samples=2048|channels=2|channel_layout=unknown > -frame|media_type=audio|stream_index=0|key_frame=1|pts=N/A|pts_time=N/A|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=N/A|best_effort_timestamp_time=N/A|pkt_duration=22528|pkt_duration_time=0.510839|duration=22528|duration_time=0.510839|pkt_pos=56|pkt_size=4092|sample_fmt=fltp|nb_samples=2048|channels=2|channel_layout=unknown > -frame|media_type=audio|stream_index=0|key_frame=1|pts=N/A|pts_time=N/A|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=N/A|best_effort_timestamp_time=N/A|pkt_duration=22528|pkt_duration_time=0.510839|duration=22528|duration_time=0.510839|pkt_pos=56|pkt_size=4092|sample_fmt=fltp|nb_samples=2048|channels=2|channel_layout=unknown > ... Thanks. I did more backward compatibility tests and I might have jumped the gun on it as well. I'll check again and will come back to it if I can confirm anything. -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] Set native order for wav channel layouts up until 8 channels.
Le ven. 23 févr. 2024 à 15:11, Marton Balint a écrit : > > > > On Fri, 23 Feb 2024, Romain Beauxis wrote: > > > The new default channel layout for the various RIFF/WAV decoders is not > > backward compatible. > > > > Historically, most decoders will expect the channel layouts to follow > > the native layout up-to a reasonable number of channels. > > > > Additionally, non-native layouts are causing troubles with filters > > chaining. > > > > This PR changes the default channel layout reported by RIFF/WAV decoders > > to default to the native layout when the number of channels is up-to 8. > > > > The logic for these changes is the same as the logic for the vorbis/opus > > decoders. > > For Vorbis the channel layout is in the actual Vorbis specification. So > you should follow the specification, simple guessing in the demuxer likely > won't be acceptable. I would argue that even though there is no official specification on channel layout for wav/riff, the de-facto assumption that _most_ users of the library would expect is the native layout. Typically, 1 and 2 channels would be assumed to be mono and stereo by most users. It's great that the API does provide flexibility but the default should be set to satisfy most users and, in that regard, it seems that assuming a native layout is what the vast majority of library's users will expect. This choice also implies at least two ABI breakage for applications using the deprecated API but running on a the new ABI: 1: With the updated API, the library is not able to provide a backward compatible `channel_layout` for AVFrame when the new channel order is AV_CHANNEL_ORDER_UNSPEC which breaks ABI compatibility as the field is reported as `0`. 2. AV_CHANNEL_ORDER_UNSPEC channel order also breaks filters chaining. The issue appears to be that the unspec channel order implicitly sets the the filter to accept all channel order, which breaks compatibility here: if (link->incfg.channel_layouts->all_layouts) { av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for" " the link between filters %s and %s.\n", link->src->name, link->dst->name); if (!link->incfg.channel_layouts->all_counts) av_log(link->src, AV_LOG_ERROR, "Unknown channel layouts not " "supported, try specifying a channel layout using " "'aformat=channel_layouts=something'.\n"); return AVERROR(EINVAL); } -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] Set native order for wav channel layouts up until 8 channels.
The new default channel layout for the various RIFF/WAV decoders is not backward compatible. Historically, most decoders will expect the channel layouts to follow the native layout up-to a reasonable number of channels. Additionally, non-native layouts are causing troubles with filters chaining. This PR changes the default channel layout reported by RIFF/WAV decoders to default to the native layout when the number of channels is up-to 8. The logic for these changes is the same as the logic for the vorbis/opus decoders. Romain --- libavformat/riff.h| 1 + libavformat/riffdec.c | 31 --- libavformat/wavdec.c | 4 +--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/libavformat/riff.h b/libavformat/riff.h index a93eadfeca..f474efdce9 100644 --- a/libavformat/riff.h +++ b/libavformat/riff.h @@ -67,6 +67,7 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecParameters *par, int for_asf, int int ff_put_wav_header(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par, int flags); enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps); +void ff_get_wav_ch_layout(AVChannelLayout *ch_layout, int channels); int ff_get_wav_header(void *logctx, AVIOContext *pb, AVCodecParameters *par, int size, int big_endian); diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c index 0fe4e02b7b..bb7c01c5f5 100644 --- a/libavformat/riffdec.c +++ b/libavformat/riffdec.c @@ -90,6 +90,33 @@ static void parse_waveformatex(void *logctx, AVIOContext *pb, AVCodecParameters } } +const AVChannelLayout ff_wav_demux_ch_layouts[9] = { +AV_CHANNEL_LAYOUT_MONO, +AV_CHANNEL_LAYOUT_STEREO, +AV_CHANNEL_LAYOUT_SURROUND, +AV_CHANNEL_LAYOUT_QUAD, +AV_CHANNEL_LAYOUT_5POINT0_BACK, +AV_CHANNEL_LAYOUT_5POINT1_BACK, +{ +.nb_channels = 7, +.order = AV_CHANNEL_ORDER_NATIVE, +.u.mask = AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER, +}, +AV_CHANNEL_LAYOUT_7POINT1, +{ 0 } +}; + +void ff_get_wav_ch_layout(AVChannelLayout *ch_layout, int channels) +{ +av_channel_layout_uninit(ch_layout); +if (channels > 8) { +ch_layout->order = AV_CHANNEL_ORDER_UNSPEC; +ch_layout->nb_channels = channels; +} else { +av_channel_layout_copy(ch_layout, _wav_demux_ch_layouts[channels - 1]); +} +} + /* "big_endian" values are needed for RIFX file format */ int ff_get_wav_header(void *logctx, AVIOContext *pb, AVCodecParameters *par, int size, int big_endian) @@ -195,9 +222,7 @@ int ff_get_wav_header(void *logctx, AVIOContext *pb, /* ignore WAVEFORMATEXTENSIBLE layout if different from channel count */ if (channels != par->ch_layout.nb_channels) { -av_channel_layout_uninit(>ch_layout); -par->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; -par->ch_layout.nb_channels = channels; +ff_get_wav_ch_layout(>ch_layout, channels); } return 0; diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index 0c6629b157..282e1ae017 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -222,9 +222,7 @@ static int wav_parse_xma2_tag(AVFormatContext *s, int64_t size, AVStream *st) channels += avio_r8(pb); avio_skip(pb, 3); } -av_channel_layout_uninit(>codecpar->ch_layout); -st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; -st->codecpar->ch_layout.nb_channels = channels; +ff_get_wav_ch_layout(>codecpar->ch_layout, channels); if (st->codecpar->ch_layout.nb_channels <= 0 || st->codecpar->sample_rate <= 0) return AVERROR_INVALIDDATA; -- 2.39.3 (Apple Git-145) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] FFmpeg 6.1.1
Le jeu. 21 déc. 2023 à 13:17, Michael Niedermayer a écrit : > > Hi all > > I will probably make a 6.1.1 release in maybe 1-3 weeks due to bug/fixes > in it. > if you want something in it, please backport it now! https://ffmpeg.org/pipermail/ffmpeg-devel/2024-January/319173.html could be a good candidate. > thx > > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > If you drop bombs on a foreign country and kill a hundred thousand > innocent people, expect your government to call the consequence > "unprovoked inhuman terrorist attacks" and use it to justify dropping > more bombs and killing more people. The technology changed, the idea is old. > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavformat/hlsenc.c: Populate OTI using AAC profile in write_codec_attr.
Le sam. 30 déc. 2023 à 16:25, David Johansen a écrit : > > On Sat, Dec 30, 2023 at 8:23 AM Romain Beauxis wrote: >> >> Le jeu. 28 déc. 2023 à 17:26, David Johansen a >> écrit : >> >> >> >> I love this change, but it appears that st->codecpar->profile is always >> >> AV_PROFILE_UNKNOWN when using libfdk_aac as the encoder. Any indications >> >> where I should look for fix that so this can be used with that encoder? >> > >> > >> > It appears that the issue is that profile doesn't default to what's being >> > used so `--profile:a` has to be set explicitly with libfdk_aac and then it >> > works. Not sure if that's an issue worth fixing, but if someone points me >> > to where it needs to be done, then I'd be glad to take a look at fixing it >> >> This feels like a second, separate issue to me? >> >> Maybe we could get these changes in first and then tackle it? > > > But this is technically a breaking change, because it takes commands/uses > that currently work and changes them to no longer include CODECS since the > profile value is unknown by default Ha gotcha. Yes, in this case we do need to send the previous value as fallback when the profile is unknown. Just sent an updated patch! -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v2] libavformat/hlsenc.c: Populate OTI using AAC profile in write_codec_attr.
This patch populates the third entry for HLS codec attribute using the AAC profile. The HLS specifications[1] require this value to be the Object Type ID as referred to in table 1.3 of ISO/IEC 14496-3:2009[2]. The numerical constants in the code refer to these OTIs minus one, as documented in commit 372597e[3], confirmed by comparing the values in the code with the values in the table mentioned above. Links: 1: https://datatracker.ietf.org/doc/html/rfc6381#section-3.3 2: https://csclub.uwaterloo.ca/~ehashman/ISO14496-3-2009.pdf 3: https://github.com/FFmpeg/FFmpeg/commit/372597e5381c097455a7b73849254d56083eb056 Changes in this version: - Default value set to "mp4a.40.2" when profile is unknown for backward compatibility. --- libavformat/hlsenc.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 7049956dd7..55123d2297 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -418,8 +418,11 @@ static void write_codec_attr(AVStream *st, VariantStream *vs) } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) { snprintf(attr, sizeof(attr), "mp4a.40.34"); } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { -/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 and 29 respectively */ -snprintf(attr, sizeof(attr), "mp4a.40.2"); +if (st->codecpar->profile != AV_PROFILE_UNKNOWN) +snprintf(attr, sizeof(attr), "mp4a.40.%d", st->codecpar->profile+1); +else +// This is for backward compatibility with the previous implementation. +snprintf(attr, sizeof(attr), "mp4a.40.2"); } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { snprintf(attr, sizeof(attr), "ac-3"); } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) { -- 2.39.3 (Apple Git-145) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavformat/hlsenc.c: Populate OTI using AAC profile in write_codec_attr.
Le jeu. 28 déc. 2023 à 17:26, David Johansen a écrit : >> >> I love this change, but it appears that st->codecpar->profile is always >> AV_PROFILE_UNKNOWN when using libfdk_aac as the encoder. Any indications >> where I should look for fix that so this can be used with that encoder? > > > It appears that the issue is that profile doesn't default to what's being > used so `--profile:a` has to be set explicitly with libfdk_aac and then it > works. Not sure if that's an issue worth fixing, but if someone points me to > where it needs to be done, then I'd be glad to take a look at fixing it This feels like a second, separate issue to me? Maybe we could get these changes in first and then tackle it? -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavformat/hlsenc.c: Populate OTI using AAC profile in write_codec_attr.
Hey there! Le ven. 22 déc. 2023 à 09:09, Romain Beauxis a écrit : > > This patch populates the third entry for HLS codec attribute using the > AAC profile. > > The HLS specifications[1] require this digit to be the Object Type ID as > referred to in table 1.3 of ISO/IEC 14496-3:2009[2]. > > The numerical constants in the code refer to these OTIs minus one, as > documented in commit 372597e[3], confirmed by comparing the values in the > code with the values in the table mentioned above. > > Links: > 1: https://datatracker.ietf.org/doc/html/rfc6381#section-3.3 > 2: https://csclub.uwaterloo.ca/~ehashman/ISO14496-3-2009.pdf > 3: > https://github.com/FFmpeg/FFmpeg/commit/372597e5381c097455a7b73849254d56083eb056 Anyone interested? I think that this is a pretty straight-forward change that could potentially qualify as a bugfix for 6.1.1, after all, this generates incorrect HLS playlist descriptions.. -- Romain > --- > libavformat/hlsenc.c | 6 -- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c > index 7049956dd7..2551bac6ae 100644 > --- a/libavformat/hlsenc.c > +++ b/libavformat/hlsenc.c > @@ -418,8 +418,10 @@ static void write_codec_attr(AVStream *st, VariantStream > *vs) > } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) { > snprintf(attr, sizeof(attr), "mp4a.40.34"); > } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { > -/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 > and 29 respectively */ > -snprintf(attr, sizeof(attr), "mp4a.40.2"); > +if (st->codecpar->profile != AV_PROFILE_UNKNOWN) > +snprintf(attr, sizeof(attr), "mp4a.40.%d", > st->codecpar->profile+1); > +else > +goto fail; > } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { > snprintf(attr, sizeof(attr), "ac-3"); > } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) { > -- > 2.39.3 (Apple Git-145) > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] libavformat/hlsenc.c: Populate OTI using AAC profile in write_codec_attr.
This patch populates the third entry for HLS codec attribute using the AAC profile. The HLS specifications[1] require this digit to be the Object Type ID as referred to in table 1.3 of ISO/IEC 14496-3:2009[2]. The numerical constants in the code refer to these OTIs minus one, as documeted in commit 372597e[3], confirmed by comparing the values in the code with the values in the table mentioned above. Links: 1: https://datatracker.ietf.org/doc/html/rfc6381#section-3.3 2: https://csclub.uwaterloo.ca/~ehashman/ISO14496-3-2009.pdf 3: https://github.com/FFmpeg/FFmpeg/commit/372597e5381c097455a7b73849254d56083eb056 --- libavformat/hlsenc.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 7049956dd7..2551bac6ae 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -418,8 +418,10 @@ static void write_codec_attr(AVStream *st, VariantStream *vs) } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) { snprintf(attr, sizeof(attr), "mp4a.40.34"); } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { -/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 and 29 respectively */ -snprintf(attr, sizeof(attr), "mp4a.40.2"); +if (st->codecpar->profile != AV_PROFILE_UNKNOWN) +snprintf(attr, sizeof(attr), "mp4a.40.%d", st->codecpar->profile+1); +else +goto fail; } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { snprintf(attr, sizeof(attr), "ac-3"); } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) { -- 2.39.3 (Apple Git-145) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2 2/6] libavformat/sdp: remove whitespaces in fmtp
Le mar. 14 nov. 2023 à 09:47, Tomas Härdin a écrit : > > tis 2023-11-07 klockan 15:12 +0100 skrev Michael Riedl: > > Whitespaces after semicolon breaks some servers > > Which servers? If the spec allows whitespace then the onus is on them > to fix their implementations. The logic could be inverted: if the specs allow for both but a majority of users do not accept white space, it would make sense to change the implementation to maximize compatibility. > /Tomas > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v2] Extract av_hls_codec_attr
Le ven. 3 nov. 2023 à 03:00, Andreas Rheinhardt a écrit : > > Romain Beauxis: > > The logic for extracting HLS codec attribute strings is very useful and > > can be re-used in many different situations when working with HLS > > streams using libavcodec/libavformat. > > > > This patch extracts the function's code and places it into a publicly > > available function. > > > > Differences since v1: > > - ff_nal_unit_extract_rbsp renamed into avpriv_nal_unit_extract_rbsp to > > follow the appropriate library cross-linking convention. > > > > --- > > libavcodec/Makefile | 2 + > > libavcodec/hls.c | 105 +++ > > libavcodec/hls.h | 42 + > > libavformat/avc.c| 4 +- > > libavformat/avc.h| 2 +- > > libavformat/hevc.c | 2 +- > > libavformat/hlsenc.c | 83 +++--- > > 7 files changed, 159 insertions(+), 81 deletions(-) > > create mode 100644 libavcodec/hls.c > > create mode 100644 libavcodec/hls.h > > > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > > index 580a8d6b54..b3b2b18980 100644 > > --- a/libavcodec/Makefile > > +++ b/libavcodec/Makefile > > @@ -16,6 +16,7 @@ HEADERS = ac3_parser.h > > \ > >dirac.h \ > >dv_profile.h \ > >dxva2.h \ > > + hls.h \ > >jni.h \ > >mediacodec.h \ > >packet.h \ > > @@ -47,6 +48,7 @@ OBJS = ac3_parser.o > > \ > > get_buffer.o \ > > imgconvert.o \ > > jni.o\ > > + hls.o\ > > mathtables.o \ > > mediacodec.o \ > > mpeg12framerate.o\ > > diff --git a/libavcodec/hls.c b/libavcodec/hls.c > > new file mode 100644 > > index 00..05a6277dbc > > --- /dev/null > > +++ b/libavcodec/hls.c > > @@ -0,0 +1,105 @@ > > +/* > > + * HLS public API > > + * > > + * This file is part of FFmpeg. > > + * > > + * FFmpeg is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU Lesser General Public > > + * License as published by the Free Software Foundation; either > > + * version 2.1 of the License, or (at your option) any later version. > > + * > > + * FFmpeg is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * Lesser General Public License for more details. > > + * > > + * You should have received a copy of the GNU Lesser General Public > > + * License along with FFmpeg; if not, write to the Free Software > > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > > 02110-1301 USA > > + */ > > + > > +#include "hls.h" > > +#include "libavutil/intreadwrite.h" > > +#include "libavformat/avc.h" > > + > > +int av_hls_codec_attr(AVStream *st, char *attr, size_t attr_len) { > > + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { > > + uint8_t *data = st->codecpar->extradata; > > + if (data) { > > + const uint8_t *p; > > + > > + if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7) > > + p = [5]; > > + else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7) > > + p = [4]; > > + else if (data[0] == 0x01) /* avcC */ > > + p = [1]; > > + else > > + return AVERROR_INVALIDDATA; > > + snprintf(attr, attr_len, > > + "avc1.%02x%02x%02x", p[0], p[1], p[2]); > &
[FFmpeg-devel] [PATCH v3] Extract av_hls_codec_attr
The logic for extracting HLS codec attribute strings is very useful and can be re-used in many different situations when working with HLS streams using libavcodec/libavformat. This patch extracts the function's code and places it into a publicly available function. Differences since v2: - Shared function moved to libavformat, ff_nal_unit_extract_rbsp function kept identical. --- libavformat/Makefile| 2 + libavformat/hls_utils.c | 105 libavformat/hls_utils.h | 42 libavformat/hlsenc.c| 83 +++ 4 files changed, 155 insertions(+), 77 deletions(-) create mode 100644 libavformat/hls_utils.c create mode 100644 libavformat/hls_utils.h diff --git a/libavformat/Makefile b/libavformat/Makefile index 329055ccfd..5e148e5bbc 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -3,6 +3,7 @@ DESC = FFmpeg container format library HEADERS = avformat.h\ avio.h\ + hls_utils.h \ version.h \ version_major.h \ @@ -15,6 +16,7 @@ OBJS = allformats.o \ dump.o \ dv.o \ format.o \ + hls_utils.o \ id3v1.o \ id3v2.o \ isom_tags.o \ diff --git a/libavformat/hls_utils.c b/libavformat/hls_utils.c new file mode 100644 index 00..df45fbc1a4 --- /dev/null +++ b/libavformat/hls_utils.c @@ -0,0 +1,105 @@ +/* + * HLS public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hls_utils.h" +#include "libavutil/intreadwrite.h" +#include "avc.h" + +int av_hls_codec_attr(AVStream *st, char *attr, size_t attr_len) { + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { + uint8_t *data = st->codecpar->extradata; + if (data) { + const uint8_t *p; + + if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7) + p = [5]; + else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7) + p = [4]; + else if (data[0] == 0x01) /* avcC */ + p = [1]; + else + return AVERROR_INVALIDDATA; + snprintf(attr, attr_len, + "avc1.%02x%02x%02x", p[0], p[1], p[2]); + } else { + return AVERROR_INVALIDDATA; + } + } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) { + uint8_t *data = st->codecpar->extradata; + int profile = AV_PROFILE_UNKNOWN; + int level = AV_LEVEL_UNKNOWN; + + if (st->codecpar->profile != AV_PROFILE_UNKNOWN) + profile = st->codecpar->profile; + if (st->codecpar->level != AV_LEVEL_UNKNOWN) + level = st->codecpar->level; + + /* check the boundary of data which from current position is small than extradata_size */ + while (data && (data - st->codecpar->extradata + 19) < st->codecpar->extradata_size) { + /* get HEVC SPS NAL and seek to profile_tier_level */ + if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) { + uint8_t *rbsp_buf; + int remain_size = 0; + int rbsp_size = 0; + /* skip start code + nalu header */ + data += 6; + /* process by reference General NAL unit syntax */ + remain_size = st->codecpar->extradata_size - (data - st->codecpar->extradata); + rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, _size, 0); + if (!rbsp_buf) + return AVERROR_INVALIDDATA; + if (rbsp_size < 13) { + av_freep(_buf); + break; + } + /* skip sps_video_parameter_set_id u(4), + * sps_max_sub_layers_minus1u(3), + * and sps_temporal_id_nesting_flag u(1) */ + profile = rbsp_buf[1] & 0x1f; + /* skip 8 + 8 + 32 + 4 + 43 + 1 bit */ + level =
Re: [FFmpeg-devel] [PATCH] Extract av_hls_codec_attr
Le mar. 31 oct. 2023 à 11:47, Zhao Zhili a écrit : > > > > From: ffmpeg-devel On Behalf Of Romain > > Beauxis > > Sent: 2023年10月30日 9:06 > > To: ffmpeg-devel@ffmpeg.org > > Cc: Romain Beauxis > > Subject: [FFmpeg-devel] [PATCH] Extract av_hls_codec_attr > > > > The logic for extracting HLS codec attribute strings is very useful and > > can be re-used in many different situations when working with HLS > > streams using libavcodec/libavformat. > > > > This patch extracts the function's code and places it into a publicly > > available function. > > I don't think the implementation is complete enough to be exported as > an API. And the ad-hoc API needs some design too. I am not in a position to dispute this assessment but I would say it could be a "build it and they will come" kind of situation (or chicken and egg too). > > > > --- > > libavcodec/Makefile | 2 + > > libavcodec/hls.c | 105 +++ > > libavcodec/hls.h | 42 + > > libavformat/hlsenc.c | 83 +++--- > > 4 files changed, 155 insertions(+), 77 deletions(-) > > create mode 100644 libavcodec/hls.c > > create mode 100644 libavcodec/hls.h > > > > > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] Extract av_hls_codec_attr
Le mar. 31 oct. 2023 à 08:28, Michael Niedermayer a écrit : > > On Sun, Oct 29, 2023 at 08:05:50PM -0500, Romain Beauxis wrote: > > The logic for extracting HLS codec attribute strings is very useful and > > can be re-used in many different situations when working with HLS > > streams using libavcodec/libavformat. > > > > This patch extracts the function's code and places it into a publicly > > available function. > > > > --- > > libavcodec/Makefile | 2 + > > libavcodec/hls.c | 105 +++ > > libavcodec/hls.h | 42 + > > libavformat/hlsenc.c | 83 +++--- > > you cannot call ff_* functions across libs > > they need to start with av* / avpriv* Thanks for the review! Updated patch submitted. > [...] > > + rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, > > _size, 0); > > libavcodec/libavcodec.so: undefined reference to `ff_nal_unit_extract_rbsp' > clang: error: linker command failed with exit code 1 (use -v to see > invocation) > Makefile:133: recipe for target 'ffmpeg_g' failed > make: *** [ffmpeg_g] Error 1 > make: *** Waiting for unfinished jobs > libavcodec/libavcodec.so: undefined reference to `ff_nal_unit_extract_rbsp' > clang: error: linker command failed with exit code 1 (use -v to see > invocation) > Makefile:133: recipe for target 'ffplay_g' failed > make: *** [ffplay_g] Error 1 > > thx > > [...] > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > If a bugfix only changes things apparently unrelated to the bug with no > further explanation, that is a good sign that the bugfix is wrong. > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v2] Extract av_hls_codec_attr
The logic for extracting HLS codec attribute strings is very useful and can be re-used in many different situations when working with HLS streams using libavcodec/libavformat. This patch extracts the function's code and places it into a publicly available function. Differences since v1: - ff_nal_unit_extract_rbsp renamed into avpriv_nal_unit_extract_rbsp to follow the appropriate library cross-linking convention. --- libavcodec/Makefile | 2 + libavcodec/hls.c | 105 +++ libavcodec/hls.h | 42 + libavformat/avc.c| 4 +- libavformat/avc.h| 2 +- libavformat/hevc.c | 2 +- libavformat/hlsenc.c | 83 +++--- 7 files changed, 159 insertions(+), 81 deletions(-) create mode 100644 libavcodec/hls.c create mode 100644 libavcodec/hls.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 580a8d6b54..b3b2b18980 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -16,6 +16,7 @@ HEADERS = ac3_parser.h \ dirac.h \ dv_profile.h \ dxva2.h \ + hls.h \ jni.h \ mediacodec.h \ packet.h \ @@ -47,6 +48,7 @@ OBJS = ac3_parser.o \ get_buffer.o \ imgconvert.o \ jni.o\ + hls.o\ mathtables.o \ mediacodec.o \ mpeg12framerate.o\ diff --git a/libavcodec/hls.c b/libavcodec/hls.c new file mode 100644 index 00..05a6277dbc --- /dev/null +++ b/libavcodec/hls.c @@ -0,0 +1,105 @@ +/* + * HLS public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hls.h" +#include "libavutil/intreadwrite.h" +#include "libavformat/avc.h" + +int av_hls_codec_attr(AVStream *st, char *attr, size_t attr_len) { + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { + uint8_t *data = st->codecpar->extradata; + if (data) { + const uint8_t *p; + + if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7) + p = [5]; + else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7) + p = [4]; + else if (data[0] == 0x01) /* avcC */ + p = [1]; + else + return AVERROR_INVALIDDATA; + snprintf(attr, attr_len, + "avc1.%02x%02x%02x", p[0], p[1], p[2]); + } else { + return AVERROR_INVALIDDATA; + } + } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) { + uint8_t *data = st->codecpar->extradata; + int profile = AV_PROFILE_UNKNOWN; + int level = AV_LEVEL_UNKNOWN; + + if (st->codecpar->profile != AV_PROFILE_UNKNOWN) + profile = st->codecpar->profile; + if (st->codecpar->level != AV_LEVEL_UNKNOWN) + level = st->codecpar->level; + + /* check the boundary of data which from current position is small than extradata_size */ + while (data && (data - st->codecpar->extradata + 19) < st->codecpar->extradata_size) { + /* get HEVC SPS NAL and seek to profile_tier_level */ + if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) { + uint8_t *rbsp_buf; + int remain_size = 0; + int rbsp_size = 0; + /* skip start code + nalu header */ + data += 6; + /* process by reference General NAL unit syntax */ + remain_size =
[FFmpeg-devel] [PATCH] Extract av_hls_codec_attr
The logic for extracting HLS codec attribute strings is very useful and can be re-used in many different situations when working with HLS streams using libavcodec/libavformat. This patch extracts the function's code and places it into a publicly available function. --- libavcodec/Makefile | 2 + libavcodec/hls.c | 105 +++ libavcodec/hls.h | 42 + libavformat/hlsenc.c | 83 +++--- 4 files changed, 155 insertions(+), 77 deletions(-) create mode 100644 libavcodec/hls.c create mode 100644 libavcodec/hls.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 580a8d6b54..b3b2b18980 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -16,6 +16,7 @@ HEADERS = ac3_parser.h \ dirac.h \ dv_profile.h \ dxva2.h \ + hls.h \ jni.h \ mediacodec.h \ packet.h \ @@ -47,6 +48,7 @@ OBJS = ac3_parser.o \ get_buffer.o \ imgconvert.o \ jni.o\ + hls.o\ mathtables.o \ mediacodec.o \ mpeg12framerate.o\ diff --git a/libavcodec/hls.c b/libavcodec/hls.c new file mode 100644 index 00..59ab0c4819 --- /dev/null +++ b/libavcodec/hls.c @@ -0,0 +1,105 @@ +/* + * HLS public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hls.h" +#include "libavutil/intreadwrite.h" +#include "libavformat/avc.h" + +int av_hls_codec_attr(AVStream *st, char *attr, size_t attr_len) { + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { + uint8_t *data = st->codecpar->extradata; + if (data) { + const uint8_t *p; + + if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7) + p = [5]; + else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7) + p = [4]; + else if (data[0] == 0x01) /* avcC */ + p = [1]; + else + return AVERROR_INVALIDDATA; + snprintf(attr, attr_len, + "avc1.%02x%02x%02x", p[0], p[1], p[2]); + } else { + return AVERROR_INVALIDDATA; + } + } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) { + uint8_t *data = st->codecpar->extradata; + int profile = AV_PROFILE_UNKNOWN; + int level = AV_LEVEL_UNKNOWN; + + if (st->codecpar->profile != AV_PROFILE_UNKNOWN) + profile = st->codecpar->profile; + if (st->codecpar->level != AV_LEVEL_UNKNOWN) + level = st->codecpar->level; + + /* check the boundary of data which from current position is small than extradata_size */ + while (data && (data - st->codecpar->extradata + 19) < st->codecpar->extradata_size) { + /* get HEVC SPS NAL and seek to profile_tier_level */ + if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) { + uint8_t *rbsp_buf; + int remain_size = 0; + int rbsp_size = 0; + /* skip start code + nalu header */ + data += 6; + /* process by reference General NAL unit syntax */ + remain_size = st->codecpar->extradata_size - (data - st->codecpar->extradata); + rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, _size, 0); + if (!rbsp_buf) + return AVERROR_INVALIDDATA; + if (rbsp_size < 13)
Re: [FFmpeg-devel] [PATCH] libavformat/mpegts.c: fix hardcoded 5-bytes skip for metadata streams.
Le sam. 24 juin 2023 à 05:51, Thilo Borgmann a écrit : > > Am 24.06.23 um 12:43 schrieb Anton Khirnov: > > Quoting Romain Beauxis (2023-06-22 16:19:36) > >> commit ca0472eeebe478b7eb6e7d1dc4351037f8811728 > >> Author: Romain Beauxis > >> Date: Thu Jun 22 09:14:18 2023 -0500 > >> > >> Add FATE test for timed id3 demux. > >> > >> diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak > >> index d8fc68af88..ace8fa0b52 100644 > >> --- a/tests/fate/demux.mak > >> +++ b/tests/fate/demux.mak > >> @@ -157,6 +157,9 @@ fate-xwma-demux: CMD = crc -i $(TARGET_SAMPLES)/xwma/ergon.xwma -c:a copy > >> FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-demux > >> fate-ts-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/ac3/mp3ac325-4864-small.ts > >> > >> +FATE_FFPROBE_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-timed-id3-demux > >> +fate-ts-timed-id3-demux: CMD = ffprobe_demux $(TARGET_SAMPLES)/mpegts/id3.ts > >> + > >> FATE_SAMPLES_DEMUX += $(FATE_SAMPLES_DEMUX-yes) > >> FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_DEMUX) > >> FATE_FFPROBE_DEMUX += $(FATE_FFPROBE_DEMUX-yes) > >> diff --git a/tests/ref/fate/ts-timed-id3-demux b/tests/ref/fate/ts-timed-id3-demux > >> new file mode 100644 > >> index 00..922ca17d15 > >> --- /dev/null > >> +++ b/tests/ref/fate/ts-timed-id3-demux > >> @@ -0,0 +1,6 @@ > >> +packet|codec_type=data|stream_index=0|pts=126000|pts_time=1.40|dts=126000|dts_time=1.40|duration=N/A|duration_time=N/A|size=26|pos=564|flags=K__|data_hash=CRC32:469f474b|side_data|side_data_type=MPEGTS Stream ID|id=189 > >> + > >> +packet|codec_type=data|stream_index=0|pts=577350|pts_time=6.415000|dts=577350|dts_time=6.415000|duration=N/A|duration_time=N/A|size=26|pos=1316|flags=K__|data_hash=CRC32:469f474b|side_data|side_data_type=MPEGTS Stream ID|id=189 > >> + > >> +stream|index=0|codec_name=timed_id3|profile=unknown|codec_type=data|codec_tag_string=ID3 |codec_tag=0x20334449|ts_packetsize=188|id=0x100|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/9|start_pts=126000|start_time=1.40|duration_ts=451350|duration=5.015000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=2|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 > >> +format|filename=id3.ts|nb_streams=1|nb_programs=1|format_name=mpegts|start_time=1.40|duration=5.015000|size=1504|bit_rate=2399|probe_score=2 > > > > Looks good, can someone please put the sample in place? > > Done. > > 4200d5ad77c2495255742248cbfd69c3 fate-suite/mpegts/id3.ts Thanks! I guess we still need someone's help pushing the patch adding the test to the main repo. > -Thilo > > ___ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavformat/mpegts.c: fix hardcoded 5-bytes skip for metadata streams.
Le mer. 21 juin 2023 à 03:32, Anton Khirnov a écrit : > > Quoting to...@rastageeks.org (2023-06-20 07:09:33) > > From: Romain Beauxis > > > > Before the introduction of AV_CODEC_ID_TIMED_ID3 for timed_id3 metadata streams > > in mpegts (commit 4a4437c0fbc8f7afe0c533070395a42e56b4ee75), AV_CODEC_ID_SMPTE_KLV > > was the only existing codec for metadata. > > > > It seems that this codec has a 5-bytes metadata header[1] that, for some reason, > > was always skipped when decoding data packets. > > > > However, when working with a AV_CODEC_ID_TIMED_ID3 streams, this results in the > > 5 first bytes of the payload being cut-off, which includes essential informations > > such as the ID3 tag version. > > > > This patch fixes the issue by keeping the 5-bytes skip only for AV_CODEC_ID_SMPTE_KLV > > streams. > > > > To test: > > 1. download this file: https://www.dropbox.com/s/jy8sih3pe8qskxb/bla.ts?dl=1 > > > > This file was download from: http://playertest.longtailvideo.com/adaptive/wowzaid3/playlist.m3u8 > > > > 2. run this command: > > ffprobe -show_streams -select_streams 0 -show_packets -show_private_data \ > > -show_data /path/to/bla.ts > > > > Before: > > [PACKET] > > codec_type=data > > stream_index=0 > > pts=494646418 > > pts_time=5496.071311 > > dts=494646418 > > dts_time=5496.071311 > > duration=N/A > > duration_time=N/A > > size=21 > > pos=482784 > > flags=K__ > > data= > > : 1054 4954 3200 0600 0003 .TIT2... > > 0010: 7465 7374 00 test. > > > > After: > > [PACKET] > > codec_type=data > > stream_index=0 > > pts=494646418 > > pts_time=5496.071311 > > dts=494646418 > > dts_time=5496.071311 > > duration=N/A > > duration_time=N/A > > size=26 > > pos=482784 > > flags=K__ > > data= > > : 4944 3304 0010 5449 5432 ID3...TIT2.. > > 0010: 0006 0374 6573 7400 .test. > > A FATE test for this would be nice. Here's a patch attached, along with the sample that should go into fate-suite/mpegts/id3.ts The output has been verified with a local ffprobe build: packet|codec_type=data|stream_index=0|pts=126000|pts_time=1.40|dts=126000|dts_time=1.40|duration=N/A|duration_time=N/A|size=26|pos=564|flags=K__|data=\n: 4944 3304 0010 5449 5432 ID3...TIT2..\n0010: 0006 0374 6573 7400 .test.\n|side_data|side_data_type=MPEGTS Stream ID|id=189 packet|codec_type=data|stream_index=0|pts=577350|pts_time=6.415000|dts=577350|dts_time=6.415000|duration=N/A|duration_time=N/A|size=26|pos=1316|flags=K__|data=\n: 4944 3304 0010 5449 5432 ID3...TIT2..\n0010: 0006 0374 6573 7400 .test.\n|side_data|side_data_type=MPEGTS Stream ID|id=189 stream|index=0|codec_name=timed_id3|profile=unknown|codec_type=data|codec_tag_string=ID3 |codec_tag=0x20334449|ts_packetsize=188|id=0x100|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/9|start_pts=126000|start_time=1.40|duration_ts=451350|duration=5.015000|bit_rate=N/A|max_bit_rate=N/A|bits_per_raw_sample=N/A|nb_frames=N/A|nb_read_frames=N/A|nb_read_packets=2|extradata=\n|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|disposition:captions=0|disposition:descriptions=0|disposition:metadata=0|disposition:dependent=0|disposition:still_image=0 format|filename=id3.ts|nb_streams=1|nb_programs=1|format_name=mpegts|start_time=1.40|duration=5.015000|size=1504|bit_rate=2399|probe_score=2 > -- > Anton Khirnov timed_id3_fate_test.patch Description: Binary data id3.ts Description: Binary data ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavformat/mpegts.c: fix hardcoded 5-bytes skip for metadata streams.
Le mar. 20 juin 2023 à 02:10, Paul B Mahol a écrit : > > > > On Tue, Jun 20, 2023 at 7:19 AM wrote: >> >> From: Romain Beauxis >> >> Before the introduction of AV_CODEC_ID_TIMED_ID3 for timed_id3 metadata streams >> in mpegts (commit 4a4437c0fbc8f7afe0c533070395a42e56b4ee75), AV_CODEC_ID_SMPTE_KLV >> was the only existing codec for metadata. >> >> It seems that this codec has a 5-bytes metadata header[1] that, for some reason, >> was always skipped when decoding data packets. >> >> However, when working with a AV_CODEC_ID_TIMED_ID3 streams, this results in the >> 5 first bytes of the payload being cut-off, which includes essential informations >> such as the ID3 tag version. >> >> This patch fixes the issue by keeping the 5-bytes skip only for AV_CODEC_ID_SMPTE_KLV >> streams. >> >> To test: >> 1. download this file: https://www.dropbox.com/s/jy8sih3pe8qskxb/bla.ts?dl=1 >> >> This file was download from: http://playertest.longtailvideo.com/adaptive/wowzaid3/playlist.m3u8 >> >> 2. run this command: >> ffprobe -show_streams -select_streams 0 -show_packets -show_private_data \ >> -show_data /path/to/bla.ts >> >> Before: >> [PACKET] >> codec_type=data >> stream_index=0 >> pts=494646418 >> pts_time=5496.071311 >> dts=494646418 >> dts_time=5496.071311 >> duration=N/A >> duration_time=N/A >> size=21 >> pos=482784 >> flags=K__ >> data= >> : 1054 4954 3200 0600 0003 .TIT2... >> 0010: 7465 7374 00 test. >> >> After: >> [PACKET] >> codec_type=data >> stream_index=0 >> pts=494646418 >> pts_time=5496.071311 >> dts=494646418 >> dts_time=5496.071311 >> duration=N/A >> duration_time=N/A >> size=26 >> pos=482784 >> flags=K__ >> data= >> : 4944 3304 0010 5449 5432 ID3...TIT2.. >> 0010: 0006 0374 6573 7400 .test. >> >> --- >> libavformat/mpegts.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c >> index fb8b0bf8fd..0b3edda817 100644 >> --- a/libavformat/mpegts.c >> +++ b/libavformat/mpegts.c >> @@ -1305,7 +1305,7 @@ skip: >> p += sl_header_bytes; >> buf_size -= sl_header_bytes; >> } >> -if (pes->stream_type == 0x15 && buf_size >= 5) { >> +if (pes->st->codecpar->codec_id == AV_CODEC_ID_SMPTE_KLV && buf_size >= 5) { >> /* skip metadata access unit header */ >> pes->pes_header_size += 5; >> p += 5; >> -- >> 2.39.2 (Apple Git-143) > > > LGTM Great, thanks! Anything I can do to help move this to the finish line? Thanks, -- Romain >> >> >> ___ >> ffmpeg-devel mailing list >> ffmpeg-devel@ffmpeg.org >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> >> To unsubscribe, visit link above, or email >> ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v3 2/2] libavformat/oggparseopus: Clear existing stream metadata before parsing potentially new one. Fixes: #10363
Hello again! I wanted to see if there was any interest in this patch and the other one adding metadata decoding for chained ogg bitstream. These two feel like easy bugfixes and features to add to the next release. Reproduction steps for this one are detailed here: https://trac.ffmpeg.org/ticket/10363 -- Romain Le dim. 14 mai 2023 à 16:42, a écrit : > From: Romain Beauxis > > This is the third version of a series of patches improving metadata > support in > chained ogg streams. > > Previous versions of this patch were including changes that were later > identified as issues from another encoded and fixed there. See: > https://github.com/savonet/liquidsoap/pull/3062 > > The remaining changes address a memory leak in chained ogg/opus stream > metadata. Reproduction steps for the issue are detailed in: > https://trac.ffmpeg.org/ticket/10363 > > --- > libavformat/oggparseopus.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c > index 54aa725be6..86977b41db 100644 > --- a/libavformat/oggparseopus.c > +++ b/libavformat/oggparseopus.c > @@ -80,6 +80,7 @@ static int opus_header(AVFormatContext *avf, int idx) > if (priv->need_comments) { > if (os->psize < 8 || memcmp(packet, "OpusTags", 8)) > return AVERROR_INVALIDDATA; > +av_dict_free(>metadata); > ff_vorbis_stream_comment(avf, st, packet + 8, os->psize - 8); > priv->need_comments--; > return 1; > -- > 2.37.1 (Apple Git-137.1) > > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v3 1/2] libavformat/oggparseflac: Decode metadata packets. Fixes: #10364
Le dim. 14 mai 2023 à 16:40, a écrit : > > From: Romain Beauxis > > This is the third version on a series of patches improving ffmpeg support for > ogg chained streams. > > Reproduction steps for the issue fixed with patch are included in this bug > report: https://trac.ffmpeg.org/ticket/10363 Sorry correct link is: https://trac.ffmpeg.org/ticket/10364 > > --- > libavformat/oggparseflac.c | 20 > 1 file changed, 20 insertions(+) > > diff --git a/libavformat/oggparseflac.c b/libavformat/oggparseflac.c > index eef6e09927..1dd292483d 100644 > --- a/libavformat/oggparseflac.c > +++ b/libavformat/oggparseflac.c > @@ -126,10 +126,30 @@ fail: > return ret; > } > > +static int flac_packet(AVFormatContext *s, int idx) > +{ > +struct ogg *ogg = s->priv_data; > +struct ogg_stream *os = ogg->streams + idx; > +int ret; > + > +if (os->psize > 4 && (*(os->buf + os->pstart) & 0x7F) == > FLAC_METADATA_TYPE_VORBIS_COMMENT) { > +AVStream *st = s->streams[idx]; > +av_dict_free(>metadata); > +ret = ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 4, > + os->psize - 4); > + > +if (ret < 0) return ret; > +} > + > +return 0; > +} > + > + > const struct ogg_codec ff_flac_codec = { > .magic = "\177FLAC", > .magicsize = 5, > .header = flac_header, > +.packet = flac_packet, > .nb_header = 2, > }; > > -- > 2.37.1 (Apple Git-137.1) > ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/4] Use appropriate method for device discovery, fix crash with bogus device index.
Le lun. 31 janv. 2022 à 04:11, Thilo Borgmann a écrit : > > Hi, > > Am 30.01.22 um 18:30 schrieb to...@rastageeks.org: > > From: Romain Beauxis > > > > This updates the code for avfoundation to use modern device lookup APIs and also adds a check to avoid querying the video devices array beyound its maximum size. > > > > --- > > libavdevice/avfoundation.m | 71 ++ > > 1 file changed, 56 insertions(+), 15 deletions(-) > > > > diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m > > index 0cd6e646d5..d8bcd98f81 100644 > > --- a/libavdevice/avfoundation.m > > +++ b/libavdevice/avfoundation.m > > @@ -27,6 +27,7 @@ > > > > #import > > #include > > +#include > > > > #include "libavutil/channel_layout.h" > > #include "libavutil/pixdesc.h" > > @@ -764,8 +765,34 @@ static int avf_read_header(AVFormatContext *s) > [...] > > the patch doesn't appear to be broken any more, though it does not apply to current HEAD > > Thilos-Mac-mini:FFmpeg borgmann$ git apply ../patches/avfoundation/\[PATCH\ 1_4\]\ Use\ appropriate\ method\ for\ device\ discovery\,\ fix\ crash\ with\ bogus\ device\ index.\ -\ toots\@ rastageeks.org\ -\ 2022-01-30\ 1830.eml > error: patch failed: libavdevice/avfoundation.m:27 > error: libavdevice/avfoundation.m: patch does not apply > > I don't see why it does not apply as the part around line 27 looks sane. Did you try to apply to HEAD? It does seem to apply here: https://patchwork.ffmpeg.org/project/ffmpeg/patch/20220130173045.32690-2-to...@rastageeks.org/ ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 5/5] Add AudioToolbox audio input device.
Le sam. 29 janv. 2022 à 14:42, Andreas Rheinhardt a écrit : > > Romain Beauxis: > > Le mer. 19 janv. 2022 à 10:59, Marvin Scholz a écrit : > >> > >> > >> > >> On 19 Jan 2022, at 15:42, Romain Beauxis wrote: > >> > >> Hi, thanks for the patch. I've not done a full code review yet, just a > >> few > >> initial remarks below: > >> > >>> This patch adds support for a new, audio-specific input device using > >>> the documented and battle-tested AUHAL input. This provides a pendant > >>> to the AudioToolbox audio-only output. > >>> > >>> A couple of advantages for this: > >>> * It avoids a lot of the complexity of supporting audio and video in a > >>> single input > >>> * The AUHAL API seems tested, documented and robust > >>> * This implementation hopefully gives good control over audio latency > >>> and also minimizes data copy > >>> From: Romain Beauxis > >>> To: ffmpeg-devel@ffmpeg.org > >>> Subject: [PATCH] Add AudioToolbox audio input device. > >>> Date: 18. January 2022 at 23:29 > >>> Signed-off-by: Romain Beauxis > >>> --- > >>> configure | 5 + > >>> doc/indevs.texi| 44 > >>> libavdevice/Makefile | 1 + > >>> libavdevice/alldevices.c | 1 + > >>> libavdevice/audiotoolbox_dec.m | 466 > >>> + > >>> 5 files changed, 517 insertions(+) > >>> create mode 100644 libavdevice/audiotoolbox_dec.m > >>> > >>> diff --git a/configure b/configure > >>> index 1413122d87..80e39aae44 100755 > >>> --- a/configure > >>> +++ b/configure > >>> @@ -204,6 +204,7 @@ External library support: > >>>--disable-avfoundation disable Apple AVFoundation framework > >>> [autodetect] > >>>--enable-avisynthenable reading of AviSynth script files > >>> [no] > >>>--disable-bzlib disable bzlib [autodetect] > >>> + --disable-coremedia disable Apple CoreMedia framework > >>> [autodetect] > >>>--disable-coreimage disable Apple CoreImage framework > >>> [autodetect] > >>>--enable-chromaprint enable audio fingerprinting with > >>> chromaprint [no] > >>>--enable-frei0r enable frei0r video filtering [no] > >>> @@ -1750,6 +1751,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" > >>> appkit > >>> avfoundation > >>> bzlib > >>> +coremedia > >>> coreimage > >>> iconv > >>> libxcb > >>> @@ -3493,6 +3495,8 @@ alsa_outdev_deps="alsa" > >>> avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" > >>> avfoundation_indev_suggest="coregraphics applicationservices" > >>> avfoundation_indev_extralibs="-framework Foundation" > >>> +audiotoolbox_indev_deps="coremedia audiotoolbox" > >>> +audiotoolbox_indev_extralibs="-framework CoreMedia -framework > >>> AudioToolbox" > >>> audiotoolbox_outdev_deps="audiotoolbox pthreads" > >>> audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework > >>> CoreAudio" > >>> bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h > >>> dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" > >>> @@ -6340,6 +6344,7 @@ check_lib camera2ndk "stdbool.h stdint.h > >>> camera/NdkCameraManager.h" ACameraManag > >>> enabled appkit && check_apple_framework AppKit > >>> enabled audiotoolbox && check_apple_framework AudioToolbox > >>> enabled avfoundation && check_apple_framework AVFoundation > >>> +enabled coremedia&& check_apple_framework CoreMedia > >>> enabled coreimage&& check_apple_framework CoreImage > >>> enabled metal&& check_apple_framework Metal > >>> enabled videotoolbox && check_apple_framework VideoToolbox > >>> diff --git a/doc/indevs.texi b/doc/indevs.texi > >>> index 858c0fa4e4..30a91d304f 100644 > >>> --- a/doc/indevs.texi > >>> +++ b/doc/indevs.texi > >>> @@ -103,6 +103,50 @@ Set the maximum number of frames to buffer. > &
Re: [FFmpeg-devel] [PATCH 5/5] Add AudioToolbox audio input device.
Le mer. 19 janv. 2022 à 10:59, Marvin Scholz a écrit : > > > > On 19 Jan 2022, at 15:42, Romain Beauxis wrote: > > Hi, thanks for the patch. I've not done a full code review yet, just a > few > initial remarks below: > > > This patch adds support for a new, audio-specific input device using > > the documented and battle-tested AUHAL input. This provides a pendant > > to the AudioToolbox audio-only output. > > > > A couple of advantages for this: > > * It avoids a lot of the complexity of supporting audio and video in a > > single input > > * The AUHAL API seems tested, documented and robust > > * This implementation hopefully gives good control over audio latency > > and also minimizes data copy > > From: Romain Beauxis > > To: ffmpeg-devel@ffmpeg.org > > Subject: [PATCH] Add AudioToolbox audio input device. > > Date: 18. January 2022 at 23:29 > > Signed-off-by: Romain Beauxis > > --- > > configure | 5 + > > doc/indevs.texi| 44 > > libavdevice/Makefile | 1 + > > libavdevice/alldevices.c | 1 + > > libavdevice/audiotoolbox_dec.m | 466 > > + > > 5 files changed, 517 insertions(+) > > create mode 100644 libavdevice/audiotoolbox_dec.m > > > > diff --git a/configure b/configure > > index 1413122d87..80e39aae44 100755 > > --- a/configure > > +++ b/configure > > @@ -204,6 +204,7 @@ External library support: > >--disable-avfoundation disable Apple AVFoundation framework > > [autodetect] > >--enable-avisynthenable reading of AviSynth script files > > [no] > >--disable-bzlib disable bzlib [autodetect] > > + --disable-coremedia disable Apple CoreMedia framework > > [autodetect] > >--disable-coreimage disable Apple CoreImage framework > > [autodetect] > >--enable-chromaprint enable audio fingerprinting with > > chromaprint [no] > >--enable-frei0r enable frei0r video filtering [no] > > @@ -1750,6 +1751,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" > > appkit > > avfoundation > > bzlib > > +coremedia > > coreimage > > iconv > > libxcb > > @@ -3493,6 +3495,8 @@ alsa_outdev_deps="alsa" > > avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" > > avfoundation_indev_suggest="coregraphics applicationservices" > > avfoundation_indev_extralibs="-framework Foundation" > > +audiotoolbox_indev_deps="coremedia audiotoolbox" > > +audiotoolbox_indev_extralibs="-framework CoreMedia -framework > > AudioToolbox" > > audiotoolbox_outdev_deps="audiotoolbox pthreads" > > audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework > > CoreAudio" > > bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h > > dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" > > @@ -6340,6 +6344,7 @@ check_lib camera2ndk "stdbool.h stdint.h > > camera/NdkCameraManager.h" ACameraManag > > enabled appkit && check_apple_framework AppKit > > enabled audiotoolbox && check_apple_framework AudioToolbox > > enabled avfoundation && check_apple_framework AVFoundation > > +enabled coremedia&& check_apple_framework CoreMedia > > enabled coreimage&& check_apple_framework CoreImage > > enabled metal&& check_apple_framework Metal > > enabled videotoolbox && check_apple_framework VideoToolbox > > diff --git a/doc/indevs.texi b/doc/indevs.texi > > index 858c0fa4e4..30a91d304f 100644 > > --- a/doc/indevs.texi > > +++ b/doc/indevs.texi > > @@ -103,6 +103,50 @@ Set the maximum number of frames to buffer. > > Default is 5. > > > > @end table > > > > +@section AudioToolbox > > + > > +AudioToolbox input device. > > + > > +Allows native input from CoreAudio devices on OSX. > Nit: Nowadays it's macOS instead of OSX > > > + > > +All available devices can be enumerated by using > > @option{-list_devices true}, listing > > +all device names, and corresponding unique ID. > > Instead of adding another device that uses a custom list-devices option, > could you > instead implement the .get_device_list callback? (See alsa or pulse > modules for an > example) Then listing would work properly with the `ffmpeg -sources` > command and > devices could be iterated over using the avdevic
Re: [FFmpeg-devel] [PATCH 5/5] Add AudioToolbox audio input device.
Le lun. 24 janv. 2022 à 10:19, Marvin Scholz a écrit : > > > > On 24 Jan 2022, at 16:42, Romain Beauxis wrote: > > > Hi Marvin, > > > > Le mer. 19 janv. 2022 à 10:59, Marvin Scholz a > > écrit : > >> On 19 Jan 2022, at 15:42, Romain Beauxis wrote: > >> > >> Hi, thanks for the patch. I've not done a full code review yet, just > >> a > >> few > >> initial remarks below: > >> > >>> This patch adds support for a new, audio-specific input device using > >>> the documented and battle-tested AUHAL input. This provides a > >>> pendant > >>> to the AudioToolbox audio-only output. > >>> > >>> A couple of advantages for this: > >>> * It avoids a lot of the complexity of supporting audio and video in > >>> a > >>> single input > >>> * The AUHAL API seems tested, documented and robust > >>> * This implementation hopefully gives good control over audio > >>> latency > >>> and also minimizes data copy > > > > Thanks! > > > > Do you need more time for this review? We discovered another issue > > with the dynamic array of video devices and I'd like to send a revised > > series soon. > > Well if you want to address the things I mentioned last time > it will anyway change a bunch of things probably, so it > might be easier if I just wait for the new patch. > > Additionally it might be useful to send it independent of the > whole patchset as IIUC it does not really depend on any of the > previous patches. Will do, thanks! > > Also, I think I'll reorder the patches so that the most > > trivial one (unique device name, probing API call updates) can be > > applied right away. > > > > Let me know! > > Romain > > > >>> From: Romain Beauxis > >>> To: ffmpeg-devel@ffmpeg.org > >>> Subject: [PATCH] Add AudioToolbox audio input device. > >>> Date: 18. January 2022 at 23:29 > >>> Signed-off-by: Romain Beauxis > >>> --- > >>> configure | 5 + > >>> doc/indevs.texi| 44 > >>> libavdevice/Makefile | 1 + > >>> libavdevice/alldevices.c | 1 + > >>> libavdevice/audiotoolbox_dec.m | 466 > >>> + > >>> 5 files changed, 517 insertions(+) > >>> create mode 100644 libavdevice/audiotoolbox_dec.m > >>> > >>> diff --git a/configure b/configure > >>> index 1413122d87..80e39aae44 100755 > >>> --- a/configure > >>> +++ b/configure > >>> @@ -204,6 +204,7 @@ External library support: > >>>--disable-avfoundation disable Apple AVFoundation framework > >>> [autodetect] > >>>--enable-avisynthenable reading of AviSynth script files > >>> [no] > >>>--disable-bzlib disable bzlib [autodetect] > >>> + --disable-coremedia disable Apple CoreMedia framework > >>> [autodetect] > >>>--disable-coreimage disable Apple CoreImage framework > >>> [autodetect] > >>>--enable-chromaprint enable audio fingerprinting with > >>> chromaprint [no] > >>>--enable-frei0r enable frei0r video filtering [no] > >>> @@ -1750,6 +1751,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" > >>> appkit > >>> avfoundation > >>> bzlib > >>> +coremedia > >>> coreimage > >>> iconv > >>> libxcb > >>> @@ -3493,6 +3495,8 @@ alsa_outdev_deps="alsa" > >>> avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" > >>> avfoundation_indev_suggest="coregraphics applicationservices" > >>> avfoundation_indev_extralibs="-framework Foundation" > >>> +audiotoolbox_indev_deps="coremedia audiotoolbox" > >>> +audiotoolbox_indev_extralibs="-framework CoreMedia -framework > >>> AudioToolbox" > >>> audiotoolbox_outdev_deps="audiotoolbox pthreads" > >>> audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework > >>> CoreAudio" > >>> bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h > >>> dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" > >>> @@ -6340,6 +6344,7 @@ check_lib camera2ndk "stdbool.h stdint.h > >&g
Re: [FFmpeg-devel] [PATCH 5/5] Add AudioToolbox audio input device.
Hi Marvin, Le mer. 19 janv. 2022 à 10:59, Marvin Scholz a écrit : > On 19 Jan 2022, at 15:42, Romain Beauxis wrote: > > Hi, thanks for the patch. I've not done a full code review yet, just a > few > initial remarks below: > > > This patch adds support for a new, audio-specific input device using > > the documented and battle-tested AUHAL input. This provides a pendant > > to the AudioToolbox audio-only output. > > > > A couple of advantages for this: > > * It avoids a lot of the complexity of supporting audio and video in a > > single input > > * The AUHAL API seems tested, documented and robust > > * This implementation hopefully gives good control over audio latency > > and also minimizes data copy Thanks! Do you need more time for this review? We discovered another issue with the dynamic array of video devices and I'd like to send a revised series soon. Also, I think I'll reorder the patches so that the most trivial one (unique device name, probing API call updates) can be applied right away. Let me know! Romain > > From: Romain Beauxis > > To: ffmpeg-devel@ffmpeg.org > > Subject: [PATCH] Add AudioToolbox audio input device. > > Date: 18. January 2022 at 23:29 > > Signed-off-by: Romain Beauxis > > --- > > configure | 5 + > > doc/indevs.texi| 44 > > libavdevice/Makefile | 1 + > > libavdevice/alldevices.c | 1 + > > libavdevice/audiotoolbox_dec.m | 466 > > + > > 5 files changed, 517 insertions(+) > > create mode 100644 libavdevice/audiotoolbox_dec.m > > > > diff --git a/configure b/configure > > index 1413122d87..80e39aae44 100755 > > --- a/configure > > +++ b/configure > > @@ -204,6 +204,7 @@ External library support: > >--disable-avfoundation disable Apple AVFoundation framework > > [autodetect] > >--enable-avisynthenable reading of AviSynth script files > > [no] > >--disable-bzlib disable bzlib [autodetect] > > + --disable-coremedia disable Apple CoreMedia framework > > [autodetect] > >--disable-coreimage disable Apple CoreImage framework > > [autodetect] > >--enable-chromaprint enable audio fingerprinting with > > chromaprint [no] > >--enable-frei0r enable frei0r video filtering [no] > > @@ -1750,6 +1751,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" > > appkit > > avfoundation > > bzlib > > +coremedia > > coreimage > > iconv > > libxcb > > @@ -3493,6 +3495,8 @@ alsa_outdev_deps="alsa" > > avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" > > avfoundation_indev_suggest="coregraphics applicationservices" > > avfoundation_indev_extralibs="-framework Foundation" > > +audiotoolbox_indev_deps="coremedia audiotoolbox" > > +audiotoolbox_indev_extralibs="-framework CoreMedia -framework > > AudioToolbox" > > audiotoolbox_outdev_deps="audiotoolbox pthreads" > > audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework > > CoreAudio" > > bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h > > dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" > > @@ -6340,6 +6344,7 @@ check_lib camera2ndk "stdbool.h stdint.h > > camera/NdkCameraManager.h" ACameraManag > > enabled appkit && check_apple_framework AppKit > > enabled audiotoolbox && check_apple_framework AudioToolbox > > enabled avfoundation && check_apple_framework AVFoundation > > +enabled coremedia&& check_apple_framework CoreMedia > > enabled coreimage&& check_apple_framework CoreImage > > enabled metal&& check_apple_framework Metal > > enabled videotoolbox && check_apple_framework VideoToolbox > > diff --git a/doc/indevs.texi b/doc/indevs.texi > > index 858c0fa4e4..30a91d304f 100644 > > --- a/doc/indevs.texi > > +++ b/doc/indevs.texi > > @@ -103,6 +103,50 @@ Set the maximum number of frames to buffer. > > Default is 5. > > > > @end table > > > > +@section AudioToolbox > > + > > +AudioToolbox input device. > > + > > +Allows native input from CoreAudio devices on OSX. > Nit: Nowadays it's macOS instead of OSX > > > + > > +All available devices can be enumerated by using > > @option{-list_devices true}, listing > > +all device names, and corresponding unique ID. > > Instea
Re: [FFmpeg-devel] [PATCH 1/5] libavdevice/avfoundation.m: use setAudioSettings, extend supported formats
Le mer. 19 janv. 2022 à 09:45, Gyan Doshi a écrit : > On 2022-01-19 08:51 pm, Romain Beauxis wrote: > > Le mer. 19 janv. 2022 à 09:19, Gyan Doshi a écrit : > >> On 2022-01-19 08:44 pm, Romain Beauxis wrote: > >>> Le mer. 19 janv. 2022 à 08:31, Gyan Doshi a écrit : > >>>> On 2022-01-19 07:53 pm, Romain Beauxis wrote: > >>>>> This patch switches the logic around audio settings to let the caller > >>>>> drive the format. > >>>>> > >>>>> After experimenting with the AudioConverter, we realized that, even > >>>>> when adhering to a strict implementation of the documented API, we were > >>>>> still getting errors during conversions. The input device would > >>>>> randomly change from e.g. s32le to s24le between restarts and error out > >>>>> on conversion (using a freshly initialized converter). > >>>> At present, the code uses the first frame to set attributes. If you > >>>> wait for a few frames and then probe, the attributes are stable. > >>> How is that supposed to work to get a full A/V stream? Discarding > >>> initial audio frames results in data loss in audio-only input and > >>> corrupted initial audio in A/V inputs. > >> We're talking about around 5-6 packets, so ~100 ms. The streaming > >> scenarios I worked on weren't sensitive to that amount of initial loss. > >> YMMV. > > I see thanks. And what advantages does this method provide aside from > > supporting 24 bit sample formats which are currently excluded from > > these changes? > > I was remarking on a way to avoid format changes post-initialization. > Not a comment on your patches. For sure, and I appreciate the feedback. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/5] libavdevice/avfoundation.m: use setAudioSettings, extend supported formats
Le mer. 19 janv. 2022 à 09:19, Gyan Doshi a écrit : > On 2022-01-19 08:44 pm, Romain Beauxis wrote: > > Le mer. 19 janv. 2022 à 08:31, Gyan Doshi a écrit : > >> On 2022-01-19 07:53 pm, Romain Beauxis wrote: > >>> This patch switches the logic around audio settings to let the caller > >>> drive the format. > >>> > >>> After experimenting with the AudioConverter, we realized that, even when > >>> adhering to a strict implementation of the documented API, we were still > >>> getting errors during conversions. The input device would randomly change > >>> from e.g. s32le to s24le between restarts and error out on conversion > >>> (using a freshly initialized converter). > >>At present, the code uses the first frame to set attributes. If you > >> wait for a few frames and then probe, the attributes are stable. > > How is that supposed to work to get a full A/V stream? Discarding > > initial audio frames results in data loss in audio-only input and > > corrupted initial audio in A/V inputs. > > We're talking about around 5-6 packets, so ~100 ms. The streaming > scenarios I worked on weren't sensitive to that amount of initial loss. > YMMV. I see thanks. And what advantages does this method provide aside from supporting 24 bit sample formats which are currently excluded from these changes? ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH 1/5] libavdevice/avfoundation.m: use setAudioSettings, extend supported formats
Le mer. 19 janv. 2022 à 08:31, Gyan Doshi a écrit : > On 2022-01-19 07:53 pm, Romain Beauxis wrote: > > This patch switches the logic around audio settings to let the caller drive > > the format. > > > > After experimenting with the AudioConverter, we realized that, even when > > adhering to a strict implementation of the documented API, we were still > > getting errors during conversions. The input device would randomly change > > from e.g. s32le to s24le between restarts and error out on conversion > > (using a freshly initialized converter). > At present, the code uses the first frame to set attributes. If you > wait for a few frames and then probe, the attributes are stable. How is that supposed to work to get a full A/V stream? Discarding initial audio frames results in data loss in audio-only input and corrupted initial audio in A/V inputs. ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH 5/5] Add AudioToolbox audio input device.
This patch adds support for a new, audio-specific input device using the documented and battle-tested AUHAL input. This provides a pendant to the AudioToolbox audio-only output. A couple of advantages for this: * It avoids a lot of the complexity of supporting audio and video in a single input * The AUHAL API seems tested, documented and robust * This implementation hopefully gives good control over audio latency and also minimizes data copy --- Begin Message --- From 803e1aa52018bdac0a448be255f645ca447273e9 Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Tue, 18 Jan 2022 16:29:59 -0600 Subject: [PATCH] Add AudioToolbox audio input device. X-Unsent: 1 To: ffmpeg-devel@ffmpeg.org Signed-off-by: Romain Beauxis --- configure | 5 + doc/indevs.texi| 44 libavdevice/Makefile | 1 + libavdevice/alldevices.c | 1 + libavdevice/audiotoolbox_dec.m | 466 + 5 files changed, 517 insertions(+) create mode 100644 libavdevice/audiotoolbox_dec.m diff --git a/configure b/configure index 1413122d87..80e39aae44 100755 --- a/configure +++ b/configure @@ -204,6 +204,7 @@ External library support: --disable-avfoundation disable Apple AVFoundation framework [autodetect] --enable-avisynthenable reading of AviSynth script files [no] --disable-bzlib disable bzlib [autodetect] + --disable-coremedia disable Apple CoreMedia framework [autodetect] --disable-coreimage disable Apple CoreImage framework [autodetect] --enable-chromaprint enable audio fingerprinting with chromaprint [no] --enable-frei0r enable frei0r video filtering [no] @@ -1750,6 +1751,7 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" appkit avfoundation bzlib +coremedia coreimage iconv libxcb @@ -3493,6 +3495,8 @@ alsa_outdev_deps="alsa" avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" avfoundation_indev_suggest="coregraphics applicationservices" avfoundation_indev_extralibs="-framework Foundation" +audiotoolbox_indev_deps="coremedia audiotoolbox" +audiotoolbox_indev_extralibs="-framework CoreMedia -framework AudioToolbox" audiotoolbox_outdev_deps="audiotoolbox pthreads" audiotoolbox_outdev_extralibs="-framework AudioToolbox -framework CoreAudio" bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" @@ -6340,6 +6344,7 @@ check_lib camera2ndk "stdbool.h stdint.h camera/NdkCameraManager.h" ACameraManag enabled appkit && check_apple_framework AppKit enabled audiotoolbox && check_apple_framework AudioToolbox enabled avfoundation && check_apple_framework AVFoundation +enabled coremedia&& check_apple_framework CoreMedia enabled coreimage&& check_apple_framework CoreImage enabled metal&& check_apple_framework Metal enabled videotoolbox && check_apple_framework VideoToolbox diff --git a/doc/indevs.texi b/doc/indevs.texi index 858c0fa4e4..30a91d304f 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -103,6 +103,50 @@ Set the maximum number of frames to buffer. Default is 5. @end table +@section AudioToolbox + +AudioToolbox input device. + +Allows native input from CoreAudio devices on OSX. + +All available devices can be enumerated by using @option{-list_devices true}, listing +all device names, and corresponding unique ID. + +@subsection Options + +AudioToolbox supports the following options: + +@table @option + +@item channels +Set the number of channels. Default is device's default. + +@item frames_queue_length +Maximum of buffers in the input queue + +@item buffer_frame_size +Buffer frame size, gouverning internal latency + +@item big_endian +Return big endian samples + +@item sample_format +Sample format + +@end table + +@subsection Examples + +@itemize + +@item +Print the list of supported devices +@example +$ ffmpeg -f audiotoolbox -list_devices true -i "" +@end example + +@end itemize + @section avfoundation AVFoundation input device. diff --git a/libavdevice/Makefile b/libavdevice/Makefile index 53efda0514..0c73255a21 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -14,6 +14,7 @@ OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o OBJS-$(CONFIG_ALSA_INDEV)+= alsa_dec.o alsa.o timefilter.o OBJS-$(CONFIG_ALSA_OUTDEV) += alsa_enc.o alsa.o OBJS-$(CONFIG_ANDROID_CAMERA_INDEV) += android_camera.o +OBJS-$(CONFIG_AUDIOTOOLBOX_INDEV)+= audiotoolbox_dec.o OBJS-$(CONFIG_AUDIOTOOLBOX_OUTDEV) += audiotoolbox.o OBJS-$(CONFIG_AVFOUNDATION_INDEV)+= avfoundation.o OBJS-$(CONFIG_BKTR_INDEV)+= bktr.o diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index 22323a0a44..fbecdbb0b2 100644 --- a
[FFmpeg-devel] [PATCH 4/5] Use appropriate method for device discovery.
This adds support for the non-deprecated methods for selecting devices, when available. --- Begin Message --- From c42612b455289622edb638436b1892e43279d8ac Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Fri, 14 Jan 2022 10:06:08 -0600 Subject: [PATCH] Use appropriate method for device discovery. X-Unsent: 1 To: ffmpeg-devel@ffmpeg.org Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 77 -- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 5d013cc0eb..03ec49df86 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -27,6 +27,7 @@ #import #import +#include #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -698,8 +699,34 @@ static int avf_read_header(AVFormatContext *s) AVCaptureDevice *video_device = nil; AVCaptureDevice *audio_device = nil; // Find capture device -NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; -NSArray *devices_muxed = [AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed]; +#if defined(__MAC_10_15) || (TARGET_OS_IPHONE && defined(__IPHONE_10_0)) + AVCaptureDeviceDiscoverySession *discoverySession = +[AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[ +#if TARGET_OS_IPHONE + AVCaptureDeviceTypeBuiltInDualCamera, + AVCaptureDeviceTypeBuiltInDualWideCamera, + AVCaptureDeviceTypeBuiltInUltraWideCamera, + AVCaptureDeviceTypeBuiltInTrueDepthCamera, + AVCaptureDeviceTypeBuiltInTelephotoCamera, +#endif + AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeExternalUnknown + ] + mediaType:NULL + position:AVCaptureDevicePositionUnspecified]; + + NSMutableArray *devices = [NSMutableArray array]; + NSMutableArray *devices_muxed = [NSMutableArray array]; + for (AVCaptureDevice *device in [discoverySession devices]) { + if ([device hasMediaType:AVMediaTypeVideo]) + [devices addObject:device]; + else if ([device hasMediaType:AVMediaTypeMuxed]) + [devices_muxed addObject:device]; + } +#else + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + NSArray *devices_muxed = [AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed]; +#endif ctx->num_video_devices = [devices count] + [devices_muxed count]; @@ -707,6 +734,21 @@ static int avf_read_header(AVFormatContext *s) CGGetActiveDisplayList(0, NULL, _screens); #endif +NSArray *audio_devices; +#if defined(__MAC_10_15) || (TARGET_OS_IPHONE && defined(__IPHONE_10_0)) +discoverySession = +[AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[ + AVCaptureDeviceTypeBuiltInMicrophone, + AVCaptureDeviceTypeExternalUnknown + ] + mediaType:AVMediaTypeAudio + position:AVCaptureDevicePositionUnspecified]; + +audio_devices = [discoverySession devices]; +#else +audio_devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; +#endif + // List devices if requested if (ctx->list_devices) { int index = 0; @@ -734,8 +776,7 @@ static int avf_read_header(AVFormatContext *s) #endif av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n"); -devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; -for (AVCaptureDevice *device in devices) { +for (AVCaptureDevice *device in audio_devices) { const char *name = [[device localizedName] UTF8String]; const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); int index= [devices indexOfObject:device]; @@ -885,9 +926,7 @@ static int avf_read_header(AVFormatContext *s) // get audio device if (ctx->audio_device_index >= 0) { -NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; - -if (ctx->audio_device_index >= [devices count]) { +if (ctx->audio_device_index >= [audio_devices count]) { av_log(ctx, AV_LOG_ERROR, "Invalid audio device index\n"); goto fail; } @@ -898,22 +937,20 @@ static int avf_read_he
[FFmpeg-devel] [PATCH 3/5] libavdevice/avfoundation.m: Allow to select devices by unique ID
This patch changes the logic around device selection to allow to use a static, machine-readable unique ID when selecting devices. Device names depends on locale settings and device index can change when plugging/unplugging devices. --- Begin Message --- From bf72d48c846f5116866ec588fc0ee54a2c354e87 Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Mon, 13 Dec 2021 09:14:50 -0600 Subject: [PATCH] libavdevice/avfoundation.m: Allow to select devices by unique ID X-Unsent: 1 To: ffmpeg-devel@ffmpeg.org Signed-off-by: Romain Beauxis --- doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 9d8020311a..858c0fa4e4 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index e6f64b35b8..5d013cc0eb 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + static void av_log_avfoundation(void *s, int lvl, const char *str, OSStatus err) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; av_log(s, lvl, "AVFoundation: %s, %s\n", str, @@ -710,21 +712,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _screens); for (int i = 0; i < num_screens; i++) { -av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx->num_video_devices + i, i); +av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d (ID: AvfilterAvfoundationCaptureScreen%d)\n", ctx->num_video_devices + i, i, screens[i]); } } #endif @@ -732,9 +736,10 @@ static int avf_read_header(AVFormatContext *s) av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n"); devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -int index = [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, nam
[FFmpeg-devel] [PATCH 2/5] libavdevice/avfoundation.m: Replace mutex-based concurrency by a thread-safe fifo queue with maximum length
The existing implementation of avdevice input has issues in its concurrent model as it only allows for one shared frame between writing and reading threads. This means that, if reading thread gets late, frames get dropped, resulting in corrupted input. This patch changes the concurrency logic to use a single shared queue for both video and audio frames. Previous version of the patch used separate queues for audio and video but this could cause synchronization issues. In order to avoid dropping initial audio frames, the video configuration logic is also changed to assume height/width as configured when opening the input device so as to not depend on the first video frame for it. --- Begin Message --- From d1a4c6e74ff589d9e59e1310a9afc9bc185382a1 Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Sun, 12 Dec 2021 17:29:27 -0600 Subject: [PATCH] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length X-Unsent: 1 To: ffmpeg-devel@ffmpeg.org * Use a shared CMSimpleQueueEnqueue with maximum length to queue and process incoming audio and video frames. * Simplify video configuration to avoid consuming first frame. * Log avfoundation errors. * Use AVERROR_EXTERNAL instead of AVERROR(EIO) in avfoundation errors. Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 227 + 1 file changed, 101 insertions(+), 126 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 77c6e68763..e6f64b35b8 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -39,6 +39,13 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +static void av_log_avfoundation(void *s, int lvl, const char *str, OSStatus err) { +NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +av_log(s, lvl, "AVFoundation: %s, %s\n", str, +[[[NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil] localizedDescription] UTF8String]); +[pool release]; +} + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -84,9 +91,6 @@ { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -121,8 +125,9 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; + +CMSimpleQueueRef frames_queue; +int max_frames; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -131,16 +136,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -218,17 +213,13 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); +OSStatus ret = CMSimpleQueueEnqueue(_context->frames_queue, videoFrame); -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); +if (ret != noErr) { + av_log_avfoundation(_context, AV_LOG_DEBUG, "Error while queueing video frame", ret); } -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); } @end @@ -262,17 +253,13 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); +OSStatus ret = CMSimpleQueueEnqueue(_context->frames_queue, audioFrame); -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); +if (ret != noErr) { + av_log_avfoundation(_context, AV_LOG_DEBUG, "Error while queueing audio frame", ret); } -_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); - -unlock_frames(_context); - -++_context->audio_frames_captured; +CFRetain(audioFrame); } @end @@ -287,6 +274,19 @@ static void destroy_context(AVFContext* ctx) [ctx->avf_de
[FFmpeg-devel] [PATCH 1/5] libavdevice/avfoundation.m: use setAudioSettings, extend supported formats
This patch switches the logic around audio settings to let the caller drive the format. After experimenting with the AudioConverter, we realized that, even when adhering to a strict implementation of the documented API, we were still getting errors during conversions. The input device would randomly change from e.g. s32le to s24le between restarts and error out on conversion (using a freshly initialized converter). Using setAudioSettings allow the OS to drive audio conversion internally and pick whatever appropriate settings for the audio device. This has been working very well and is also the way AVFoundation audio input is setup in videolan. --- Begin Message --- From fd30f651bdaafe812b5cdc022ef3e4ebd74b6727 Mon Sep 17 00:00:00 2001 From: Romain Beauxis Date: Mon, 29 Nov 2021 08:46:05 -0600 Subject: [PATCH] libavdevice/avfoundation.m: use setAudioSettings, extend supported formats X-Unsent: 1 To: ffmpeg-devel@ffmpeg.org This fixes: https://trac.ffmpeg.org/ticket/9502 Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 206 - 1 file changed, 63 insertions(+), 143 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..77c6e68763 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -93,6 +93,11 @@ AVRational framerate; int width, height; +int channels; +int big_endian; +int sample_rate; +enum AVSampleFormat sample_format; + int capture_cursor; int capture_mouse_clicks; int capture_raw_data; @@ -111,17 +116,6 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; - enum AVPixelFormat pixel_format; AVCaptureSession *capture_session; @@ -298,14 +292,6 @@ static void destroy_context(AVFContext* ctx) ctx->audio_output= NULL; ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; - -av_freep(>audio_buffer); - -pthread_mutex_destroy(>frame_lock); - -if (ctx->current_frame) { -CFRelease(ctx->current_frame); -} } static void parse_device_name(AVFormatContext *s) @@ -671,88 +657,62 @@ static int get_video_config(AVFormatContext *s) static int get_audio_config(AVFormatContext *s) { AVFContext *ctx = (AVFContext*)s->priv_data; -CMFormatDescriptionRef format_desc; -AVStream* stream = avformat_new_stream(s, NULL); +AVStream* stream; +int bits_per_sample, is_float; -if (!stream) { -return 1; -} +enum AVCodecID codec_id = av_get_pcm_codec(ctx->sample_format, ctx->big_endian); -// Take stream info from the first frame. -while (ctx->audio_frames_captured < 1) { -CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES); +if (codec_id == AV_CODEC_ID_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error: invalid sample format!\n"); + return AVERROR(EINVAL); } -lock_frames(ctx); - -ctx->audio_stream_index = stream->index; - -avpriv_set_pts_info(stream, 64, 1, avf_time_base); - -format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +switch (ctx->sample_format) { +case AV_SAMPLE_FMT_S16: +bits_per_sample = 16; +is_float = 0; +break; +case AV_SAMPLE_FMT_S32: +bits_per_sample = 32; +is_float = 0; +break; +case AV_SAMPLE_FMT_FLT: +bits_per_sample = 32; +is_float = 1; +break; +default: +av_log(ctx, AV_LOG_ERROR, "Error: invalid sample format!\n"); +unlock_frames(ctx); +return AVERROR(EINVAL); +} -if (!basic_desc) { +[ctx->audio_output setAudioSettings:@{ +AVFormatIDKey: @(kAudioFormatLinearPCM), +AVLinearPCMBitDepthKey: @(bits_per_sample), +AVLinearPCMIsFloatKey: @(is_float), +AVLinearPCMIsBigEndianKey: @(ctx->big_endian), +AVNumberOfChannelsKey: @(ctx->channels), +AVLinearPCMIsNonInterleaved: @NO, +AVSampleRateKey: @(ctx->sample_rate) +}]; + +stream = avformat_new_stream(s, NULL); +if (!stream) { unlock_frames(ctx); -av_log(s, AV_LOG_ERROR, "audio format not available\n"); -return 1; +return -1; } +
[FFmpeg-devel] [PATCH 0/5] macos avdevice fixes and improvements
This is a follow-up from a previous series of patches that fix, enhance and cleanup support for audio and video input on macos in libavdevice. Due to some important recent refactoring and addition, version is reset. Patches: libavdevice/avfoundation.m: use setAudioSettings, extend supported formats libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length libavdevice/avfoundation.m: Allow to select devices by unique ID Use appropriate method for device discovery. Add AudioToolbox audio input device. configure| 5 ++ doc/indevs.texi | 50 +++- libavdevice/Makefile | 1 + libavdevice/alldevices.c | 1 + libavdevice/audiotoolbox_dec.m (new) | 466 +++ libavdevice/avfoundation.m | 548 - 6 files changed, 781 insertions(+), 290 deletions(-) create mode 100644 libavdevice/audiotoolbox_dec.m ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v9 1/3] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
Le ven. 14 janv. 2022 à 11:47, Thilo Borgmann a écrit : > > Am 14.01.22 um 13:57 schrieb Marvin Scholz: > > > > > > On 6 Jan 2022, at 15:24, Romain Beauxis wrote: > > > >> * Implement support for AudioConverter > >> * Switch to AudioConverter's API to convert unsupported PCM > >> formats (non-interleaved, non-packed) to supported formats > >> * Minimize data copy. > >> > >> This fixes: https://trac.ffmpeg.org/ticket/9502 > >> > >> API ref: > >> https://developer.apple.com/documentation/audiotoolbox/audio_converter_services > >> > >> Signed-off-by: Romain Beauxis > >> --- > >> This is the first patch of a series of 3 that fix, cleanup and enhance the > >> avfoundation implementation for libavdevice. > >> > >> These patches come from an actual user-facing application relying on > >> libavdevice’s implementation of avfoundation audio input. Without them, > >> Avfoundation is practically unusable as it will: > >> * Refuse to process certain specific audio input format that are actually > >> returned by the OS for some users (packed PCM audio) > >> * Drop audio frames, resulting in corrupted audio input. This might have > >> been > >> unnoticed with video frames but this makes avfoundation essentially > >> unusable > >> for audio. > >> > >> The patches are now being included in our production build so they are > >> tested > >> and usable in production. > >> > > > > Hi, > > > > the patches are still corrupt and do not apply. > > As stated earlier, please either use git send-email or attach the patch > > to the mail instead of putting its contents in it, as apparently Mail.app > > messes them up. > > Still the same for me. Do you use git send-email or git format-patch? Thanks for checking on this y'all and sorry about these complications. I used git format-patches. I might try git send-email or the github PR bridge, that seems like a neat trick. I'm working on a new revision of the patches, I discovered more issues with audio conversion, possibly linked to bugs with the AudioConverter API. I also discovered an API to do the conversion internally without having to deal with manually reconverting. Hopefully, this also fixes the issues we uncovered. Will post once we have done more testing. All in all, macos sound APIs are pretty confusing and buggy around the edges it seems. Thanks again! -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] 5.0 blocking issues
Le sam. 8 janv. 2022 à 10:30, Michael Niedermayer a écrit : > > Hi all > > This is a simple go/no go call > if you know of something that still should go into 5.0 please reply here > with a list of what you are working on and a timelimit until when you > will be done with it > > if you think everything is ready for the release, then too feel free to > reply (assuming few others said ok yet) this is not supposed to become a > 100 reply thread with oks, just maybe 2-3 people confirming that noone > is aware of things missing. > > I intend to do the release within 2-3 days of all "no go" things being > resolved or timeouting Hi, Not sure if that should be blocking but the series of patches starting here: http://ffmpeg.org/pipermail/ffmpeg-devel/2022-January/290940.html do fix avfoundation devices, which are currently unusable. It would be nice to get it out as part of a new release. I'm available in the coming days for quick review/changes/fixes. -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH v8 2/3] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length
Le mer. 5 janv. 2022 à 08:50, Marvin Scholz a écrit : > > On 31 Dec 2021, at 18:43, Romain Beauxis wrote: > > > * Use a CMSimpleQueueEnqueue with maximum length to queue and process > > incoming audio and video frames. > > * Log avfoundation errors. > > * Use AVERROR_EXTERNAL instead of AVERROR(EIO) in avfoundation errors. > > > > Signed-off-by: Romain Beauxis > > — > > [Sorry for the noise but an issue came up with the previous set] > > > > This is the second patch of a series of 3 that fix, cleanup and > > enhance the > > avfoundation implementation for libavdevice. > > > > These patches come from an actual user-facing application relying on > > libavdevice’s implementation of avfoundation audio input. Without > > them, > > Avfoundation is practically unusable as it will: > > * Refuse to process certain specific audio input format that are > > actually > > returned by the OS for some users (packed PCM audio) > > * Drop audio frames, resulting in corrupted audio input. This might > > have been > > unnoticed with video frames but this makes avfoundation essentially > > unusable > > for audio. > > > > The patches are now being included in our production build so they are > > tested > > and usable in production. > > > > Changelog for this patch: > > * v2: None > > * v3: None > > * v4: None > > * v5: Fix indentation/wrapping > > * v6: None > > * v7: Removed use of kAudioConverterPropertyCalculateOutputBufferSize > > to calculate output buffer size. The calculation is trivial and this > > call was > > randomly failing for no reason > > * v8: Fix memory leak when video or audio queue is full > > > > libavdevice/avfoundation.m | 194 +++-- > > 1 file changed, 100 insertions(+), 94 deletions(-) > > > > diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m > > index 738cd93375..36f9fdc53d 100644 > > --- a/libavdevice/avfoundation.m > > +++ b/libavdevice/avfoundation.m > > @@ -26,7 +26,7 @@ > > */ > > > > #import > > -#include > > +#import > > > > #include "libavutil/channel_layout.h" > > #include "libavutil/pixdesc.h" > > @@ -39,6 +39,11 @@ > > #include "libavutil/imgutils.h" > > #include "avdevice.h" > > > > +#define av_log_avfoundation_error(s, str, err) \ > > + av_log(s, AV_LOG_ERROR, "Avfoundation: %s, %s\n", str, \ > > nitpick: should probably be AVFoundation, no? Done! > > + [[[NSError errorWithDomain:NSOSStatusErrorDomain code:err > > userInfo:nil] localizedDescription] UTF8String] \ > > + ) > > + > > The errorWithDomain: returns an autorelease NSError, however there is no > autorelease pool. > Either make this a function with an @autorelease pool or use [[… > alloc] init…] instead, and > release the NSError. That's right, thanks for pointing that out. Just sent a v9 version of the patchset fixing that and also dropping the log level for the error returned when the queue is full. In practice, the queue can become full pretty often, for instance when waiting on a remote output connection so these logs end up polluting the output in situations that are not really problematic. Thanks for looking into this! -- Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH v9 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID
Signed-off-by: Romain Beauxis --- This is the third patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. Changes: v2: None v3: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture v4: Cleanup v5: Fix indentation/wrapping v6: None v7: None V8: None v9: None doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 9d8020311a..858c0fa4e4 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 5ee19f4863..c4a4272965 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -46,6 +46,8 @@ static inline void av_log_avfoundation(void *s, int lvl, const char *str, OSStat [pool release]; } +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -817,21 +819,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _screens); for (int i = 0; i < num_screens; i++) { -av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx->num_video_devices + i, i); +av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d (ID: AvfilterAvfoundationCaptureScreen%d)\n", ctx->num_video_devices + i, i, screens[i]); } } #endif @@ -839,9 +843,10 @@ static int avf_read_header(AVFormatContext *s) av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n"); devices = [AVCaptureDevice devicesWithMediaType:AVM
[FFmpeg-devel] [PATCH v9 2/3] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length
* Use a CMSimpleQueueEnqueue with maximum length to queue and process incoming audio and video frames. * Log avfoundation errors. * Use AVERROR_EXTERNAL instead of AVERROR(EIO) in avfoundation errors. Signed-off-by: Romain Beauxis --- This is the first patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. Changes: * v2: None * v3: Switched queue implementation to CMSimpleQueue * v4: None * v5: Fix indentation/wrapping * v6: Fix audio/video frame queue cleanup logic * v7: Enhance avfoundation error reporting: add human-readable description, use AVERROR_EXTERNAL instead of AVERROR(EIO) * v8: Fix memory leak when video or audio queue is full * v9: Use auto-release pool for av_log_avfoundation, make it an inline function, drop log level to AV_LOG_DEBUG when frame queueing fails as it is quite likely to happen while setting up a processing pipeline. libavdevice/avfoundation.m | 196 +++-- 1 file changed, 102 insertions(+), 94 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 738cd93375..5ee19f4863 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -39,6 +39,13 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +static inline void av_log_avfoundation(void *s, int lvl, const char *str, OSStatus err) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil]; + av_log(s, lvl, "AVFoundation: %s, %s\n", str, [[error localizedDescription] UTF8String]); + [pool release]; +} + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -80,13 +87,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -122,8 +128,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -132,16 +138,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -219,17 +215,13 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); +OSStatus ret = CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); +if (ret != noErr) { + av_log_avfoundation(_context, AV_LOG_DEBUG, "Error while queueing video frame", ret); } -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); } @end @@ -263,17 +255,13 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); +OSStatus ret = CMSimpleQueueEnqueue(_context->audio_frames_queue, audioFrame); -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); +if (ret != noErr) { + av_log_avfoundation(_context, AV_LOG_DEBUG, "Error while queueing audio frame", ret); } -_context->current_audio_frame =
[FFmpeg-devel] [PATCH v9 1/3] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
* Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis --- This is the first patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. Changelog for this patch: * v2: None * v3: None * v4: None * v5: Fix indentation/wrapping * v6: None * v7: Removed use of kAudioConverterPropertyCalculateOutputBufferSize to calculate output buffer size. The calculation is trivial and this call was randomly failing for no reason * v8: None * v9: None libavdevice/avfoundation.m | 255 + 1 file changed, 145 insertions(+), 110 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..738cd93375 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,11 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32input_bytes_per_sample; +UInt32output_bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +294,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +671,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +692,97 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags &
[FFmpeg-devel] [PATCH v8 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID
Signed-off-by: Romain Beauxis — [Sorry for the noise but an issue came up with the previous set] This is the third patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production Changes: v2: None v3: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture v4: Cleanup v5: Fix indentation/wrapping v6: None v7: None V8: None This patch adds a unique ID to avfoundation devices. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. Example of output: ./ffmpeg -f avfoundation -list_devices true -i "" [...] [AVFoundation indev @ 0x158705230] AVFoundation video devices: [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID: 47B4B64B70674B9CAD2BAE273A71F4B5) [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID: AvfilterAvfoundationCaptureScreen1) [AVFoundation indev @ 0x158705230] AVFoundation audio devices: [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID: com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B) [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID:BuiltInMicrophoneDevice) Notes: * Unique names do not seem to follow any specific pattern. I have used one similar to the builtin microphone for screen capture * The : substitution is actually required. The loopback device above did have it in its name. doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 9d8020311a..858c0fa4e4 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 36f9fdc53d..d09a81cb3b 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + #define av_log_avfoundation_error(s, str, err) \ av_log(s, AV_LOG_ERROR, "Avfoundation: %s, %s\n", str, \ [[[NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil] localizedDescription] UTF8String] \ @@ -815,21 +817,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [
[FFmpeg-devel] [PATCH v8 2/3] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length
* Use a CMSimpleQueueEnqueue with maximum length to queue and process incoming audio and video frames. * Log avfoundation errors. * Use AVERROR_EXTERNAL instead of AVERROR(EIO) in avfoundation errors. Signed-off-by: Romain Beauxis — [Sorry for the noise but an issue came up with the previous set] This is the second patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. Changelog for this patch: * v2: None * v3: None * v4: None * v5: Fix indentation/wrapping * v6: None * v7: Removed use of kAudioConverterPropertyCalculateOutputBufferSize to calculate output buffer size. The calculation is trivial and this call was randomly failing for no reason * v8: Fix memory leak when video or audio queue is full libavdevice/avfoundation.m | 194 +++-- 1 file changed, 100 insertions(+), 94 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 738cd93375..36f9fdc53d 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -39,6 +39,11 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define av_log_avfoundation_error(s, str, err) \ + av_log(s, AV_LOG_ERROR, "Avfoundation: %s, %s\n", str, \ + [[[NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil] localizedDescription] UTF8String] \ + ) + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -80,13 +85,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -122,8 +126,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -132,16 +136,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -219,17 +213,13 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); +OSStatus ret = CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); +if (ret != noErr) { + av_log_avfoundation_error(_context, "Error while queueing video frame", ret); } -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); } @end @@ -263,17 +253,13 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); +OSStatus ret = CMSimpleQueueEnqueue(_context->audio_frames_queue, audioFrame); -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); +if (ret != noErr) { + av_log_avfoundation_error(_context, "Error while queueing audio frame", ret); } -_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); - -unlock_frames(_context); - -++_context->audio_frames_captured; +CFRetain(audioFrame); } @end @@ -288,6 +274,30 @@ static void destroy_context(AVFContext* ctx) [ctx->avf_delegaterelease]; [ctx->avf_audio_delegate release]; +CMSampleBufferRef fra
[FFmpeg-devel] [PATCH v8 1/3] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
* Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis — [Sorry for the noise but an issue came up with the previous set] This is the first patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. Changelog for this patch: * v2: None * v3: None * v4: None * v5: Fix indentation/wrapping * v6: None * v7: Removed use of kAudioConverterPropertyCalculateOutputBufferSize to calculate output buffer size. The calculation is trivial and this call was randomly failing for no reason * v8: None libavdevice/avfoundation.m | 255 + 1 file changed, 145 insertions(+), 110 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..738cd93375 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,11 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32input_bytes_per_sample; +UInt32output_bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +294,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +671,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +692,97 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
[FFmpeg-devel] [PATCH v7 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID
Signed-off-by: Romain Beauxis — This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture v4: Cleanup v5: Fix indentation/wrapping v6: None v7: None This patch adds a unique ID to avfoundation devices. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. Example of output: ./ffmpeg -f avfoundation -list_devices true -i "" [...] [AVFoundation indev @ 0x158705230] AVFoundation video devices: [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID: 47B4B64B70674B9CAD2BAE273A71F4B5) [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID: AvfilterAvfoundationCaptureScreen1) [AVFoundation indev @ 0x158705230] AVFoundation audio devices: [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID: com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B) [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID:BuiltInMicrophoneDevice) Notes: * Unique names do not seem to follow any specific pattern. I have used one similar to the builtin microphone for screen capture * The : substitution is actually required. The loopback device above did have it in its name. doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 9d8020311a..858c0fa4e4 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index c740745fce..bad0cd7155 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + #define av_log_avfoundation_error(str, err) \ av_log(s, AV_LOG_ERROR, "Avfoundation: %s, %s\n", str, \ [[[NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil] localizedDescription] UTF8String] \ @@ -805,21 +807,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _sc
[FFmpeg-devel] [PATCH v7 2/3] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length
* Use a CMSimpleQueueEnqueue with maximum length to queue and process incoming audio and video frames. * Log avfoundation errors. * Use AVERROR_EXTERNAL instead of AVERROR(EIO) in avfoundation errors. Signed-off-by: Romain Beauxis — This is the second patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. This patch fixes the concurrency model. Avfoundation runs its own producing thread to send produced frames and ffmpeg runs its own thread to consume them. The existing implementation stores the last transmitted frame and uses a mutex to avoid concurrent access. However, this leads to situations where upcoming frames can be dropped if the ffmpeg thread is acessing the latest frame. This happens even when the thread would otherwise catch up and process frames fast enought. This patches changes this implementation to use a buffer queue with a max queue length and encapsulated thread-safety. This greatly simplifies the logic of the calling code and gives the consuming thread a chance to process all frames concurrently to the producing thread while avoiding memory leaks. Changes: v2: None v3: Switched queue implementation to CMSimpleQueue v4: None v5: Fix indentation/wrapping v6: Fix audio/video frame queue cleanup logic v7: Enhance avfoundation error reporting: add human-readable description, use AVERROR_EXTERNAL instead of AVERROR(EIO) libavdevice/avfoundation.m | 196 ++--- 1 file changed, 96 insertions(+), 100 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 738cd93375..c740745fce 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -39,6 +39,11 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define av_log_avfoundation_error(str, err) \ + av_log(s, AV_LOG_ERROR, "Avfoundation: %s, %s\n", str, \ + [[[NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil] localizedDescription] UTF8String] \ + ) + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -80,13 +85,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -122,8 +126,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -132,16 +136,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -219,17 +213,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); -} - -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); +CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); } @end @@ -263,17 +248,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); -} - -_context->current_audio_frame =
[FFmpeg-devel] [PATCH v7 1/3] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
* Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis — This is the first patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. Changelog for this patch: * v2: None * v3: None * v4: None * v5: Fix indentation/wrapping * v6: None * v7: Removed use of kAudioConverterPropertyCalculateOutputBufferSize to calculate output buffer size. The calculation is trivial and this call was randomly failing for no reason libavdevice/avfoundation.m | 255 + 1 file changed, 145 insertions(+), 110 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..738cd93375 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,11 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32input_bytes_per_sample; +UInt32output_bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +294,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +671,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +692,97 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacke
Re: [FFmpeg-devel] [PATCH v6 01/03] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
> On Dec 28, 2021, at 6:54 PM, Aman Karmani wrote: > > > > On Tue, Dec 28, 2021 at 2:50 PM Romain Beauxis wrote: > This is the first patch of a series of 3 that fix, cleanup and enhance the > avfoundation implementation for libavdevice. > > The patches have been submitted a couple of times now and have > received very nice feedback for the last two however but they do not seem > to have been considered for inclusion thus far. > > These patches come from an actual user-facing application relying on > libavdevice’s implementation of avfoundation audio input. Without them, > Avfoundation is practically unusable as it will: > * Refuse to process certain specific audio input format that are actually > returned by the OS for some users (packed PCM audio) > * Drop audio frames, resulting in corrupted audio input. This might have been > unnoticed with video frames but this makes avfoundation essentially unusable > for audio. > > The patches are now being included in our production build so they are tested > and usable in production. > > So, this bares the question: is avfoundation still supported and actively > maintained > in libavdevice? It feels that such important bugs should have been noticed by > now > and also generated a little more interest in fixing them. > > Thanks for working on this, and addressing all the feedback so far. > > The patchset LGTM, and I think it should be applied. > > Looks like MAINTAINERS lists Thilo for avfoundation.m. I'm not sure if he's > seen this yet, so I'm cc'ing on this reply. > > If we don't hear in the next couple weeks, I can apply these changes. Thank you, this is much appreciated! We discovered a bug in the audio converter patch, I’m posting a new updated series right away & will CC everyone here. Thanks! > > > Thanks for y’all feedback! > — Romain > - > > Changes: > * v2: None > * v3: None > * v4: None > * v5: Fix indentation/wrapping > * v6: None > > * Implement support for AudioConverter > * Switch to AudioConverter's API to convert unsupported PCM > formats (non-interleaved, non-packed) to supported formats > * Minimize data copy. > > This fixes: https://trac.ffmpeg.org/ticket/9502 > > API ref: > https://developer.apple.com/documentation/audiotoolbox/audio_converter_services > > Signed-off-by: Romain Beauxis > --- > libavdevice/avfoundation.m | 250 + > 1 file changed, 144 insertions(+), 106 deletions(-) > > diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m > index 0cd6e646d5..79c9207cfa 100644 > --- a/libavdevice/avfoundation.m > +++ b/libavdevice/avfoundation.m > @@ -111,16 +111,10 @@ > > int num_video_devices; > > -int audio_channels; > -int audio_bits_per_sample; > -int audio_float; > -int audio_be; > -int audio_signed_integer; > -int audio_packed; > -int audio_non_interleaved; > - > -int32_t *audio_buffer; > -int audio_buffer_size; > +UInt32audio_buffers; > +UInt32audio_channels; > +UInt32bytes_per_sample; > +AudioConverterRef audio_converter; > > enum AVPixelFormat pixel_format; > > @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) > ctx->avf_delegate= NULL; > ctx->avf_audio_delegate = NULL; > > -av_freep(>audio_buffer); > +if (ctx->audio_converter) { > + AudioConverterDispose(ctx->audio_converter); > + ctx->audio_converter = NULL; > +} > > pthread_mutex_destroy(>frame_lock); > > @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) > AVFContext *ctx = (AVFContext*)s->priv_data; > CMFormatDescriptionRef format_desc; > AVStream* stream = avformat_new_stream(s, NULL); > +AudioStreamBasicDescription output_format = {0}; > +int audio_bits_per_sample, audio_float, audio_be; > +int audio_signed_integer, audio_packed, audio_non_interleaved; > +int must_convert = 0; > > if (!stream) { > return 1; > @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) > avpriv_set_pts_info(stream, 64, 1, avf_time_base); > > format_desc = > CMSampleBufferGetFormatDescription(ctx->current_audio_frame); > -const AudioStreamBasicDescription *basic_desc = > CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); > +const AudioStreamBasicDescription *input_format = > CMAudioFormatDescriptionGetStreamBasicDescription(format
[FFmpeg-devel] [PATCH v6 03/03] libavdevice/avfoundation.m: Allow to select devices by unique ID
This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture v4: Cleanup v5: Fix indentation/wrapping V6: None This patch adds a unique ID to avfoundation devices. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. Example of output: ./ffmpeg -f avfoundation -list_devices true -i "" [...] [AVFoundation indev @ 0x158705230] AVFoundation video devices: [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID: 47B4B64B70674B9CAD2BAE273A71F4B5) [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID: AvfilterAvfoundationCaptureScreen1) [AVFoundation indev @ 0x158705230] AVFoundation audio devices: [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID: com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B) [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID:BuiltInMicrophoneDevice) Notes: * Unique names do not seem to follow any specific pattern. I have used one similar to the builtin microphone for screen capture * The : substitution is actually required. The loopback device above did have it in its name. Signed-off-by: Romain Beauxis --- doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 9d8020311a..858c0fa4e4 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index f7bd5be404..fda5a4d261 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -797,21 +799,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _screens); for (int i = 0; i < num_screens; i++) { -av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx->num
[FFmpeg-devel] [PATCH v6 02/03] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length
This is the second patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: Switched queue implementation to CMSimpleQueue v4: None v5: Fix indentation/wrapping V6: Fix audio/video frame queue cleanup logic This patch fixes the concurrency model. Avfoundation runs its own producing thread to send produced frames and ffmpeg runs its own thread to consume them. The existing implementation stores the last transmitted frame and uses a mutex to avoid concurrent access. However, this leads to situations where upcoming frames can be dropped if the ffmpeg thread is acessing the latest frame. This happens even when the thread would otherwise catch up and process frames fast enought. This patches changes this implementation to use a buffer queue with a max queue length and encapsulated thread-safety. This greatly simplifies the logic of the calling code and gives the consuming thread a chance to process all frames concurrently to the producing thread while avoiding memory leaks. Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 169 + 1 file changed, 76 insertions(+), 93 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 79c9207cfa..f7bd5be404 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -80,13 +80,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -121,8 +120,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -131,16 +130,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -218,17 +207,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); -} - -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); +CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); } @end @@ -262,17 +242,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); -} - -_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); - -unlock_frames(_context); - -++_context->audio_frames_captured; +CFRetain(audioFrame); +CMSimpleQueueEnqueue(_context->audio_frames_queue, audioFrame); } @end @@ -287,6 +258,30 @@ static void destroy_context(AVFContext* ctx) [ctx->avf_delegaterelease]; [ctx->avf_audio_delegate release]; +CMSampleBufferRef frame; + +if (ctx->video_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +while (frame) { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +} + +CFRelease(ctx->video_frames_queue); +ctx->video_frames_queue = NULL; +} + +if (ctx->audio_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +while (frame) { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +} + +CFRelease(ctx->audio_frames_queue); +ctx->audio_frames_queue = NULL; +} + ctx->capture_session = NULL; ctx->video_output= NULL; ctx->audio_output= NULL; @@ -297,12 +292,6 @@ static void destroy_context(AVFContext* ctx) Au
[FFmpeg-devel] [PATCH v6 01/03] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
This is the first patch of a series of 3 that fix, cleanup and enhance the avfoundation implementation for libavdevice. The patches have been submitted a couple of times now and have received very nice feedback for the last two however but they do not seem to have been considered for inclusion thus far. These patches come from an actual user-facing application relying on libavdevice’s implementation of avfoundation audio input. Without them, Avfoundation is practically unusable as it will: * Refuse to process certain specific audio input format that are actually returned by the OS for some users (packed PCM audio) * Drop audio frames, resulting in corrupted audio input. This might have been unnoticed with video frames but this makes avfoundation essentially unusable for audio. The patches are now being included in our production build so they are tested and usable in production. So, this bares the question: is avfoundation still supported and actively maintained in libavdevice? It feels that such important bugs should have been noticed by now and also generated a little more interest in fixing them. Thanks for y’all feedback! — Romain - Changes: * v2: None * v3: None * v4: None * v5: Fix indentation/wrapping * v6: None * Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 250 + 1 file changed, 144 insertions(+), 106 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..79c9207cfa 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,10 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioForm
Re: [FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID.
> On Dec 17, 2021, at 3:51 PM, Marvin Scholz wrote: > > > > On 17 Dec 2021, at 16:12, Romain Beauxis wrote: > >> This is the third patch of a series of 3 that cleanup and enhance the >> avfoundation implementation for libavdevice. >> >> Changes: >> v2: None >> v3: >> * Switched unique ID to use system-prodvided unique ID >> * Implemented unique IDs for screen capture >> v4: Cleanup >> >> This patch adds a unique ID to avfoundation devices. This is needed >> because device index can change while the machine is running when >> devices are plugged or unplugged and device names can be tricky to use >> with localization and etc. >> >> Example of output: >> ./ffmpeg -f avfoundation -list_devices true -i "" >> [...] >> [AVFoundation indev @ 0x158705230] AVFoundation video devices: >> [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID: >> 47B4B64B70674B9CAD2BAE273A71F4B5) >> [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID: >> AvfilterAvfoundationCaptureScreen1) >> [AVFoundation indev @ 0x158705230] AVFoundation audio devices: >> [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID: >> com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B) >> [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID: >> BuiltInMicrophoneDevice) >> >> Notes: >> * Unique names do not seem to follow any specific pattern. I have used >> one similar to the builtin microphone for screen capture >> * The : substitution is actually required. The loopback device above did >> have it in its name. >> > > Is there no way to escape the : in the command so that we would not > need to mess with the ID the system gives us? > And if we need to, it would be ideal to have a fully reversible way of > doing so, as then you could just reverse the mangling and use > `deviceWithUniqueID:` instead of iterating all devices. I was just thinking about this. while that would indeed be possible and a great approach, I realize now that because the implementation needs to otherwise match the filename if it is used, we would still need to iterate through all the devices. The current code, while annoying, at least does one loop to catch both use of filename and unique ID. > That said, if thats not easily doable I am fine with the patch as-is, > aside from the minor comments below, thanks for your work on this. Great thanks and thanks for the great reviews! Are you interested just in this patch? In which case, should I repost it rebased on the latest main instead of the previous patch? > >> Signed-off-by: Romain Beauxis >> --- >> doc/indevs.texi| 6 ++-- >> libavdevice/avfoundation.m | 72 +- >> 2 files changed, 60 insertions(+), 18 deletions(-) >> >> diff --git a/doc/indevs.texi b/doc/indevs.texi >> index 5be647f70a..2b55399c8c 100644 >> --- a/doc/indevs.texi >> +++ b/doc/indevs.texi >> @@ -114,7 +114,7 @@ The input filename has to be given in the following >> syntax: >> -i "[[VIDEO]:[AUDIO]]" >> @end example >> The first entry selects the video input while the latter selects the audio >> input. >> -The stream has to be specified by the device name or the device index as >> shown by the device list. >> +The stream has to be specified by the device name, index or ID as shown by >> the device list. >> Alternatively, the video and/or audio input device can be chosen by index >> using the >> @option{ >> -video_device_index >> @@ -127,7 +127,9 @@ and/or >> device name or index given in the input filename. >> All available devices can be enumerated by using @option{-list_devices >> true}, listing >> -all device names and corresponding indices. >> +all device names, corresponding indices and IDs, when available. Device >> name can be +tricky to use when localized and device index can change when >> devices are plugged or unplugged. A device >> +hash, when available, uniquely identifies a device and should not change >> over time. > > This should say ID I think, as hash was never mentioned before. ACK >> There are two device name aliases: >> @table @code >> diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m >> index b602cfbe95..25286507d6 100644 >> --- a/libavdevice/avfoundation.m >> +++ b/libavdevice/avfoundation.m >> @@ -39,6 +39,8 @@ >> #include "libavutil/imgutils.h" >> #include "avdevice.h" >> +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrences
[FFmpeg-devel] [PATCH v5 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID
(Apologies for the previously mangled message, I’m still honing my tools here!) This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture v4: Cleanup v5: Fix indentation/wrapping This patch adds a unique ID to avfoundation devices. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. Example of output: ./ffmpeg -f avfoundation -list_devices true -i "" [...] [AVFoundation indev @ 0x158705230] AVFoundation video devices: [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID: 47B4B64B70674B9CAD2BAE273A71F4B5) [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID: AvfilterAvfoundationCaptureScreen1) [AVFoundation indev @ 0x158705230] AVFoundation audio devices: [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID: com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B) [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID:BuiltInMicrophoneDevice) Notes: * Unique names do not seem to follow any specific pattern. I have used one similar to the builtin microphone for screen capture * The : substitution is actually required. The loopback device above did have it in its name. Signed-off-by: Romain Beauxis --- doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 5be647f70a..2b55399c8c 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index b602cfbe95..25286507d6 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -797,21 +799,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _screens); for (int i = 0; i < num_screens; i++) { -
[FFmpeg-devel] [PATCH v5 2/3] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length
(Apologies for the previously mangled message, I’m still honing my tools here!) This is the second patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: Switched queue implementation to CMSimpleQueue v4: None v5: Fix indentation/wrapping This patch fixes the concurrency model. Avfoundation runs its own producing thread to send produced frames and ffmpeg runs its own thread to consume them. The existing implementation stores the last transmitted frame and uses a mutex to avoid concurrent access. However, this leads to situations where upcoming frames can be dropped if the ffmpeg thread is acessing the latest frame. This happens even when the thread would otherwise catch up and process frames fast enought. This patches changes this implementation to use a buffer queue with a max queue length and encapsulated thread-safety. This greatly simplifies the logic of the calling code and gives the consuming thread a chance to process all frames concurrently to the producing thread while avoiding memory leaks. Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 169 + 1 file changed, 76 insertions(+), 93 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 79c9207cfa..b602cfbe95 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -80,13 +80,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -121,8 +120,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -131,16 +130,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -218,17 +207,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); -} - -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); +CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); } @end @@ -262,17 +242,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); -} - -_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); - -unlock_frames(_context); - -++_context->audio_frames_captured; +CFRetain(audioFrame); +CMSimpleQueueEnqueue(_context->audio_frames_queue, audioFrame); } @end @@ -287,6 +258,30 @@ static void destroy_context(AVFContext* ctx) [ctx->avf_delegaterelease]; [ctx->avf_audio_delegate release]; +CMSampleBufferRef frame; + +if (ctx->video_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +do { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +} while (frame); + +CFRelease(ctx->video_frames_queue); +ctx->video_frames_queue = NULL; +} + +if (ctx->audio_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +do { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +} while (frame); + +CFRelease(ctx->audio_frames_queue); +ctx->audio_frames_queue = NULL; +} + ctx->capture_session = NULL; ctx->video_output= NULL; ctx->audio_output= NULL; @@ -297,12 +292,6 @@ static voi
[FFmpeg-devel] [PATCH v5 1/3] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
(Apologies for the previously mangled message, I’m still honing my tools here!) This is the first patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: * v2: None * v3: None * v4: None * v5: Fix indentation/wrapping * Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 250 + 1 file changed, 144 insertions(+), 106 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..79c9207cfa 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,10 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked; -ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved; - -if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_float && -ctx->audio_bits_per_sample == 32 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 16 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; -} else if (basic_d
[FFmpeg-devel] [PATCH v4 3/3] libavdevice/avfoundation.m: Allow to select devices by unique ID.
This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture v4: Cleanup This patch adds a unique ID to avfoundation devices. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. Example of output: ./ffmpeg -f avfoundation -list_devices true -i "" [...] [AVFoundation indev @ 0x158705230] AVFoundation video devices: [AVFoundation indev @ 0x158705230] [0] FaceTime HD Camera (ID: 47B4B64B70674B9CAD2BAE273A71F4B5) [AVFoundation indev @ 0x158705230] [1] Capture screen 0 (ID: AvfilterAvfoundationCaptureScreen1) [AVFoundation indev @ 0x158705230] AVFoundation audio devices: [AVFoundation indev @ 0x158705230] [0] Loopback Audio (ID: com.rogueamoeba.Loopback.A5668B36-711E-4DF5-8A8D-7148508C735B) [AVFoundation indev @ 0x158705230] [1] MacBook Pro Microphone (ID: BuiltInMicrophoneDevice) Notes: * Unique names do not seem to follow any specific pattern. I have used one similar to the builtin microphone for screen capture * The : substitution is actually required. The loopback device above did have it in its name. Signed-off-by: Romain Beauxis --- doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 72 +- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 5be647f70a..2b55399c8c 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index b602cfbe95..25286507d6 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -797,21 +799,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _screens); for (int i = 0; i < num_screens; i++) { -av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx-&
[FFmpeg-devel] [PATCH v4 2/3] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length.
This is the second patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: v2: None v3: Switched queue implementation to CMSimpleQueue v4: None This patch fixes the concurrency model. Avfoundation runs its own producing thread to send produced frames and ffmpeg runs its own thread to consume them. The existing implementation stores the last transmitted frame and uses a mutex to avoid concurrent access. However, this leads to situations where upcoming frames can be dropped if the ffmpeg thread is acessing the latest frame. This happens even when the thread would otherwise catch up and process frames fast enought. This patches changes this implementation to use a buffer queue with a max queue length and encapsulated thread-safety. This greatly simplifies the logic of the calling code and gives the consuming thread a chance to process all frames concurrently to the producing thread while avoiding memory leaks. Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 169 + 1 file changed, 76 insertions(+), 93 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 79c9207cfa..b602cfbe95 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -80,13 +80,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -121,8 +120,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -131,16 +130,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -218,17 +207,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); -} - -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); +CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); } @end @@ -262,17 +242,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); -} - -_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); - -unlock_frames(_context); - -++_context->audio_frames_captured; +CFRetain(audioFrame); +CMSimpleQueueEnqueue(_context->audio_frames_queue, audioFrame); } @end @@ -287,6 +258,30 @@ static void destroy_context(AVFContext* ctx) [ctx->avf_delegaterelease]; [ctx->avf_audio_delegate release]; +CMSampleBufferRef frame; + +if (ctx->video_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +do { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +} while (frame); + +CFRelease(ctx->video_frames_queue); +ctx->video_frames_queue = NULL; +} + +if (ctx->audio_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +do { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +} while (frame); + +CFRelease(ctx->audio_frames_queue); +ctx->audio_frames_queue = NULL; +} + ctx->capture_session = NULL; ctx->video_output= NULL; ctx->audio_output= NULL; @@ -297,12 +292,6 @@ static void destroy_context(AVFContext* ctx) AudioConverterDi
[FFmpeg-devel] [PATCH v4 1/3] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
This is the first patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes: * v2: None * v3: None * v4: None * Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 250 + 1 file changed, 144 insertions(+), 106 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..79c9207cfa 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,10 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked; -ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved; - -if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_float && -ctx->audio_bits_per_sample == 32 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 16 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_sign
Re: [FFmpeg-devel] [PATCH v2 03/03] libavdevice/avfoundation.m: Allow to select devices by digest.
Just sent an updated patch here: http://ffmpeg.org/pipermail/ffmpeg-devel/2021-December/289686.html > On Dec 13, 2021, at 12:25 PM, Marvin Scholz wrote: > > On 13 Dec 2021, at 17:40, Romain Beauxis wrote: > >> This is the third patch of a series of 3 that cleanup and enhance the >> avfoundation implementation for libavdevice. >> >> This patch adds a digest to avfoundation devices, when available. This >> is needed because device index can change while the machine is running when >> devices are plugged or unplugged and device names can be tricky to use with >> localization >> and etc. >> >> The only device type that are excluded are screen capture because the logic >> to select >> them seems a little different and I wanted to minimized the changes. Also, >> for these >> devices, the name is localized in english, quite straight forward and should >> not change. >> >> Signed-off-by: Romain Beauxis >> --- > > > Hi, > thanks for the patch, however I fail to see the benefit of it. > You mention that using the name is complicated because it is localized, > but your patch just seems to use the device name and hashes it, which > does not mitigate the issues with the localized name (that could change > when the language is changed) but just hides it behind a hash, making > this problem even more obscure and confusing. > (Correct me if I read your patch wrong, but it seems to just do that.) > > Instead I think that you should use the uniqueID property of an > AVCaptureDevice, > documented here: > https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc > > <https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc> > > According to the docs, this seems more appropriated, as it does not depend on > the localization and does not change when the device is unplugged and > re-plugged. > > Regards, > Marvin Scholz > >> doc/indevs.texi| 6 ++-- >> libavdevice/avfoundation.m | 60 ++ >> 2 files changed, 58 insertions(+), 8 deletions(-) >> >> diff --git a/doc/indevs.texi b/doc/indevs.texi >> index 5be647f70a..8345b64a28 100644 >> --- a/doc/indevs.texi >> +++ b/doc/indevs.texi >> @@ -114,7 +114,7 @@ The input filename has to be given in the following >> syntax: >> -i "[[VIDEO]:[AUDIO]]" >> @end example >> The first entry selects the video input while the latter selects the audio >> input. >> -The stream has to be specified by the device name or the device index as >> shown by the device list. >> +The stream has to be specified by the device name, index or digest as shown >> by the device list. >> Alternatively, the video and/or audio input device can be chosen by index >> using the >> @option{ >>-video_device_index >> @@ -127,7 +127,9 @@ and/or >> device name or index given in the input filename. >> >> All available devices can be enumerated by using @option{-list_devices >> true}, listing >> -all device names and corresponding indices. >> +all device names, corresponding indices and digests, when available. Device >> name can be >> +tricky to use when localized and device index can change when devices are >> plugged or unplugged. A device >> +hash, when available, uniquely identifies a device and should not change >> over time. >> >> There are two device name aliases: >> @table @code >> diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m >> index 95414fd16a..bede51bda0 100644 >> --- a/libavdevice/avfoundation.m >> +++ b/libavdevice/avfoundation.m >> @@ -26,6 +26,7 @@ >> */ >> >> #import >> +#import >> >> #include "libavutil/channel_layout.h" >> #include "libavutil/pixdesc.h" >> @@ -79,6 +80,28 @@ >>{ AV_PIX_FMT_NONE, 0 } >> }; >> >> +#define DEVICES_DIGEST_LENGTH 8 >> + >> +@interface AvdeviceAvfoundationDigest : NSObject >> ++ (NSString *)fromString:(NSString *)input; >> +@end >> + >> +@implementation AvdeviceAvfoundationDigest : NSObject >> ++ (NSString *) fromString:(NSString *)input { >> +const char *cStr = [input UTF8String]; >> +unsigned char digest[CC_SHA256_DIGEST_LENGTH]; >> +CC_SHA256( cStr, strlen(cStr), digest ); >> + >> +NSMutableString *output = [NSMutableString >> stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; >> + >> +for(int i = 0; i <
Re: [FFmpeg-devel] [PATCH v2 02/03] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length.
Just sent an updated patch here: http://ffmpeg.org/pipermail/ffmpeg-devel/2021-December/289684.html > On Dec 13, 2021, at 3:12 PM, Marvin Scholz wrote: > > > > On 13 Dec 2021, at 21:29, Romain Beauxis wrote: > >>> On Dec 13, 2021, at 12:56 PM, Marvin Scholz wrote: >>> >>> >>> >>> On 13 Dec 2021, at 17:39, Romain Beauxis wrote: >>> >>>> This is the second patch of a series of 3 that cleanup and enhance the >>>> avfoundation implementation for libavdevice. >>>> >>>> This patch fixes the concurrency model. Avfoundation runs its own >>>> producing thread >>>> to send produced frames and ffmpeg runs its own thread to consume them. >>>> >>>> The existing implementation stores the last transmitted frame and uses a >>>> mutex >>>> to avoid concurrent access. However, this leads to situations where >>>> upcoming frames >>>> can be dropped if the ffmpeg thread is acessing the latest frame. This >>>> happens >>>> even when the thread would otherwise catch up and process frames fast >>>> enought. >>>> >>>> This patches changes this implementation to use a buffer queue with a max >>>> queue length >>>> and encapsulated thread-safety. This greatly simplifies the logic of the >>>> calling code >>>> and gives the consuming thread a chance to process all frames concurrently >>>> to the producing >>>> thread while avoiding memory leaks. >>> >>> Couldn't this just use CMSimpleQueue >>> https://developer.apple.com/documentation/coremedia/cmsimplequeue?language=objc >>> or CMBufferQueue? >> >> I’m happy to switch to this one, which seems more directly related to the >> task at hand if you think it is a better primitive. >> > > I did not check in details but if either of the existing implementations > referred to above do the task you need here, > I would prefer if it is used instead of writing your own implementation. > >>> The implementation of the queue in this patch does not seem right, see >>> review below. >>> >>>> >>>> Signed-off-by: Romain Beauxis >>>> --- >>>> libavdevice/avfoundation.m | 220 + >>>> 1 file changed, 127 insertions(+), 93 deletions(-) >>>> >>>> diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m >>>> index 79c9207cfa..95414fd16a 100644 >>>> --- a/libavdevice/avfoundation.m >>>> +++ b/libavdevice/avfoundation.m >>>> @@ -26,7 +26,6 @@ >>>> */ >>>> >>>> #import >>>> -#include >>>> >>>> #include "libavutil/channel_layout.h" >>>> #include "libavutil/pixdesc.h" >>>> @@ -80,13 +79,97 @@ >>>> { AV_PIX_FMT_NONE, 0 } >>>> }; >>>> >>>> +#define MAX_QUEUED_OBJECTS 10 >>>> + >>>> +@interface AvdeviceAvfoundationBuffer : NSObject >>>> ++ (AvdeviceAvfoundationBuffer *) >>>> fromCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer; >>>> +- (CMSampleBufferRef) getCMSampleBuffer; >>>> +@end >>>> + >>>> +@implementation AvdeviceAvfoundationBuffer { >>>> +CMSampleBufferRef sampleBuffer; >>>> +} >>>> + >>>> ++ (AvdeviceAvfoundationBuffer *) >>>> fromCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer { >>>> +return [[AvdeviceAvfoundationBuffer alloc] init:sampleBuffer]; >>>> +} >>>> + >>>> +- (id) init:(CMSampleBufferRef)buffer { >>>> +sampleBuffer = buffer; >>>> +return self; >>>> +} >>>> + >>>> +- (CMSampleBufferRef) getCMSampleBuffer { >>>> +return sampleBuffer; >>>> +} >>>> +@end >>>> + >>>> +@interface AvdeviceAvfoundationBufferQueue : NSObject >>>> +- (CMSampleBufferRef) dequeue; >>>> +- (NSUInteger) count; >>>> +- (void) enqueue:(CMSampleBufferRef)obj; >>>> +@end >>>> + >>>> +@implementation AvdeviceAvfoundationBufferQueue { >>>> +NSLock *mutex; >>>> +NSMutableArray *queue; >>>> +} >>>> + >>>> +- (id) init { >>>> +mutex = [[[NSLock alloc] init] retain]; >>>> +queue = [[[NSMutableArray a
[FFmpeg-devel] [PATCH v3 03/03] libavdevice/avfoundation.m: Allow to select devices by unique ID.
This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes since last version: * Switched unique ID to use system-prodvided unique ID * Implemented unique IDs for screen capture This patch adds a unique ID to avfoundation devices. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. Signed-off-by: Romain Beauxis --- doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 73 +- 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 5be647f70a..2b55399c8c 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or ID as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and IDs, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index b602cfbe95..036fb57568 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -39,6 +39,8 @@ #include "libavutil/imgutils.h" #include "avdevice.h" +#define CLEANUP_DEVICE_ID(s) [[s stringByReplacingOccurrencesOfString:@":" withString:@"."] UTF8String] + static const int avf_time_base = 100; static const AVRational avf_time_base_q = { @@ -797,21 +799,23 @@ static int avf_read_header(AVFormatContext *s) int index = 0; av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } for (AVCaptureDevice *device in devices_muxed) { -const char *name = [[device localizedName] UTF8String]; -index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +index= [devices count] + [devices_muxed indexOfObject:device]; +av_log(ctx, AV_LOG_INFO, "[%d] %s (ID: %s)\n", index, name, uniqueId); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, _screens); for (int i = 0; i < num_screens; i++) { -av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx->num_video_devices + i, i); +av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d (ID: AvfilterAvfoundationCptureScreen%d)\n", ctx->num_video_devices + i, i, screens[i]); } } #endif @@ -819,9 +823,10 @@ static int avf_read_header(AVFormatContext *s) av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n"); devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; for (AVCaptureDevice *device in devices) { -const char *name = [[device localizedName] UTF8String]; -int index = [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +const char *name = [[device localizedName] UTF8String]; +const char *uniqueId = CLEANUP_DEVICE_ID([device uniqueID]); +int index= [devices
[FFmpeg-devel] [PATCH v3 02/03] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length.
This is the second patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes since last version: * Switched queue implementation to CMSimpleQueue This patch fixes the concurrency model. Avfoundation runs its own producing thread to send produced frames and ffmpeg runs its own thread to consume them. The existing implementation stores the last transmitted frame and uses a mutex to avoid concurrent access. However, this leads to situations where upcoming frames can be dropped if the ffmpeg thread is acessing the latest frame. This happens even when the thread would otherwise catch up and process frames fast enought. This patches changes this implementation to use a buffer queue with a max queue length and encapsulated thread-safety. This greatly simplifies the logic of the calling code and gives the consuming thread a chance to process all frames concurrently to the producing thread while avoiding memory leaks. Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 169 + 1 file changed, 76 insertions(+), 93 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 79c9207cfa..b602cfbe95 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,7 @@ */ #import -#include +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -80,13 +80,12 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_FRAMES 10 + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -121,8 +120,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +CMSimpleQueueRef audio_frames_queue; +CMSimpleQueueRef video_frames_queue; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -131,16 +130,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -218,17 +207,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); -} - -_context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame); - -unlock_frames(_context); - -++_context->frames_captured; +CFRetain(videoFrame); +CMSimpleQueueEnqueue(_context->video_frames_queue, videoFrame); } @end @@ -262,17 +242,8 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)audioFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_audio_frame != nil) { -CFRelease(_context->current_audio_frame); -} - -_context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); - -unlock_frames(_context); - -++_context->audio_frames_captured; +CFRetain(audioFrame); +CMSimpleQueueEnqueue(_context->audio_frames_queue, audioFrame); } @end @@ -287,6 +258,30 @@ static void destroy_context(AVFContext* ctx) [ctx->avf_delegaterelease]; [ctx->avf_audio_delegate release]; +CMSampleBufferRef frame; + +if (ctx->video_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +do { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->video_frames_queue); +} while (frame); + +CFRelease(ctx->video_frames_queue); +ctx->video_frames_queue = NULL; +} + +if (ctx->audio_frames_queue) { +frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +do { + CFRelease(frame); + frame = (CMSampleBufferRef)CMSimpleQueueDequeue(ctx->audio_frames_queue); +} while (frame); + +CFRelease(ctx->audio_frames_queue); +ctx->audio_frames_queue = NULL; +} + ctx->capture_session = NULL; ctx->video_output= NULL; ctx->audio_output= NULL; @@ -297,12 +292,6 @@ static void destroy_context(AVFContext* ctx) AudioConverterDispose(ctx->audio_converter); ctx->audio_
[FFmpeg-devel] [PATCH v3 01/03] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
This is the first patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. Changes since previous version: none This patch: * Implements support for AudioConverter * Switches to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimizes data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis < toots at rastageeks.org> --- libavdevice/avfoundation.m | 250 + 1 file changed, 144 insertions(+), 106 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..79c9207cfa 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,10 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked; -ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved; - -if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_float && -ctx->audio_bits_per_sample == 32 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 16 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->aud
Re: [FFmpeg-devel] [PATCH v2 02/03] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length.
> On Dec 13, 2021, at 12:56 PM, Marvin Scholz wrote: > > > > On 13 Dec 2021, at 17:39, Romain Beauxis wrote: > >> This is the second patch of a series of 3 that cleanup and enhance the >> avfoundation implementation for libavdevice. >> >> This patch fixes the concurrency model. Avfoundation runs its own producing >> thread >> to send produced frames and ffmpeg runs its own thread to consume them. >> >> The existing implementation stores the last transmitted frame and uses a >> mutex >> to avoid concurrent access. However, this leads to situations where upcoming >> frames >> can be dropped if the ffmpeg thread is acessing the latest frame. This >> happens >> even when the thread would otherwise catch up and process frames fast >> enought. >> >> This patches changes this implementation to use a buffer queue with a max >> queue length >> and encapsulated thread-safety. This greatly simplifies the logic of the >> calling code >> and gives the consuming thread a chance to process all frames concurrently >> to the producing >> thread while avoiding memory leaks. > > Couldn't this just use CMSimpleQueue > https://developer.apple.com/documentation/coremedia/cmsimplequeue?language=objc > or CMBufferQueue? I’m happy to switch to this one, which seems more directly related to the task at hand if you think it is a better primitive. > The implementation of the queue in this patch does not seem right, see review > below. > >> >> Signed-off-by: Romain Beauxis >> --- >> libavdevice/avfoundation.m | 220 + >> 1 file changed, 127 insertions(+), 93 deletions(-) >> >> diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m >> index 79c9207cfa..95414fd16a 100644 >> --- a/libavdevice/avfoundation.m >> +++ b/libavdevice/avfoundation.m >> @@ -26,7 +26,6 @@ >> */ >> >> #import >> -#include >> >> #include "libavutil/channel_layout.h" >> #include "libavutil/pixdesc.h" >> @@ -80,13 +79,97 @@ >>{ AV_PIX_FMT_NONE, 0 } >> }; >> >> +#define MAX_QUEUED_OBJECTS 10 >> + >> +@interface AvdeviceAvfoundationBuffer : NSObject >> ++ (AvdeviceAvfoundationBuffer *) >> fromCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer; >> +- (CMSampleBufferRef) getCMSampleBuffer; >> +@end >> + >> +@implementation AvdeviceAvfoundationBuffer { >> +CMSampleBufferRef sampleBuffer; >> +} >> + >> ++ (AvdeviceAvfoundationBuffer *) >> fromCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer { >> +return [[AvdeviceAvfoundationBuffer alloc] init:sampleBuffer]; >> +} >> + >> +- (id) init:(CMSampleBufferRef)buffer { >> +sampleBuffer = buffer; >> +return self; >> +} >> + >> +- (CMSampleBufferRef) getCMSampleBuffer { >> +return sampleBuffer; >> +} >> +@end >> + >> +@interface AvdeviceAvfoundationBufferQueue : NSObject >> +- (CMSampleBufferRef) dequeue; >> +- (NSUInteger) count; >> +- (void) enqueue:(CMSampleBufferRef)obj; >> +@end >> + >> +@implementation AvdeviceAvfoundationBufferQueue { >> +NSLock *mutex; >> +NSMutableArray *queue; >> +} >> + >> +- (id) init { >> +mutex = [[[NSLock alloc] init] retain]; >> +queue = [[[NSMutableArray alloc] init] retain]; >> +return self; >> +} >> + >> +- (oneway void) release { >> +NSEnumerator *enumerator = [queue objectEnumerator]; >> +AvdeviceAvfoundationBuffer *buffer; >> + >> +while (buffer = [enumerator nextObject]) { >> +CFRelease([buffer getCMSampleBuffer]); >> +} >> + >> +[mutex release]; >> +[queue release]; >> +} > > Shouldn't this be done in dealloc instead of release? > Especially as retain is not subclassed, so this seems > like it could lead to over-releasing resources. I’m fairly new to objective-c’s memory model, I’ll double check those. > >> + >> +- (NSUInteger) count { >> +[mutex lock]; >> +NSUInteger c = [queue count]; >> +[mutex unlock]; >> +return c; >> +} > > This does not look right, the count can change after it is returned > and the caller does not hold a lock to prevent this. For a generic queue it is indeed. However, here, it is used in a monotonic fashion only: * One thread only increases the frame count by pushing new ones * One thread only decreases the frame count by pulling existing ones Frame count is only us
Re: [FFmpeg-devel] [PATCH v2 03/03] libavdevice/avfoundation.m: Allow to select devices by digest.
> On Dec 13, 2021, at 12:25 PM, Marvin Scholz wrote: > > On 13 Dec 2021, at 17:40, Romain Beauxis wrote: > >> This is the third patch of a series of 3 that cleanup and enhance the >> avfoundation implementation for libavdevice. >> >> This patch adds a digest to avfoundation devices, when available. This >> is needed because device index can change while the machine is running when >> devices are plugged or unplugged and device names can be tricky to use with >> localization >> and etc. >> >> The only device type that are excluded are screen capture because the logic >> to select >> them seems a little different and I wanted to minimized the changes. Also, >> for these >> devices, the name is localized in english, quite straight forward and should >> not change. >> >> Signed-off-by: Romain Beauxis >> --- > > > Hi, > thanks for the patch, however I fail to see the benefit of it. > You mention that using the name is complicated because it is localized, > but your patch just seems to use the device name and hashes it, which > does not mitigate the issues with the localized name (that could change > when the language is changed) but just hides it behind a hash, making > this problem even more obscure and confusing. > (Correct me if I read your patch wrong, but it seems to just do that.) > > Instead I think that you should use the uniqueID property of an > AVCaptureDevice, > documented here: > https://developer.apple.com/documentation/avfoundation/avcapturedevice/1390477-uniqueid?language=objc > > According to the docs, this seems more appropriated, as it does not depend on > the localization and does not change when the device is unplugged and > re-plugged. Oh great, I totally missed this one. Will submit a new version of the changes soon then, thanks! > >> doc/indevs.texi| 6 ++-- >> libavdevice/avfoundation.m | 60 ++ >> 2 files changed, 58 insertions(+), 8 deletions(-) >> >> diff --git a/doc/indevs.texi b/doc/indevs.texi >> index 5be647f70a..8345b64a28 100644 >> --- a/doc/indevs.texi >> +++ b/doc/indevs.texi >> @@ -114,7 +114,7 @@ The input filename has to be given in the following >> syntax: >> -i "[[VIDEO]:[AUDIO]]" >> @end example >> The first entry selects the video input while the latter selects the audio >> input. >> -The stream has to be specified by the device name or the device index as >> shown by the device list. >> +The stream has to be specified by the device name, index or digest as shown >> by the device list. >> Alternatively, the video and/or audio input device can be chosen by index >> using the >> @option{ >>-video_device_index >> @@ -127,7 +127,9 @@ and/or >> device name or index given in the input filename. >> >> All available devices can be enumerated by using @option{-list_devices >> true}, listing >> -all device names and corresponding indices. >> +all device names, corresponding indices and digests, when available. Device >> name can be >> +tricky to use when localized and device index can change when devices are >> plugged or unplugged. A device >> +hash, when available, uniquely identifies a device and should not change >> over time. >> >> There are two device name aliases: >> @table @code >> diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m >> index 95414fd16a..bede51bda0 100644 >> --- a/libavdevice/avfoundation.m >> +++ b/libavdevice/avfoundation.m >> @@ -26,6 +26,7 @@ >> */ >> >> #import >> +#import >> >> #include "libavutil/channel_layout.h" >> #include "libavutil/pixdesc.h" >> @@ -79,6 +80,28 @@ >>{ AV_PIX_FMT_NONE, 0 } >> }; >> >> +#define DEVICES_DIGEST_LENGTH 8 >> + >> +@interface AvdeviceAvfoundationDigest : NSObject >> ++ (NSString *)fromString:(NSString *)input; >> +@end >> + >> +@implementation AvdeviceAvfoundationDigest : NSObject >> ++ (NSString *) fromString:(NSString *)input { >> +const char *cStr = [input UTF8String]; >> +unsigned char digest[CC_SHA256_DIGEST_LENGTH]; >> +CC_SHA256( cStr, strlen(cStr), digest ); >> + >> +NSMutableString *output = [NSMutableString >> stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; >> + >> +for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) >> +[output appendFormat:@"%02x", digest[i]]; >> + >> +// The "d" prefix makes sure that
[FFmpeg-devel] [PATCH v2 03/03] libavdevice/avfoundation.m: Allow to select devices by digest.
This is the third patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. This patch adds a digest to avfoundation devices, when available. This is needed because device index can change while the machine is running when devices are plugged or unplugged and device names can be tricky to use with localization and etc. The only device type that are excluded are screen capture because the logic to select them seems a little different and I wanted to minimized the changes. Also, for these devices, the name is localized in english, quite straight forward and should not change. Signed-off-by: Romain Beauxis --- doc/indevs.texi| 6 ++-- libavdevice/avfoundation.m | 60 ++ 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 5be647f70a..8345b64a28 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -114,7 +114,7 @@ The input filename has to be given in the following syntax: -i "[[VIDEO]:[AUDIO]]" @end example The first entry selects the video input while the latter selects the audio input. -The stream has to be specified by the device name or the device index as shown by the device list. +The stream has to be specified by the device name, index or digest as shown by the device list. Alternatively, the video and/or audio input device can be chosen by index using the @option{ -video_device_index @@ -127,7 +127,9 @@ and/or device name or index given in the input filename. All available devices can be enumerated by using @option{-list_devices true}, listing -all device names and corresponding indices. +all device names, corresponding indices and digests, when available. Device name can be +tricky to use when localized and device index can change when devices are plugged or unplugged. A device +hash, when available, uniquely identifies a device and should not change over time. There are two device name aliases: @table @code diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 95414fd16a..bede51bda0 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,6 +26,7 @@ */ #import +#import #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -79,6 +80,28 @@ { AV_PIX_FMT_NONE, 0 } }; +#define DEVICES_DIGEST_LENGTH 8 + +@interface AvdeviceAvfoundationDigest : NSObject ++ (NSString *)fromString:(NSString *)input; +@end + +@implementation AvdeviceAvfoundationDigest : NSObject ++ (NSString *) fromString:(NSString *)input { +const char *cStr = [input UTF8String]; +unsigned char digest[CC_SHA256_DIGEST_LENGTH]; +CC_SHA256( cStr, strlen(cStr), digest ); + +NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2]; + +for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) +[output appendFormat:@"%02x", digest[i]]; + +// The "d" prefix makes sure that digest strings are never mistaken for numbers. +return [@"d" stringByAppendingString:[output substringToIndex:DEVICES_DIGEST_LENGTH]]; +} +@end + #define MAX_QUEUED_OBJECTS 10 @interface AvdeviceAvfoundationBuffer : NSObject @@ -860,13 +883,15 @@ static int avf_read_header(AVFormatContext *s) av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n"); for (AVCaptureDevice *device in devices) { const char *name = [[device localizedName] UTF8String]; +NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]]; index= [devices indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +av_log(ctx, AV_LOG_INFO, "[%d] %s (digest: %s)\n", index, name, [digest UTF8String]); } for (AVCaptureDevice *device in devices_muxed) { const char *name = [[device localizedName] UTF8String]; +NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]]; index= [devices count] + [devices_muxed indexOfObject:device]; -av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); +av_log(ctx, AV_LOG_INFO, "[%d] %s (digest: %s)\n", index, name, [digest UTF8String]); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { @@ -882,8 +907,9 @@ static int avf_read_header(AVFormatContext *s) devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; for (AVCaptureDevice *device in devices) { const char *name = [[device localizedName] UTF8String]; +NSString *digest = [AvdeviceAvfoundationDigest fromString:[[NSString alloc] initWithUTF8String:name]]; int index = [devices indexOfObject:device]; -av_log(ctx
[FFmpeg-devel] [PATCH v2 02/03] libavdevice/avfoundation.m: Replace mutex-based concurrency handling in avfoundation.m by a thread-safe fifo queue with maximum length.
This is the second patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. This patch fixes the concurrency model. Avfoundation runs its own producing thread to send produced frames and ffmpeg runs its own thread to consume them. The existing implementation stores the last transmitted frame and uses a mutex to avoid concurrent access. However, this leads to situations where upcoming frames can be dropped if the ffmpeg thread is acessing the latest frame. This happens even when the thread would otherwise catch up and process frames fast enought. This patches changes this implementation to use a buffer queue with a max queue length and encapsulated thread-safety. This greatly simplifies the logic of the calling code and gives the consuming thread a chance to process all frames concurrently to the producing thread while avoiding memory leaks. Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 220 + 1 file changed, 127 insertions(+), 93 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 79c9207cfa..95414fd16a 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -26,7 +26,6 @@ */ #import -#include #include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" @@ -80,13 +79,97 @@ { AV_PIX_FMT_NONE, 0 } }; +#define MAX_QUEUED_OBJECTS 10 + +@interface AvdeviceAvfoundationBuffer : NSObject ++ (AvdeviceAvfoundationBuffer *) fromCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer; +- (CMSampleBufferRef) getCMSampleBuffer; +@end + +@implementation AvdeviceAvfoundationBuffer { +CMSampleBufferRef sampleBuffer; +} + ++ (AvdeviceAvfoundationBuffer *) fromCMSampleBufferRef:(CMSampleBufferRef)sampleBuffer { +return [[AvdeviceAvfoundationBuffer alloc] init:sampleBuffer]; +} + +- (id) init:(CMSampleBufferRef)buffer { +sampleBuffer = buffer; +return self; +} + +- (CMSampleBufferRef) getCMSampleBuffer { +return sampleBuffer; +} +@end + +@interface AvdeviceAvfoundationBufferQueue : NSObject +- (CMSampleBufferRef) dequeue; +- (NSUInteger) count; +- (void) enqueue:(CMSampleBufferRef)obj; +@end + +@implementation AvdeviceAvfoundationBufferQueue { +NSLock *mutex; +NSMutableArray *queue; +} + +- (id) init { +mutex = [[[NSLock alloc] init] retain]; +queue = [[[NSMutableArray alloc] init] retain]; +return self; +} + +- (oneway void) release { +NSEnumerator *enumerator = [queue objectEnumerator]; +AvdeviceAvfoundationBuffer *buffer; + +while (buffer = [enumerator nextObject]) { +CFRelease([buffer getCMSampleBuffer]); +} + +[mutex release]; +[queue release]; +} + +- (NSUInteger) count { +[mutex lock]; +NSUInteger c = [queue count]; +[mutex unlock]; +return c; +} + +- (CMSampleBufferRef) dequeue { +[mutex lock]; + +if ([queue count] < 1) { + [mutex unlock]; + return nil; +} + +AvdeviceAvfoundationBuffer *buffer = [queue objectAtIndex:0]; +CMSampleBufferRef sampleBuffer = [buffer getCMSampleBuffer]; +[queue removeObjectAtIndex:0]; +[mutex unlock]; + +return sampleBuffer; +} + +- (void) enqueue:(CMSampleBufferRef)buffer { +[mutex lock]; +while (MAX_QUEUED_OBJECTS < [queue count]) { + [queue removeObjectAtIndex:0]; +} +[queue addObject:[AvdeviceAvfoundationBuffer fromCMSampleBufferRef:(CMSampleBufferRef)CFRetain(buffer)]]; +[mutex unlock]; +} +@end + typedef struct { AVClass*class; -int frames_captured; -int audio_frames_captured; -pthread_mutex_t frame_lock; id avf_delegate; id avf_audio_delegate; @@ -121,8 +204,8 @@ AVCaptureSession *capture_session; AVCaptureVideoDataOutput *video_output; AVCaptureAudioDataOutput *audio_output; -CMSampleBufferRef current_frame; -CMSampleBufferRef current_audio_frame; +AvdeviceAvfoundationBufferQueue *audio_frames; +AvdeviceAvfoundationBufferQueue *video_frames; AVCaptureDevice *observed_device; #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 @@ -131,16 +214,6 @@ int observed_quit; } AVFContext; -static void lock_frames(AVFContext* ctx) -{ -pthread_mutex_lock(>frame_lock); -} - -static void unlock_frames(AVFContext* ctx) -{ -pthread_mutex_unlock(>frame_lock); -} - /** FrameReciever class - delegate for AVCaptureSession */ @interface AVFFrameReceiver : NSObject @@ -218,17 +291,7 @@ - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)videoFrame fromConnection:(AVCaptureConnection *)connection { -lock_frames(_context); - -if (_context->current_frame != nil) { -CFRelease(_context->current_frame); -} - -_context->current_frame = (CMSampleBufferRef
[FFmpeg-devel] [PATCH v2 01/03] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
This is the first patch of a series of 3 that cleanup and enhance the avfoundation implementation for libavdevice. This patch: * Implements support for AudioConverter * Switches to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimizes data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 250 + 1 file changed, 144 insertions(+), 106 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..79c9207cfa 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,10 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked; -ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved; - -if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_float && -ctx->audio_bits_per_sample == 32 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 16 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 24
Re: [FFmpeg-devel] [PATCH] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
> On Dec 7, 2021, at 7:21 AM, Thilo Borgmann wrote: > > Hi, > > will look at this soon (tm), ping me if I don‘t. Great, thank you! Would it be a good use of your time to send the two other patches that I have pending as well? — Romain ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
Re: [FFmpeg-devel] [PATCH] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
Hi there! Anyone interested in the patch below? It fixes an issue with some macos avfoundation input devices that return formats currently not supported by the implementation. I also have another important bugfix in the concurrency model of the implementation waiting for this to be merged first. Otherwise, is there any appropriate step to help getting this merged? Thanks for any insight! -- Romain > On Nov 30, 2021, at 12:02 AM, Romain Beauxis wrote: > > * Implement support for AudioConverter > * Switch to AudioConverter's API to convert unsupported PCM > formats (non-interleaved, non-packed) to supported formats > * Minimize data copy. > > This fixes: https://trac.ffmpeg.org/ticket/9502 > > API ref: > https://developer.apple.com/documentation/audiotoolbox/audio_converter_services > > Signed-off-by: Romain Beauxis > --- > libavdevice/avfoundation.m | 250 + > 1 file changed, 144 insertions(+), 106 deletions(-) > > diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m > index 0cd6e646d5..79c9207cfa 100644 > --- a/libavdevice/avfoundation.m > +++ b/libavdevice/avfoundation.m > @@ -111,16 +111,10 @@ > >int num_video_devices; > > -int audio_channels; > -int audio_bits_per_sample; > -int audio_float; > -int audio_be; > -int audio_signed_integer; > -int audio_packed; > -int audio_non_interleaved; > - > -int32_t *audio_buffer; > -int audio_buffer_size; > +UInt32audio_buffers; > +UInt32audio_channels; > +UInt32bytes_per_sample; > +AudioConverterRef audio_converter; > >enum AVPixelFormat pixel_format; > > @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) >ctx->avf_delegate= NULL; >ctx->avf_audio_delegate = NULL; > > -av_freep(>audio_buffer); > +if (ctx->audio_converter) { > + AudioConverterDispose(ctx->audio_converter); > + ctx->audio_converter = NULL; > +} > >pthread_mutex_destroy(>frame_lock); > > @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) >AVFContext *ctx = (AVFContext*)s->priv_data; >CMFormatDescriptionRef format_desc; >AVStream* stream = avformat_new_stream(s, NULL); > +AudioStreamBasicDescription output_format = {0}; > +int audio_bits_per_sample, audio_float, audio_be; > +int audio_signed_integer, audio_packed, audio_non_interleaved; > +int must_convert = 0; > >if (!stream) { >return 1; > @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) >avpriv_set_pts_info(stream, 64, 1, avf_time_base); > >format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); > -const AudioStreamBasicDescription *basic_desc = > CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); > +const AudioStreamBasicDescription *input_format = > CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); > > -if (!basic_desc) { > +if (!input_format) { >unlock_frames(ctx); >av_log(s, AV_LOG_ERROR, "audio format not available\n"); >return 1; >} > > +if (input_format->mFormatID != kAudioFormatLinearPCM) { > +unlock_frames(ctx); > +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the > moment\n"); > +return 1; > +} > + >stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; > -stream->codecpar->sample_rate= basic_desc->mSampleRate; > -stream->codecpar->channels = basic_desc->mChannelsPerFrame; > +stream->codecpar->sample_rate= input_format->mSampleRate; > +stream->codecpar->channels = input_format->mChannelsPerFrame; >stream->codecpar->channel_layout = > av_get_default_channel_layout(stream->codecpar->channels); > > -ctx->audio_channels= basic_desc->mChannelsPerFrame; > -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; > -ctx->audio_float = basic_desc->mFormatFlags & > kAudioFormatFlagIsFloat; > -ctx->audio_be = basic_desc->mFormatFlags & > kAudioFormatFlagIsBigEndian; > -ctx->audio_signed_integer = basic_desc->mFormatFlags & > kAudioFormatFlagIsSignedInteger; > -ctx->audio_packed = basic_desc->mFormatFlags & > kAudioFormatFlagIsPacked; > -ctx->audio_non_interleaved = basic_desc->mFormatFlags &
[FFmpeg-devel] [PATCH] libavdevice/avfoundation.m: use AudioConvert, extend supported formats
* Implement support for AudioConverter * Switch to AudioConverter's API to convert unsupported PCM formats (non-interleaved, non-packed) to supported formats * Minimize data copy. This fixes: https://trac.ffmpeg.org/ticket/9502 API ref: https://developer.apple.com/documentation/audiotoolbox/audio_converter_services Signed-off-by: Romain Beauxis --- libavdevice/avfoundation.m | 250 + 1 file changed, 144 insertions(+), 106 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index 0cd6e646d5..79c9207cfa 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -111,16 +111,10 @@ int num_video_devices; -int audio_channels; -int audio_bits_per_sample; -int audio_float; -int audio_be; -int audio_signed_integer; -int audio_packed; -int audio_non_interleaved; - -int32_t *audio_buffer; -int audio_buffer_size; +UInt32audio_buffers; +UInt32audio_channels; +UInt32bytes_per_sample; +AudioConverterRef audio_converter; enum AVPixelFormat pixel_format; @@ -299,7 +293,10 @@ static void destroy_context(AVFContext* ctx) ctx->avf_delegate= NULL; ctx->avf_audio_delegate = NULL; -av_freep(>audio_buffer); +if (ctx->audio_converter) { + AudioConverterDispose(ctx->audio_converter); + ctx->audio_converter = NULL; +} pthread_mutex_destroy(>frame_lock); @@ -673,6 +670,10 @@ static int get_audio_config(AVFormatContext *s) AVFContext *ctx = (AVFContext*)s->priv_data; CMFormatDescriptionRef format_desc; AVStream* stream = avformat_new_stream(s, NULL); +AudioStreamBasicDescription output_format = {0}; +int audio_bits_per_sample, audio_float, audio_be; +int audio_signed_integer, audio_packed, audio_non_interleaved; +int must_convert = 0; if (!stream) { return 1; @@ -690,60 +691,95 @@ static int get_audio_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); -const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); +const AudioStreamBasicDescription *input_format = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); -if (!basic_desc) { +if (!input_format) { unlock_frames(ctx); av_log(s, AV_LOG_ERROR, "audio format not available\n"); return 1; } +if (input_format->mFormatID != kAudioFormatLinearPCM) { +unlock_frames(ctx); +av_log(s, AV_LOG_ERROR, "only PCM audio format are supported at the moment\n"); +return 1; +} + stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; -stream->codecpar->sample_rate= basic_desc->mSampleRate; -stream->codecpar->channels = basic_desc->mChannelsPerFrame; +stream->codecpar->sample_rate= input_format->mSampleRate; +stream->codecpar->channels = input_format->mChannelsPerFrame; stream->codecpar->channel_layout = av_get_default_channel_layout(stream->codecpar->channels); -ctx->audio_channels= basic_desc->mChannelsPerFrame; -ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel; -ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat; -ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian; -ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger; -ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked; -ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved; - -if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_float && -ctx->audio_bits_per_sample == 32 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 16 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE; -} else if (basic_desc->mFormatID == kAudioFormatLinearPCM && -ctx->audio_signed_integer && -ctx->audio_bits_per_sample == 24 && -ctx->audio_packed) { -stream->codecpar->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S24BE : A