make a test ffmpeg

This commit is contained in:
William Bell
2025-12-27 21:18:41 +00:00
parent d2c4bd3f08
commit 65a5a1ee15
2 changed files with 221 additions and 8 deletions

28
Makefile Normal file
View File

@@ -0,0 +1,28 @@
CC := gcc
TARGET := player
SRC_DIR := src
BUILD := build
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(patsubst $(SRC_DIR)/%.c,$(BUILD)/%.o,$(SRCS))
CFLAGS := -Wall -Wextra -O3
CFLAGS += $(shell pkg-config --cflags libavformat libavcodec libavutil libswresample alsa)
LDFLAGS := $(shell pkg-config --libs libavformat libavcodec libavutil libswresample alsa)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
$(BUILD)/%.o: $(SRC_DIR)/%.c | $(BUILD)
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD):
mkdir -p $(BUILD)
clean:
rm -rf $(BUILD) $(TARGET)
.PHONY: all clean

View File

@@ -1,11 +1,196 @@
// player.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
#include <alsa/asoundlib.h>
#define OUT_RATE 48000
#define OUT_CHANNELS 2
#define OUT_FORMAT AV_SAMPLE_FMT_S16
#define OUT_LAYOUT AV_CH_LAYOUT_STEREO
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <audio-file>\n", argv[0]);
return 1;
}
const char *filename = argv[1];
/* ---------- Open input ---------- */
AVFormatContext *fmt = NULL;
if (avformat_open_input(&fmt, filename, NULL, NULL) < 0) {
fprintf(stderr, "failed to open input\n");
return 1;
}
if (avformat_find_stream_info(fmt, NULL) < 0) {
fprintf(stderr, "failed to read stream info\n");
return 1;
}
/* ---------- Find audio stream ---------- */
int stream_index = -1;
for (unsigned i = 0; i < fmt->nb_streams; i++) {
if (fmt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_index = i;
break;
}
}
if (stream_index < 0) {
fprintf(stderr, "no audio stream found\n");
return 1;
}
AVStream *stream = fmt->streams[stream_index];
/* ---------- Decoder ---------- */
AVCodec *codec =
avcodec_find_decoder(stream->codecpar->codec_id);
if (!codec) {
fprintf(stderr, "decoder not found\n");
return 1;
}
AVCodecContext *dec = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(dec, stream->codecpar);
if (avcodec_open2(dec, codec, NULL) < 0) {
fprintf(stderr, "failed to open decoder\n");
return 1;
}
/* ---------- Resampler ---------- */
SwrContext *swr = swr_alloc_set_opts(
NULL,
OUT_LAYOUT,
OUT_FORMAT,
OUT_RATE,
dec->channel_layout ? dec->channel_layout
: av_get_default_channel_layout(dec->channels),
dec->sample_fmt,
dec->sample_rate,
0,
NULL
);
if (!swr || swr_init(swr) < 0) {
fprintf(stderr, "failed to init resampler\n");
return 1;
}
/* ---------- ALSA ---------- */
snd_pcm_t *pcm;
if (snd_pcm_open(&pcm, "default",
SND_PCM_STREAM_PLAYBACK, 0) < 0) {
fprintf(stderr, "failed to open ALSA device\n");
return 1;
}
snd_pcm_set_params(
pcm,
SND_PCM_FORMAT_S16_LE,
SND_PCM_ACCESS_RW_INTERLEAVED,
OUT_CHANNELS,
OUT_RATE,
1,
500000 // 0.5s latency
);
/* ---------- Buffers ---------- */
AVPacket *pkt = av_packet_alloc();
AVFrame *frm = av_frame_alloc();
uint8_t *outbuf = NULL;
int out_linesize = 0;
int max_samples = 0;
/* ---------- Decode loop ---------- */
while (av_read_frame(fmt, pkt) >= 0) {
if (pkt->stream_index != stream_index) {
av_packet_unref(pkt);
continue;
}
avcodec_send_packet(dec, pkt);
while (avcodec_receive_frame(dec, frm) == 0) {
int needed = av_rescale_rnd(
swr_get_delay(swr, dec->sample_rate) + frm->nb_samples,
OUT_RATE,
dec->sample_rate,
AV_ROUND_UP
);
if (needed > max_samples) {
av_freep(&outbuf);
av_samples_alloc(
&outbuf,
&out_linesize,
OUT_CHANNELS,
needed,
OUT_FORMAT,
1
);
max_samples = needed;
}
int samples = swr_convert(
swr,
&outbuf,
needed,
(const uint8_t **)frm->data,
frm->nb_samples
);
int written = snd_pcm_writei(pcm, outbuf, samples);
if (written < 0)
snd_pcm_recover(pcm, written, 1);
}
av_packet_unref(pkt);
}
/* ---------- Flush ---------- */
avcodec_send_packet(dec, NULL);
while (avcodec_receive_frame(dec, frm) == 0) {
int samples = swr_convert(
swr,
&outbuf,
max_samples,
(const uint8_t **)frm->data,
frm->nb_samples
);
snd_pcm_writei(pcm, outbuf, samples);
}
snd_pcm_drain(pcm);
/* ---------- Cleanup ---------- */
av_freep(&outbuf);
av_frame_free(&frm);
av_packet_free(&pkt);
swr_free(&swr);
avcodec_free_context(&dec);
avformat_close_input(&fmt);
snd_pcm_close(pcm);
int main() {
FILE *ffmpeg = popen("ffmpeg -i ", "rw");
if (!ffmpeg) return -1;
printf("hello world\n");
pclose(ffmpeg);
return 0;
}
}