У меня есть файлы MPEG-TS на устройстве. Я хотел бы сократить довольно точное время с момента запуска файлов на устройстве.
Используя FFmpegWrapper в качестве базы, я надеюсь достичь этого.
Я немного потерял API C API ffmpeg. С чего начать?
Я попытался просто отбросить все пакеты до начала PTS, который я искал, но это сломало видеопоток.
packet->pts = av_rescale_q(packet->pts, inputStream.stream->time_base, outputStream.stream->time_base);
packet->dts = av_rescale_q(packet->dts, inputStream.stream->time_base, outputStream.stream->time_base);
if(startPts == 0){
startPts = packet->pts;
}
if(packet->pts < cutTimeStartPts + startPts){
av_free_packet(packet);
continue;
}
Как отрезать часть начала входного файла без разрушения видеопотока? Когда вы играете спина к спине, я хочу, чтобы 2 срезанных сегмента выполнялись вместе.
ffmpeg -i time.ts -c:v libx264 -c:a copy -ss $CUT_POINT -map 0 -y after.ts
ffmpeg -i time.ts -c:v libx264 -c:a copy -to $CUT_POINT -map 0 -y before.ts
Кажется, это то, что мне нужно. Я думаю, что требуется повторное кодирование, чтобы видео могло начинаться с любой произвольной точки, а не с существующего ключевого кадра. Если есть более эффективное решение, это здорово. Если нет, это достаточно хорошо.
EDIT: Здесь моя попытка. Я собираю различные элементы, которые я не совсем понимаю, скопировал из здесь. Я сейчас ухожу от "разрезающей" части, чтобы попытаться получить аудио + видео, закодированные без сложностей слоев. Я получаю EXC_BAD_ACCESS на avcodec_encode_video2(...)
- (void)convertInputPath:(NSString *)inputPath outputPath:(NSString *)outputPath
options:(NSDictionary *)options progressBlock:(FFmpegWrapperProgressBlock)progressBlock
completionBlock:(FFmpegWrapperCompletionBlock)completionBlock {
dispatch_async(conversionQueue, ^{
FFInputFile *inputFile = nil;
FFOutputFile *outputFile = nil;
NSError *error = nil;
inputFile = [[FFInputFile alloc] initWithPath:inputPath options:options];
outputFile = [[FFOutputFile alloc] initWithPath:outputPath options:options];
[self setupDirectStreamCopyFromInputFile:inputFile outputFile:outputFile];
if (![outputFile openFileForWritingWithError:&error]) {
[self finishWithSuccess:NO error:error completionBlock:completionBlock];
return;
}
if (![outputFile writeHeaderWithError:&error]) {
[self finishWithSuccess:NO error:error completionBlock:completionBlock];
return;
}
AVRational default_timebase;
default_timebase.num = 1;
default_timebase.den = AV_TIME_BASE;
FFStream *outputVideoStream = outputFile.streams[0];
FFStream *inputVideoStream = inputFile.streams[0];
AVFrame *frame;
AVPacket inPacket, outPacket;
frame = avcodec_alloc_frame();
av_init_packet(&inPacket);
while (av_read_frame(inputFile.formatContext, &inPacket) >= 0) {
if (inPacket.stream_index == 0) {
int frameFinished;
avcodec_decode_video2(inputVideoStream.stream->codec, frame, &frameFinished, &inPacket);
// if (frameFinished && frame->pkt_pts >= starttime_int64 && frame->pkt_pts <= endtime_int64) {
if (frameFinished){
av_init_packet(&outPacket);
int output;
avcodec_encode_video2(outputVideoStream.stream->codec, &outPacket, frame, &output);
if (output) {
if (av_write_frame(outputFile.formatContext, &outPacket) != 0) {
fprintf(stderr, "convert(): error while writing video frame\n");
[self finishWithSuccess:NO error:nil completionBlock:completionBlock];
}
}
av_free_packet(&outPacket);
}
if (frame->pkt_pts > endtime_int64) {
break;
}
}
}
av_free_packet(&inPacket);
if (![outputFile writeTrailerWithError:&error]) {
[self finishWithSuccess:NO error:error completionBlock:completionBlock];
return;
}
[self finishWithSuccess:YES error:nil completionBlock:completionBlock];
});
}