我正在尝试阅读并且最重要的是使用ffmpeg将元数据写入文件。但是我得到了sigseg。
int main(int argc, char **argv) {
av_register_all();
AVFormatContext* ctx;
std::string path("/home/stefan/test_track.mp3");
ctx = avformat_alloc_context();
if (avformat_open_input(&ctx, path.c_str(), 0, 0) < 0)
std::cout << "error1" << std::endl;
if (avformat_find_stream_info(ctx, 0) < 0)
std::cout << "error2" << std::endl;
AVDictionaryEntry *tag = nullptr;
tag = av_dict_get(ctx->metadata, "artist", tag, AV_DICT_IGNORE_SUFFIX);
std::cout << tag->key << " : " << tag->value << std::endl;
av_dict_set(&ctx->metadata, "TPFL", "testtest", 0);
std::cout << "test!" << std::endl;
int status = avformat_write_header(ctx, &ctx->metadata);
if(status == 0)
std::cout << "test1" << std::endl;
return 0;
}
我还尝试制作AVDictionary的完整副本,而不是使用我要保存的新增字段来保存它。但仍然是sigseg。
我错过了什么?
答案 0 :(得分:0)
您需要使用另一个AVFormatContext
来编写输出。
在您的示例中,只需添加一些元数据并复制编解码器,因此ffmpeg库的复用步骤为
avformat_alloc_output_context2
avformat_new_stream
av_write_frame
编写编码数据下面是一个可行的示例,只需对您的代码进行少量修改。
#include <iostream>
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#ifdef __cplusplus
}
#endif
int main(int argc, char **argv) {
av_register_all();
avcodec_register_all();
AVFormatContext* ctx;
std::string path("./input.mp3");
ctx = avformat_alloc_context();
if (avformat_open_input(&ctx, path.c_str(), 0, 0) < 0)
std::cout << "error1" << std::endl;
if (avformat_find_stream_info(ctx, 0) < 0)
std::cout << "error2" << std::endl;
AVDictionaryEntry *tag = nullptr;
tag = av_dict_get(ctx->metadata, "artist", tag, AV_DICT_IGNORE_SUFFIX);
std::cout << tag->key << " : " << tag->value << std::endl;
av_dict_set(&ctx->metadata, "TPFL", "testtest", 0);
std::cout << "test!" << std::endl;
int status;
AVFormatContext* ofmt_ctx;
AVOutputFormat* ofmt = av_guess_format("mp3", "./out.mp3", NULL);
status = avformat_alloc_output_context2(&ofmt_ctx, ofmt, "mp3", "./out.mp3");
if (status < 0) {
std::cerr << "could not allocate output format" << std::endl;
return 0;
}
int audio_stream_index = 0;
for (unsigned i = 0; i < ctx->nb_streams; i++) {
if (ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_index = i;
const AVCodec *c = avcodec_find_encoder(ctx->streams[i]->codecpar->codec_id);
if (c) {
AVStream *ostream = avformat_new_stream(ofmt_ctx, c);
avcodec_parameters_copy(ostream->codecpar, ctx->streams[i]->codecpar);
ostream->codecpar->codec_tag = 0;
}
break;
}
}
av_dict_set(&ofmt_ctx->metadata, "TPFL", "testtest", 0);
av_dump_format(ofmt_ctx, 0, "./out.mp3", 1);
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_open(&ofmt_ctx->pb, "./out.mp3", AVIO_FLAG_WRITE);
}
if (avformat_init_output(ofmt_ctx, NULL) == AVSTREAM_INIT_IN_WRITE_HEADER) {
status = avformat_write_header(ofmt_ctx, NULL);
}
AVPacket *pkt = av_packet_alloc();
av_init_packet(pkt);
pkt->data = NULL;
pkt->size = 0;
while (av_read_frame(ctx, pkt) == 0) {
if (pkt->stream_index == audio_stream_index) {
// this is optional, we are copying the stream
av_packet_rescale_ts(pkt, ctx->streams[audio_stream_index]->time_base,
ofmt_ctx->streams[audio_stream_index]->time_base);
av_write_frame(ofmt_ctx, pkt);
}
}
av_packet_free(&pkt);
av_write_trailer(ofmt_ctx);
avformat_close_input(&ctx);
avformat_free_context(ofmt_ctx);
avformat_free_context(ctx);
if(status == 0)
std::cout << "test1" << std::endl;
return 0;
}
完成后,您可以使用ffprobe output.mp3
检查已写入的元数据。
Input #0, mp3, from 'out.mp3':
Metadata:
TPFL : testtest
encoder : Lavf57.75.100
Duration: 00:00:08.75, start: 0.011995, bitrate: 128 kb/s
Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 128 kb/s
Metadata:
encoder : Lavf