use*_*526 5 ffmpeg h.264 libavcodec libav libavformat
我\xe2\x80\x99m 尝试使用 FFMpeg/LibAv 在我的 iOS 应用程序上对视频进行转码。\n我\xe2\x80\x99m 试图完成的是对视频进行转码,以便调整每个帧的大小并可能降低比特率为了在设备中节省宝贵的 MB。
\n\n生成的视频必须可以在所有 iPhone5+ 设备上播放。
\n\n阅读文档后我发现:
\n\n从 FFMpeg 角度来看,我尝试使用 LibAv 实现的目标是:
\n\nffmpeg -i INPUT.MOV -c:v libx264 -preset ultrafast -profile:v baseline -level 3.0 -c:a copy output.MOV\nRun Code Online (Sandbox Code Playgroud)\n\n(生成的文件 - 可以在下面找到 - 如果它是由 FFMpeg 通过命令行生成的\xe2\x80\x99s,则可以在 QuickTime 上播放)
\n\n原始视频是使用 iOS 8.2 使用普通 iPhone 生成的,但问题不是特定于设备或 iOS 特定的,它出现在使用 LibAv 生成的所有视频上。
\n\n虽然这两个生成的文件都可以通过 VideoLan (VLC) 播放,但我通过 LibAv 生成的文件不能通过 QuickTime 播放,尽管我无法\xe2\x80\x99 发现它有任何问题。
\n\n如下所示,我在调用 avformat_new_stream 时使用正确的视频编解码器创建视频流:
\n\nAVStream *out_stream; // output stream\nAVStream *in_stream; // input stream\nAVCodecContext *dec_ctx, *enc_ctx; // codec context for the stream\nAVCodec *encoder; // codec used\nint ret;\nunsigned int i;\n\nofmt_ctx = NULL;\n// Allocate an AVFormatContext for an output format. This will be the file header (similar to avformat_open_input but with an zero\'ed memory)\navformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);\nif (!ofmt_ctx) {\n av_log(NULL, AV_LOG_ERROR, "Could not create output context\\n");\n [self errorWith:kErrorCreatingOutputContext and:@"Could not create output context"];\n return AVERROR_UNKNOWN;\n}\n// we must not use the AVCodecContext from the video stream directly! So we have to use avcodec_copy_context() to copy the context to a new location (after allocating memory for it, of course).\n// iterate over all input streams\nfor (i = 0; i < ifmt_ctx->nb_streams; i++) {\n in_stream = ifmt_ctx->streams[i]; // input stream\n dec_ctx = in_stream->codec; // get the codec context for the decoder\n\n if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {\n // lets use h264\n encoder = avcodec_find_encoder(AV_CODEC_ID_H264);\n if (!encoder) {\n [self errorWith:kErrorCodecNotFound and:@"H264 Codec Not Found"];\n return AVERROR_UNKNOWN;\n }\n out_stream = avformat_new_stream(ofmt_ctx, encoder); // create a new stream with h264 codec\n if (!out_stream) {\n av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\\n");\n [self errorWith:kErrorAllocateOutputStream and:@"Failed allocating output stream"];\n return AVERROR_UNKNOWN;\n }\n enc_ctx = out_stream->codec; // pointer to the stream codec context\n /* we transcode to same properties (picture size,\n * sample rate etc.). These properties can be changed for output\n * streams easily using filters */\n if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {\n enc_ctx->width = dec_ctx->width;\n enc_ctx->height = dec_ctx->height;\n enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;\n enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;\n enc_ctx->time_base = dec_ctx->time_base;\n av_opt_set(enc_ctx->priv_data, "preset", "ultrafast", 0);\n av_opt_set(enc_ctx->priv_data, "profile", "baseline", 0);\n av_opt_set(enc_ctx->priv_data, "level", "3.0", 0);\n }\n\n out_stream->time_base = in_stream->time_base;\n\n AVDictionaryEntry *tag = NULL;\n while ((tag = av_dict_get(in_stream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {\n printf("%s=%s\\n", tag->key, tag->value);\n char *k = av_strdup(tag->key); // if your strings are already allocated,\n char *v = av_strdup(tag->value); // you can avoid copying them like this\n av_dict_set(&out_stream->metadata, k, v, 0);\n }\n\n ret = avcodec_open2(enc_ctx, encoder, NULL);\n if (ret < 0) {\n av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\\n", i);\n [self errorWith:kErrorCantOpenOutputFile and:[NSString stringWithFormat:@"Cannot open video encoder for stream #%u",i]];\n return ret;\n }\n\n }\n else if(dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {\n // if we cant figure out the stream type, fail\n av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\\n", i);\n [self errorWith:kErrorUnknownStream and:[NSString stringWithFormat:@"Elementary stream #%d is of unknown type, cannot proceed",i]];\n return AVERROR_INVALIDDATA;\n }\n else {\n out_stream = avformat_new_stream(ofmt_ctx, NULL);\n if (!out_stream) {\n av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\\n");\n [self errorWith:kErrorAllocateOutputStream and:@"Failed allocating output stream"];\n return AVERROR_UNKNOWN;\n }\n enc_ctx = out_stream->codec;\n /* this stream must be remuxed */\n // copies ifmt_ctx->streams[i]->codec into ofmt_ctx->streams[i]->codec - Copy the settings of the source AVCodecContext into the destination AVCodecContext.\n ret = avcodec_copy_context(ofmt_ctx->streams[i]->codec,\n ifmt_ctx->streams[i]->codec);\n if (ret < 0) {\n av_log(NULL, AV_LOG_ERROR, "Copying stream context failed\\n");\n [self errorWith:kErrorCopyStreamFailed and:@"Copying stream context failed"];\n return ret;\n }\n\n }\n // dunno what this is for\n if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)\n enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;\n\n}\nif (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {\n // Create and initialize a AVIOContext for accessing the\n // resource indicated by url.\n ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);\n if (ret < 0) {\n av_log(NULL, AV_LOG_ERROR, "Could not open output file \'%s\'", filename);\n [self errorWith:kErrorCantOpenOutputFile and:[NSString stringWithFormat:@"Could not open output file \'%s\'", filename]];\n return ret;\n }\n}\n\n/* init muxer, write output file header */\n// Allocate the stream private data and write the stream header to an output media file.\nret = avformat_write_header(ofmt_ctx, NULL);\nif (ret < 0) {\n av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\\n");\n [self errorWith:kErrorOutFileCantWriteHeader and:@"Error occurred when opening output file"];\n return ret;\n}\nreturn 0;\nRun Code Online (Sandbox Code Playgroud)\n\n您可以在此处找到这些文件:
\n\n非常感谢,\nZe
\n| 归档时间: |
|
| 查看次数: |
780 次 |
| 最近记录: |