diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
index 61dac4b713..3f52afd8c9 100644
|
a
|
b
|
|
| 82 | 82 | { AV_PIX_FMT_NONE, 0 } |
| 83 | 83 | }; |
| 84 | 84 | |
| | 85 | #define AVF_FRAME_LIST_LENGTH 4 |
| | 86 | |
| | 87 | typedef struct |
| | 88 | { |
| | 89 | size_t write_index; |
| | 90 | size_t read_index; |
| | 91 | CMSampleBufferRef frames[AVF_FRAME_LIST_LENGTH]; |
| | 92 | } AVFFrameList; |
| | 93 | |
| | 94 | static void push_frame(AVFFrameList* list, CMSampleBufferRef frame) |
| | 95 | { |
| | 96 | list->frames[list->write_index] = (CMSampleBufferRef)CFRetain(frame); |
| | 97 | list->write_index = (list->write_index + 1) % AVF_FRAME_LIST_LENGTH; |
| | 98 | |
| | 99 | if (list->write_index == list->read_index) { |
| | 100 | CFRelease(list->frames[list->read_index]); |
| | 101 | list->read_index = (list->read_index + 1) % AVF_FRAME_LIST_LENGTH; |
| | 102 | } |
| | 103 | } |
| | 104 | |
| | 105 | static CMSampleBufferRef peek_frame(AVFFrameList* list) |
| | 106 | { |
| | 107 | if (list->write_index != list->read_index) |
| | 108 | return list->frames[list->read_index]; |
| | 109 | |
| | 110 | return nil; |
| | 111 | } |
| | 112 | |
| | 113 | static void pop_frame(AVFFrameList* list) |
| | 114 | { |
| | 115 | if (list->write_index != list->read_index) { |
| | 116 | CFRelease(list->frames[list->read_index]); |
| | 117 | list->read_index = (list->read_index + 1) % AVF_FRAME_LIST_LENGTH; |
| | 118 | } |
| | 119 | } |
| | 120 | |
| 85 | 121 | typedef struct |
| 86 | 122 | { |
| 87 | 123 | AVClass* class; |
| … |
… |
|
| 131 | 167 | AVCaptureVideoDataOutput *video_output; |
| 132 | 168 | AVCaptureAudioDataOutput *audio_output; |
| 133 | 169 | CMSampleBufferRef current_frame; |
| 134 | | CMSampleBufferRef current_audio_frame; |
| | 170 | AVFFrameList audio_frames; |
| 135 | 171 | |
| 136 | 172 | AVCaptureDevice *observed_device; |
| 137 | 173 | #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 |
| … |
… |
- (id)initWithContext:(AVFContext*)context
|
| 263 | 299 | { |
| 264 | 300 | if (self = [super init]) { |
| 265 | 301 | _context = context; |
| | 302 | _context->audio_frames.write_index = 0; |
| | 303 | _context->audio_frames.read_index = 0; |
| 266 | 304 | } |
| 267 | 305 | return self; |
| 268 | 306 | } |
| … |
… |
- (void) captureOutput:(AVCaptureOutput *)captureOutput
|
| 273 | 311 | { |
| 274 | 312 | lock_frames(_context); |
| 275 | 313 | |
| 276 | | if (_context->current_audio_frame != nil) { |
| 277 | | CFRelease(_context->current_audio_frame); |
| 278 | | } |
| 279 | | |
| 280 | | _context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame); |
| | 314 | push_frame(&_context->audio_frames, audioFrame); |
| 281 | 315 | |
| 282 | 316 | unlock_frames(_context); |
| 283 | 317 | |
| … |
… |
static int get_audio_config(AVFormatContext *s)
|
| 695 | 729 | |
| 696 | 730 | avpriv_set_pts_info(stream, 64, 1, avf_time_base); |
| 697 | 731 | |
| 698 | | format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame); |
| | 732 | format_desc = CMSampleBufferGetFormatDescription(peek_frame(&ctx->audio_frames)); |
| 699 | 733 | const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc); |
| 700 | 734 | |
| 701 | 735 | if (!basic_desc) { |
| … |
… |
static int get_audio_config(AVFormatContext *s)
|
| 743 | 777 | } |
| 744 | 778 | |
| 745 | 779 | if (ctx->audio_non_interleaved) { |
| 746 | | CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame); |
| | 780 | CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(peek_frame(&ctx->audio_frames)); |
| 747 | 781 | ctx->audio_buffer_size = CMBlockBufferGetDataLength(block_buffer); |
| 748 | 782 | ctx->audio_buffer = av_malloc(ctx->audio_buffer_size); |
| 749 | 783 | if (!ctx->audio_buffer) { |
| … |
… |
static int get_audio_config(AVFormatContext *s)
|
| 753 | 787 | } |
| 754 | 788 | } |
| 755 | 789 | |
| 756 | | CFRelease(ctx->current_audio_frame); |
| 757 | | ctx->current_audio_frame = nil; |
| | 790 | pop_frame(&ctx->audio_frames); |
| 758 | 791 | |
| 759 | 792 | unlock_frames(ctx); |
| 760 | 793 | |
| … |
… |
static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
| 1171 | 1204 | unlock_frames(ctx); |
| 1172 | 1205 | return status; |
| 1173 | 1206 | } |
| 1174 | | } else if (ctx->current_audio_frame != nil) { |
| 1175 | | CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame); |
| | 1207 | } else if (peek_frame(&ctx->audio_frames) != nil) { |
| | 1208 | CMSampleBufferRef frame = peek_frame(&ctx->audio_frames); |
| | 1209 | CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(frame); |
| 1176 | 1210 | int block_buffer_size = CMBlockBufferGetDataLength(block_buffer); |
| 1177 | 1211 | |
| 1178 | 1212 | if (!block_buffer || !block_buffer_size) { |
| … |
… |
static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
| 1193 | 1227 | CMItemCount count; |
| 1194 | 1228 | CMSampleTimingInfo timing_info; |
| 1195 | 1229 | |
| 1196 | | if (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_audio_frame, 1, &timing_info, &count) == noErr) { |
| | 1230 | if (CMSampleBufferGetOutputSampleTimingInfoArray(frame, 1, &timing_info, &count) == noErr) { |
| 1197 | 1231 | AVRational timebase_q = av_make_q(1, timing_info.presentationTimeStamp.timescale); |
| 1198 | 1232 | pkt->pts = pkt->dts = av_rescale_q(timing_info.presentationTimeStamp.value, timebase_q, avf_time_base_q); |
| 1199 | 1233 | } |
| … |
… |
static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
| 1247 | 1281 | } |
| 1248 | 1282 | } |
| 1249 | 1283 | |
| 1250 | | CFRelease(ctx->current_audio_frame); |
| 1251 | | ctx->current_audio_frame = nil; |
| | 1284 | pop_frame(&ctx->audio_frames); |
| 1252 | 1285 | } else { |
| 1253 | 1286 | pkt->data = NULL; |
| 1254 | 1287 | unlock_frames(ctx); |