- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 FFmpeg 拍摄视频(在本例中为 MP4)并将其复制为另一个 MP4。这样我就可以掌握解码/编码视频的窍门,并在该过程中继续做其他事情。我的代码基本上获取一个视频文件,对视频和音频流进行解码,然后将视频和音频流编码为输出视频文件。
截至目前,我的代码仅适用于输入文件的视频流。输出文件的视频部分与输入文件的视频部分完全相同。但是,音频部分不是。输出的音频部分包含原始音频,但上面有噪音。可以把它想象成有人对着他们的麦克风尖叫,或者当音频声音太大以至于扬声器无法处理时。
我处理视频和音频流的解码/编码过程的方式是相同的,除了 AVCodecContext 设置不同(视频 --> frame_rate、width、height 等;音频 --> sample_rate 、 channel 等)。
这是我目前正在使用的代码:
视频结构:
typedef struct Video {
AVFormatContext* inputContext;
AVFormatContext* outputContext;
AVCodec* videoCodec;
AVCodec* audioCodec;
AVStream* inputStream;
AVStream* outputStream;
AVCodecContext* videoCodecContext_I; // Input
AVCodecContext* audioCodecContext_I; // Input
AVCodecContext* videoCodecContext_O; // Output
AVCodecContext* audioCodecContext_O; // Output
int videoStream; // Video stream index
int audioStream; // Audio stream index
} Video;
处理编码/解码的主要代码(我只包含了音频端,因为视频端是一样的):
int openVideo(Video* video, char* filename, char* outputFile) {
video->inputContext = avformat_alloc_context();
if (!video->inputContext) {
printf("[ERROR] Failed to allocate input format context\n");
return -1;
}
if (avformat_open_input(&(video->inputContext), filename, NULL, NULL) < 0) {
printf("[ERROR] Could not open the input file\n");
return -1;
}
if (avformat_find_stream_info(video->inputContext, NULL) < 0) {
printf("[ERROR] Failed to retrieve input stream info\n");
return -1;
}
avformat_alloc_output_context2(&(video->outputContext), NULL, NULL, outputFile);
if (!video->outputContext) {
printf("[ERROR] Failed to create output context\n");
return -1;
}
printf("[OPEN] Video %s opened\n", filename);
return 0;
}
int prepareStreamInfo(AVCodecContext** codecContext, AVCodec** codec, AVStream* stream) {
*codec = avcodec_find_decoder(stream->codecpar->codec_id);
if (!*codec) {
printf("[ERROR] Failed to find input codec\n");
return -1;
}
*codecContext = avcodec_alloc_context3(*codec);
if (!codecContext) {
printf("[ERROR] Failed to allocate memory for input codec context\n");
return -1;
}
if (avcodec_parameters_to_context(*codecContext, stream->codecpar) < 0) {
printf("[ERROR] Failed to fill input codec context\n");
return -1;
}
if (avcodec_open2(*codecContext, *codec, NULL) < 0) {
printf("[ERROR] Failed to open input codec\n");
return -1;
}
return 0;
}
int findStreams(Video* video, char* filename, char* outputFile) {
if (openVideo(video, filename, outputFile) < 0) {
printf("[ERROR] Video %s failed to open\n", filename);
return -1;
}
for (int i = 0; i < video->inputContext->nb_streams; i++) {
video->inputStream = video->inputContext->streams[i];
if (video->inputContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video->videoStream = i;
if (prepareStreamInfo(&(video->videoCodecContext_I), &(video->videoCodec), video->inputStream) < 0) {
printf("[ERROR] Could not prepare video stream information\n");
return -1;video->outputStream->time_base = video->audioCodecContext_O->time_base;
}
} else if (video->inputContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
video->audioStream = i;
if (prepareStreamInfo(&(video->audioCodecContext_I), &(video->audioCodec), video->inputStream) < 0) {
printf("[ERROR] Could not prepare audio stream information\n");
return -1;
}
}
video->outputStream = avformat_new_stream(video->outputContext, NULL);
if (!video->outputStream) {
printf("[ERROR] Failed allocating output stream\n");
return -1;
}
if (avcodec_parameters_copy(video->outputStream->codecpar, video->inputStream->codecpar) < 0) {
printf("[ERROR] Failed to copy codec parameters\n");
return -1;
}
}
if (video->videoStream == -1) {
printf("[ERROR] Video stream for %s not found\n", filename);
return -1;
}
if (video->audioStream == -1) {
printf("[ERROR] Audio stream for %s not found\n", filename);
return -1;
}
if (!(video->outputContext->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&(video->outputContext->pb), outputFile, AVIO_FLAG_WRITE) < 0) {
printf("Could not open output file %s", outputFile);
return -1;
}
}
return 0;
}
int prepareAudioOutStream(Video* video) {
video->audioCodec = avcodec_find_encoder_by_name("mp2");
if (!video->audioCodec) {
printf("[ERROR] Failed to find audio output codec\n");
return -1;
}
video->audioCodecContext_O = avcodec_alloc_context3(video->audioCodec);
if (!video->audioCodecContext_O) {
printf("[ERROR] Failed to allocate memory for audio output codec context\n");
return -1;
}
// Quite possibly the issue
video->audioCodecContext_O->channels = video->audioCodecContext_I->channels;
video->audioCodecContext_O->channel_layout = av_get_default_channel_layout(video->audioCodecContext_O->channels);
video->audioCodecContext_O->sample_rate = video->audioCodecContext_I->sample_rate;
video->audioCodecContext_O->sample_fmt = video->audioCodec->sample_fmts[0];
video->audioCodecContext_O->bit_rate = video->audioCodecContext_I->bit_rate;
video->audioCodecContext_O->time_base = video->audioCodecContext_I->time_base;
video->audioCodecContext_O->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
if (avcodec_open2(video->audioCodecContext_O, video->audioCodec, NULL) < 0) {
printf("[ERROR] Failed to open audio output codec\n");
return -1;
}
if (avcodec_parameters_from_context(getAudioStream(video)->codecpar, video->audioCodecContext_O) < 0) {
printf("[ERROR] Failed to fill audio stream\n");
return -1;
}
return 0;
}
int decodeAudio(Video* video, AVPacket* packet, AVFrame* frame) {
int response = avcodec_send_packet(video->audioCodecContext_I, packet);
if (response < 0) {
printf("[ERROR] Failed to send audio packet to decoder\n");
return response;
}
while (response >= 0) {
response = avcodec_receive_frame(video->audioCodecContext_I, frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
} else if (response < 0) {
printf("[ERROR] Failed to receive audio frame from decoder\n");
return response;
}
if (response >= 0) {
// Do stuff and encode
if (encodeAudio(video, frame) < 0) {
printf("[ERROR] Failed to encode new audio\n");
return -1;
}
}
av_frame_unref(frame);
}
return 0;
}
int encodeAudio(Video* video, AVFrame* frame) {
AVPacket* packet = av_packet_alloc();
if (!packet) {
printf("[ERROR] Could not allocate memory for audio output packet\n");
return -1;
}
int response = avcodec_send_frame(video->audioCodecContext_O, frame);
if (response < 0) {
printf("[ERROR] Failed to send audio frame for encoding\n");
return response;
}
while (response >= 0) {
response = avcodec_receive_packet(video->audioCodecContext_O, packet);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
} else if (response < 0) {
printf("[ERROR] Failed to receive audio packet from encoder\n");
return response;
}
packet->stream_index = video->audioStream;
video->inputStream = getAudioStream(video);
video->outputStream = video->outputContext->streams[packet->stream_index];
packet->pts = av_rescale_q_rnd(packet->pts, video->inputStream->time_base, video->outputStream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
packet->dts = av_rescale_q_rnd(packet->dts, video->inputStream->time_base, video->outputStream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
packet->duration = av_rescale_q(packet->duration, video->inputStream->time_base, video->outputStream->time_base);
packet->pos = -1;
//av_packet_rescale_ts(packet, video->inputStream->time_base, video->outputStream->time_base);
response = av_interleaved_write_frame(video->outputContext, packet);
if (response < 0) {
printf("[ERROR] Failed to write audio packet\n");
break;
}
}
av_packet_unref(packet);
av_packet_free(&packet);
return 0;
}
int readFrames(Video* video, AVPacket* packet, AVFrame* frame) {
if (!packet) {
printf("[ERROR] Packet not allocated to be read\n");
return -1;
}
if (!frame) {
printf("[ERROR] Frame not allocated to be read\n");
return -1;
}
if (prepareVideoOutStream(video) < 0) {
printf("[ERROR] Failed to prepare output video stream\n");
return -1;
}
if (prepareAudioOutStream(video) < 0) {
printf("[ERROR] Failed to prepare output audio stream\n");
return -1;
}
int frameNum = 0;
while (av_read_frame(video->inputContext, packet) >= 0) {
printf("[READ] Reading frame %i\n", frameNum);
if (packet->stream_index == video->videoStream) {
if (decodeVideo(video, packet, frame) < 0) {
printf("[ERROR] Failed to decode and encode video\n");
return -1;
}
} else if (packet->stream_index == video->audioStream) {
if (decodeAudio(video, packet, frame) < 0) {
printf("[ERROR] Failed to decode and encode audio\n");
return -1;
}
}
av_packet_unref(packet);
frameNum++;
}
// Flush encoder
encodeVideo(video, NULL);
encodeAudio(video, NULL);
av_write_trailer(video->outputContext);
return 0;
}
运行所有函数的主要方法:
int main(int argc, char* argv[]) {
Video* video = (Video*)malloc(sizeof(Video));
initVideo(video);
if (findStreams(video, argv[1], argv[2]) < 0) {
printf("[ERROR] Could not find streams\n");
return -1;
}
AVDictionary* dic = NULL;
if (avformat_write_header(video->outputContext, &dic) < 0) {
printf("[ERROR] Error while writing header to output file\n");
return -1;
}
AVFrame* frame = av_frame_alloc();
AVPacket* packet = av_packet_alloc();
if (readFrames(video, packet, frame) < 0) {
printf("[ERROR] Failed to read and write new video\n");
return -1;
}
freeVideo(video); // Frees all codecs and contexts and the video
return 0;
}
我尝试对我的代码进行布局,以便无需向上滚动即可从上到下阅读它。
我意识到在复制视频时,我可以通过 AVPacket 写入输出文件,但我希望以后能够与 AVFrame 一起工作,所以我这样写。我感觉我的音频行为方式的问题是因为 prepareAudioOutStream() 函数的音频输出 AVCodecContext。
事实证明,阅读 FFmpeg 文档和其他在线资源对解决此问题帮助不大。我一定是遗漏了一些东西(或者有一些不需要的东西),所以任何能给我指明正确方向的东西都会有所帮助。
谢谢。
最佳答案
我是音频工程师,不是编码员,但我希望这对您有所帮助。可能发生的情况是您的位深度被截断了;例如,24 位音频被截断为 16 位,这将听起来失真和嘈杂。 从最重要截断的每一位将削减 6dB 的余量。这将增加本底噪声,并将响亮但清晰的正弦波稳定地变成失真的方波,因为显着的比特减少增加了。
检查重新编码过程中的位深度选项。可能是您的编码器对其位深度有限制。检查源位深度和重新编码的位深度,看看有什么区别。您可以为此使用 VLC 媒体播放器。
还建议您在编码前在信号中留出一些余量(至少 0.1 dB)。预编码的音频可能已经达到极限,因此重新编码可能会增加一些轻微的失真。
更多信息在这里:
关于c - FFmpeg - 音频编码在音频上产生额外的噪音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61846094/
我一直在为实时流和静态文件(HTTP 上的 MP3)构建网络广播播放器。我选了Howler.js作为规范化 quirks 的后端的 HTML5 Audio (思考:自动播放、淡入/淡出、进度事件)。
vue移动端input上传视频、音频,供大家参考,具体内容如下 html部分 ?
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 7年前关闭。 Improve this questi
我想在我的程序中访问音频和视频。 MAC里面可以吗? 我们的程序在 Windows 上运行,我使用 directshow 进行音频/视频编程。但我想在 MAC 中开发相同的东西。 有没有像direct
我的应用程序(使用 Flutter 制作,但这应该无关紧要)具有类似于计时器的功能,可以定期(10 秒到 3 分钟)发出滴答声。我在我的 Info.plist 中激活了背景模式 Audio、AirPl
我是 ionic 2 的初学者 我使用了音频文件。 import { Component } from '@angular/core'; import {NavController, Alert
我有一个包含ListView和图片的数据库,我想在每个语音数据中包含它们。我已经尝试过,但是有很多错误。以下是我的java和xml。 数据库.java package com.example.data
我在zend framework 2上建立了一个音乐社交网络。您可以想象它与SoundCloud相同,用户上传歌曲,其他用户播放它们,这些是网站上的基本操作。 我知道将要托管该页面的服务器将需要大量带
我正在尝试在android应用中播放音频,但是在代码中AssetFileDescriptor asset1及其下一行存在错误。这是代码: MediaPlayer mp; @Override prote
我对 WordPress Audio Shortcode有问题。我这样使用它: 但是在前面,在HTML代码中我得到了: document.createElement('audio');
我正在做一项关于降低噪音的滤波技术的实验。我在数据集中的样本是音频文件(.wav),因此,我有:原始录制的音频文件,我将它们与噪声混合,因此变得混合(噪声信号),我将这些噪声信号通过滤波算法传递,输出
一个人会使用哪种类型的神经网络架构将声音映射到其他声音?神经网络擅长学习从序列到其他序列,因此声音增强/生成似乎是它们的一种非常流行的应用(但不幸的是,事实并非如此-我只能找到一个(相当古老的)洋红色
这个让我抓狂: 在专用于此声音播放/录制应用程序的 Vista+ 计算机上,我需要我的应用程序确保(默认)麦克风电平被推到最大。我该怎么做? 我找到了 Core Audio lib ,找到了如何将 I
{ "manifest_version": 2, "name": "Kitten Radio Extension", "description": "Listen while browsi
class Main { WaveFileReader reader; short[] sample; Complex[] tmpComplexArray; publi
我正在使用电话录音软件(android),该软件可以记录2个人在电话中的通话。每个电话的输出是一个音频文件,其中包含来自 call 者和被 call 者的声音。 但是,大多数情况下,运行此软件的电话发
我正在构建一个需要语音激活命令的Web应用程序。我正在使用getUserMedia作为音频输入。 对于语音激活命令,该过程是用户将需要通过记录其语音来“校准”命令。例如,对于“停止”命令,用户将说出“
我正在开发一个Cordova应用程序,并将PouchDB用作数据库,当连接可用时,它将所有信息复制到CouchDB。 我成功存储了简单的文本和图像。 我一直在尝试存储视频和音频,但是没有运气。 我存储
我正在开发web application,我必须在其中使用.MP3的地方使用播放声音,但是会发生问题。 声音为play good in chrome, Firefox,但为safari its not
如何减少音频文件的位深?是否忽略了MSB或LSB?两者混合吗? (旁问:这叫什么?) 最佳答案 TL / DR:将音频曲线高度变量右移至较低位深度 可以将音频视为幅度(Y轴)随时间(X轴)的模拟曲线。
我是一名优秀的程序员,十分优秀!