4141#define VSYNC_DROP 0xff
4242
4343@interface FFStream : NSObject
44+ @property (nonatomic ) AVRational frameRate;
4445@property (nonatomic ) AVStream *stream;
4546- (id ) initWithStream : (AVStream*)newStream ;
4647@end
@@ -55,12 +56,48 @@ - (id) initWithStream:(AVStream *)newStream {
5556}
5657@end
5758
59+ @interface FFInputStream : FFStream
60+ /* predicted dts of the next packet read for this stream or (when there are
61+ * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
62+ @property (nonatomic ) int64_t nextDTS;
63+ @property (nonatomic ) int64_t DTS; // /< dts of the last packet read for this stream (in AV_TIME_BASE units)
64+
65+ @property (nonatomic ) int64_t nextPTS; // /< synthetic pts for the next decode frame (in AV_TIME_BASE units)
66+ @property (nonatomic ) int64_t PTS; // /< current pts of the decoded frame (in AV_TIME_BASE units)
67+ @property (nonatomic ) int64_t filterInRescaleDeltaLast;
68+
69+ @property (nonatomic ) BOOL sawFirstTS;
70+ @end
71+
72+ @implementation FFInputStream
73+ @synthesize nextDTS, DTS, nextPTS, PTS;
74+ - (id ) initWithStream : (AVStream *)newStream {
75+ if (self = [super initWithStream: newStream]) {
76+ self.nextPTS = AV_NOPTS_VALUE;
77+ self.PTS = AV_NOPTS_VALUE;
78+ self.nextDTS = AV_NOPTS_VALUE;
79+ self.DTS = AV_NOPTS_VALUE;
80+ self.filterInRescaleDeltaLast = AV_NOPTS_VALUE;
81+ self.sawFirstTS = NO ;
82+ }
83+ return self;
84+ }
85+ @end
86+
5887@interface FFOutputStream : FFStream
5988@property (nonatomic ) int64_t lastMuxDTS;
89+ @property (nonatomic ) int frameNumber;
6090@end
6191
6292@implementation FFOutputStream
63- @synthesize lastMuxDTS;
93+ @synthesize lastMuxDTS, frameNumber;
94+ - (id ) initWithStream : (AVStream *)newStream {
95+ if (self = [super initWithStream: newStream]) {
96+ self.lastMuxDTS = AV_NOPTS_VALUE;
97+ self.frameNumber = 0 ;
98+ }
99+ return self;
100+ }
64101@end
65102
66103@implementation FFmpegWrapper
@@ -103,6 +140,136 @@ + (NSError*) errorWithCode:(int)errorCode localizedDescription:(NSString*)descri
103140 return [NSError errorWithDomain: kFFmpegErrorDomain code: errorCode userInfo: userInfo];
104141}
105142
143+ + (void ) copyInputStream : (FFInputStream*)inputStream outputStream : (FFOutputStream*)outputStream packet : (AVPacket*)packet outputFormatContext : (AVFormatContext*)outputFormatContext
144+ {
145+ int64_t ost_tb_start_time = av_rescale_q (0 , AV_TIME_BASE_Q, outputStream.stream ->time_base );
146+ AVPicture picture;
147+ AVPacket outputPacket;
148+
149+ av_init_packet (&outputPacket);
150+
151+ if (packet->pts != AV_NOPTS_VALUE)
152+ outputPacket.pts = av_rescale_q (packet->pts , inputStream.stream ->time_base , outputStream.stream ->time_base ) - ost_tb_start_time;
153+ else
154+ outputPacket.pts = AV_NOPTS_VALUE;
155+
156+ if (packet->dts == AV_NOPTS_VALUE)
157+ outputPacket.dts = av_rescale_q (inputStream.DTS , AV_TIME_BASE_Q, outputStream.stream ->time_base );
158+ else
159+ outputPacket.dts = av_rescale_q (packet->dts , inputStream.stream ->time_base , outputStream.stream ->time_base );
160+ outputPacket.dts -= ost_tb_start_time;
161+
162+ if (outputStream.stream ->codec ->codec_type == AVMEDIA_TYPE_AUDIO && packet->dts != AV_NOPTS_VALUE) {
163+ int duration = av_get_audio_frame_duration (inputStream.stream ->codec , packet->size );
164+ if (!duration)
165+ duration = inputStream.stream ->codec ->frame_size ;
166+ int64_t filter_in_rescale_delta_last;
167+ outputPacket.dts = outputPacket.pts = av_rescale_delta (inputStream.stream ->time_base , packet->dts ,
168+ (AVRational){1 , inputStream.stream ->codec ->sample_rate }, duration, &filter_in_rescale_delta_last,
169+ outputStream.stream ->time_base ) - ost_tb_start_time;
170+ inputStream.filterInRescaleDeltaLast = filter_in_rescale_delta_last;
171+ }
172+
173+ outputPacket.duration = av_rescale_q (packet->duration , inputStream.stream ->time_base , outputStream.stream ->time_base );
174+ outputPacket.flags = packet->flags ;
175+
176+ // FIXME remove the following 2 lines they shall be replaced by the bitstream filters
177+ if ( outputStream.stream ->codec ->codec_id != AV_CODEC_ID_H264
178+ && outputStream.stream ->codec ->codec_id != AV_CODEC_ID_MPEG1VIDEO
179+ && outputStream.stream ->codec ->codec_id != AV_CODEC_ID_MPEG2VIDEO
180+ && outputStream.stream ->codec ->codec_id != AV_CODEC_ID_VC1
181+ ) {
182+ if (av_parser_change (inputStream.stream ->parser , outputStream.stream ->codec , &outputPacket.data , &outputPacket.size , packet->data , packet->size , packet->flags & AV_PKT_FLAG_KEY)) {
183+ outputPacket.buf = av_buffer_create (outputPacket.data , outputPacket.size , av_buffer_default_free, NULL , 0 );
184+ if (!outputPacket.buf ) {
185+ NSLog (@" couldnt allocate packet buffer" );
186+ }
187+ }
188+ } else {
189+ outputPacket.data = packet->data ;
190+ outputPacket.size = packet->size ;
191+ }
192+
193+ if (outputStream.stream ->codec ->codec_type == AVMEDIA_TYPE_VIDEO && (outputFormatContext->oformat ->flags & AVFMT_RAWPICTURE)) {
194+ /* store AVPicture in AVPacket, as expected by the output format */
195+ avpicture_fill (&picture, outputPacket.data , outputStream.stream ->codec ->pix_fmt , outputStream.stream ->codec ->width , outputStream.stream ->codec ->height );
196+ outputPacket.data = (uint8_t *)&picture;
197+ outputPacket.size = sizeof (AVPicture);
198+ outputPacket.flags |= AV_PKT_FLAG_KEY;
199+ }
200+
201+ // write_frame(of->ctx, &outputPacket, ost);
202+ outputStream.stream ->codec ->frame_number ++;
203+ }
204+
205+
206+ /* pkt = NULL means EOF (needed to flush decoder buffers) */
207+ + (int ) processInputStream : (FFInputStream*)inputStream outputStream : (FFOutputStream*)outputStream packet : (AVPacket*)packet outputFormatContext : (AVFormatContext*)outputFormatContext
208+ {
209+ AVPacket avpkt;
210+ if (!inputStream.sawFirstTS ) {
211+ inputStream.DTS = inputStream.stream ->avg_frame_rate .num ? - inputStream.stream ->codec ->has_b_frames * AV_TIME_BASE / av_q2d (inputStream.stream ->avg_frame_rate ) : 0 ;
212+ inputStream.PTS = 0 ;
213+ if (packet != NULL && packet->pts != AV_NOPTS_VALUE) {
214+ inputStream.DTS += av_rescale_q (packet->pts , inputStream.stream ->time_base , AV_TIME_BASE_Q);
215+ inputStream.PTS = inputStream.DTS ; // unused but better to set it to a value thats not totally wrong
216+ }
217+ inputStream.sawFirstTS = YES ;
218+ }
219+
220+ if (inputStream.nextDTS == AV_NOPTS_VALUE)
221+ inputStream.nextDTS = inputStream.DTS ;
222+ if (inputStream.nextPTS == AV_NOPTS_VALUE)
223+ inputStream.nextPTS = inputStream.PTS ;
224+
225+ if (packet == NULL ) {
226+ /* EOF handling */
227+ av_init_packet (&avpkt);
228+ avpkt.data = NULL ;
229+ avpkt.size = 0 ;
230+ // goto handle_eof;
231+ } else {
232+ avpkt = *packet;
233+ }
234+
235+ if (packet->dts != AV_NOPTS_VALUE) {
236+ inputStream.nextDTS = inputStream.DTS = av_rescale_q (packet->dts , inputStream.stream ->time_base , AV_TIME_BASE_Q);
237+ inputStream.nextPTS = inputStream.PTS = inputStream.DTS ;
238+ }
239+
240+ /* handle stream copy */
241+ inputStream.DTS = inputStream.nextDTS ;
242+ switch (inputStream.stream ->codec ->codec_type ) {
243+ case AVMEDIA_TYPE_AUDIO:
244+ inputStream.nextDTS += ((int64_t )AV_TIME_BASE * inputStream.stream ->codec ->frame_size ) /
245+ inputStream.stream ->codec ->sample_rate ;
246+ break ;
247+ case AVMEDIA_TYPE_VIDEO:
248+ if (inputStream.frameRate .num ) {
249+ // TODO: Remove work-around for c99-to-c89 issue 7
250+ AVRational time_base_q = AV_TIME_BASE_Q;
251+ int64_t next_dts = av_rescale_q (inputStream.nextDTS , time_base_q, av_inv_q (inputStream.frameRate ));
252+ inputStream.nextDTS = av_rescale_q (next_dts + 1 , av_inv_q (inputStream.frameRate ), time_base_q);
253+ } else if (packet->duration ) {
254+ inputStream.nextDTS += av_rescale_q (packet->duration , inputStream.stream ->time_base , AV_TIME_BASE_Q);
255+ } else if (inputStream.stream ->codec ->time_base .num != 0 ) {
256+ int ticks= inputStream.stream ->parser ? inputStream.stream ->parser ->repeat_pict + 1 : inputStream.stream ->codec ->ticks_per_frame ;
257+ inputStream.nextDTS += ((int64_t )AV_TIME_BASE *
258+ inputStream.stream ->codec ->time_base .num * ticks) /
259+ inputStream.stream ->codec ->time_base .den ;
260+ }
261+ break ;
262+ default :
263+ break ;
264+ }
265+ inputStream.PTS = inputStream.DTS ;
266+ inputStream.nextPTS = inputStream.nextDTS ;
267+
268+ [[self class ] copyInputStream: inputStream outputStream: outputStream packet: packet outputFormatContext: outputFormatContext];
269+
270+ return 0 ;
271+ }
272+
106273+ (NSError *) errorForAVErrorNumber : (int )errorNumber {
107274 NSString *description = [self stringForAVErrorNumber: errorNumber];
108275 return [self errorWithCode: errorNumber localizedDescription: description];
@@ -122,6 +289,7 @@ - (void) convertInputPath:(NSString*)inputPath outputPath:(NSString*)outputPath
122289 BOOL success = NO ;
123290 int video_sync_method = VSYNC_PASSTHROUGH;
124291 int audio_sync_method = 0 ;
292+ int64_t videoDTS = 0 ;
125293 NSError *error = nil ;
126294 NSFileManager *fileManager = [NSFileManager defaultManager ];
127295 NSDictionary *inputFileAttributes = [fileManager attributesOfItemAtPath: inputPath error: &error];
@@ -180,11 +348,13 @@ - (void) convertInputPath:(NSString*)inputPath outputPath:(NSString*)outputPath
180348 int copy_tb = -1 ;
181349 for (int i = 0 ; i < inputStreamCount; i++) {
182350 AVStream *inputStream = inputFormatContext->streams [i];
183- [inputStreams addObject: [[FFStream alloc ] initWithStream: inputStream]];
351+ FFInputStream *ffInputStream = [[FFInputStream alloc ] initWithStream: inputStream];
352+ [inputStreams addObject: ffInputStream];
184353 AVCodecContext *inputCodecContext = inputStream->codec ;
185354 AVCodec *outputCodec = avcodec_find_encoder (inputCodecContext->codec_id );
186355 AVStream *outputStream = avformat_new_stream (outputFormatContext, outputCodec);
187- [outputStreams addObject: [[FFOutputStream alloc ] initWithStream: outputStream]];
356+ FFOutputStream *ffOutputStream = [[FFOutputStream alloc ] initWithStream: outputStream];
357+ [outputStreams addObject: ffOutputStream];
188358
189359 AVCodecContext *outputCodecContext = outputStream->codec ;
190360
@@ -252,6 +422,11 @@ - (void) convertInputPath:(NSString*)inputPath outputPath:(NSString*)outputPath
252422 outputCodecContext->time_base = inputCodecContext->time_base ;
253423 }
254424
425+ if (ffInputStream && !ffOutputStream.frameRate .num )
426+ ffOutputStream.frameRate = ffInputStream.frameRate ;
427+ if (ffOutputStream.frameRate .num )
428+ outputCodecContext->time_base = av_inv_q (ffOutputStream.frameRate );
429+
255430 av_reduce (&outputCodecContext->time_base .num , &outputCodecContext->time_base .den ,
256431 outputCodecContext->time_base .num , outputCodecContext->time_base .den , INT_MAX);
257432
@@ -273,8 +448,12 @@ - (void) convertInputPath:(NSString*)inputPath outputPath:(NSString*)outputPath
273448 outputCodecContext->width = inputCodecContext->width ;
274449 outputCodecContext->height = inputCodecContext->height ;
275450 outputCodecContext->has_b_frames = inputCodecContext->has_b_frames ;
276- sar = inputCodecContext->sample_aspect_ratio ;
277- break ;
451+ if (inputStream->sample_aspect_ratio .num )
452+ sar = inputStream->sample_aspect_ratio ;
453+ else
454+ sar = inputCodecContext->sample_aspect_ratio ;
455+ outputStream->sample_aspect_ratio = inputCodecContext->sample_aspect_ratio = sar;
456+ outputStream->avg_frame_rate = inputStream->avg_frame_rate ; break ;
278457 case AVMEDIA_TYPE_SUBTITLE:
279458 outputCodecContext->width = inputCodecContext->width ;
280459 outputCodecContext->height = inputCodecContext->height ;
@@ -329,6 +508,9 @@ - (void) convertInputPath:(NSString*)inputPath outputPath:(NSString*)outputPath
329508 }
330509
331510 FFOutputStream *ffOutputStream = [outputStreams objectAtIndex: packet->stream_index];
511+ FFInputStream *ffInputStream = [inputStreams objectAtIndex: packet->stream_index];
512+
513+ [[self class ] processInputStream: ffInputStream outputStream: ffOutputStream packet: packet outputFormatContext: outputFormatContext];
332514
333515 AVStream *outputStream = ffOutputStream.stream ;
334516
0 commit comments