Skip to content

requires free packet #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
cmake_minimum_required (VERSION 2.8.11)
project (spdif-decoder)

add_executable (spdif-decoder
codechandler.c
helper.c
myspdif.c
myspdifdec.c
resample.c
spdif-loop.c
)

SET(FFMPEG ${CMAKE_CURRENT_SOURCE_DIR}/../ffmpeg-4.3.1)

target_include_directories (spdif-decoder
PUBLIC ${FFMPEG}
)

FIND_LIBRARY(libavcodec avcodec ${FFMPEG}/libavcodec)
FIND_LIBRARY(libavformat avformat ${FFMPEG}/libavformat)
FIND_LIBRARY(libavdevice avdevice ${FFMPEG}/libavdevice)
FIND_LIBRARY(libavutil avutil ${FFMPEG}/libavutil)
FIND_LIBRARY(libswresample swresample ${FFMPEG}/libswresample)
FIND_LIBRARY(libavfilter avfilter ${FFMPEG}/libavfilter)
TARGET_LINK_LIBRARIES(spdif-decoder
${libavcodec}
${libavformat}
${libavdevice}
${libavutil}
${libswresample}
${libavfilter}
ao
m
)
9 changes: 0 additions & 9 deletions Makefile

This file was deleted.

50 changes: 0 additions & 50 deletions NOTES

This file was deleted.

32 changes: 20 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
spdif-loop
==========
spdif-decoder
=============

SPDIF to 5.1 software loop decoder. Use if you want to connect a
digital surround signal (Dolby Digital), such as an Xbox 360 S, via
digital surround signal (Dolby Digital), such as an Xbox 360 S or TV, via
your PC to your 5.1 (analog) stereo. Like a digital receiver/decoder,
just in software.

FFMPEG is licenced under the GNU Lesser General Public License version 2.1 and so is
this piece of software.

Requirements
------------
- libasound2-dev
- libao-dev
- cmake
- ffmpeg from Source https://www.ffmpeg.org/download.html (tested with 4.3.1)

- ffmpeg/libav
- libao


Build
Build ffmpeg shared library with a minimal set for alsa and AC3 support
-----
./configure --enable-shared --disable-static --disable-everything --enable-demuxer=spdif --enable-decoder=ac3 --enable-indev=alsa
make

make
Build spdif-decoder
-----
Prepare CMakeLists.txt - set FFMPEG Var with Path to ffmpeg (if not in ../ffmpeg-4.3.1)

cmake .
make

Run
---

I run it like this:

./spdif-loop -i hw:CARD=Device -d pulse -o alsa_output.usb-0d8c_USB_Sound_Device-00-Device.analog-surround51
./spdif-decoder -i hw:CARD=Device -d pulse -o alsa_output.usb-0d8c_USB_Sound_Device-00-Device.analog-surround51

Alsa's `hw:CARD=Device` is my SPDIF input. You can list your alsa devices with

Expand All @@ -39,7 +47,7 @@ I had to use `amixer` to set the capture source to SPIF. In this case
amixer -c Device set 'PCM Capture Source' 'IEC958 In' # set input


Contact
Thanks to
-------

Sebastian Morgenstern <Sebastian.Morgenstern@gmail.com>
Simon Schubert <2@0x2c.org>
102 changes: 102 additions & 0 deletions codechandler.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* codechandler.c
*
* Created on: 25.04.2015
* Author: sebastian
*/

#include <stdio.h>
#include <errno.h>
#include <err.h>
#include "resample.h"
#include "codechandler.h"

void CodecHandler_init(CodecHandler* h){
h->codec = NULL;
h->codecContext = NULL;
h->currentChannelCount = 0;
h->currentCodecID = AV_CODEC_ID_NONE;
h->currentSampleRate = 0;
h->swr = resample_init();
h->frame = av_frame_alloc();
}
void CodecHandler_deinit(CodecHandler* h){
resample_deinit(h->swr);
av_frame_free(&h->frame);
}

int CodecHandler_loadCodec(CodecHandler * handler, AVFormatContext * formatcontext){
if (formatcontext->nb_streams == 0){
printf("could not find a stream\n");
handler->currentCodecID = AV_CODEC_ID_NONE;
return -1;
}

if(handler->currentCodecID == formatcontext->streams[0]->codec->codec_id){
//Codec already loaded
return 0;
}

if(handler->codecContext != NULL){
CodecHandler_closeCodec(handler);
}
handler->currentCodecID = AV_CODEC_ID_NONE;

handler->codec = avcodec_find_decoder(formatcontext->streams[0]->codec->codec_id);
if (!handler->codec) {
printf("could not find codec\n");
return -1;
}else{
printf("found codec\n");
}
handler->codecContext = avcodec_alloc_context3(handler->codec);
if (!handler->codecContext)
errx(1, "cannot allocate codec");
if (avcodec_open2(handler->codecContext, handler->codec, NULL) != 0)
errx(1, "cannot open codec");
handler->currentCodecID = formatcontext->streams[0]->codec->codec_id;
return 0;
}

int CodecHandler_decodeCodec(CodecHandler * h, AVPacket * pkt,
uint8_t *outbuffer, uint32_t* bufferfilled){
int got_frame;
int processed_len = avcodec_decode_audio4(h->codecContext, h->frame, &got_frame, pkt);
if (processed_len < 0)
errx(1, "cannot decode input");

int ret = 0;

pkt->data += processed_len;
pkt->size -= processed_len;
if(h->currentChannelCount != h->codecContext->channels
|| h->currentSampleRate != h->codecContext->sample_rate
|| h->currentChannelLayout != h->codecContext->channel_layout){
resample_loadFromCodec(h->swr, h->codecContext);
printf("c: %d, s: %d\n",h->codecContext->channels, h->codecContext->sample_rate);
ret = 1;
}

swr_convert(h->swr, &outbuffer, h->frame->nb_samples, (const uint8_t **)h->frame->data, h->frame->nb_samples);
*bufferfilled = av_samples_get_buffer_size(NULL,
h->codecContext->channels,
h->frame->nb_samples,
AV_SAMPLE_FMT_S16,
1);

h->currentChannelCount = h->codecContext->channels;
h->currentSampleRate = h->codecContext->sample_rate;
h->currentChannelLayout = h->codecContext->channel_layout;
return ret;
}


int CodecHandler_closeCodec(CodecHandler * handler){
if(handler->codecContext != NULL){
avcodec_close(handler->codecContext);
avcodec_free_context(&handler->codecContext);
}
handler->codec = NULL;
handler->codecContext = NULL;
return 0;
}
37 changes: 37 additions & 0 deletions codechandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* codechandler.h
*
* Created on: 25.04.2015
* Author: sebastian
*/

#ifndef CODECHANDLER_H_
#define CODECHANDLER_H_
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libavutil/frame.h>

typedef struct s_codechandler{
AVCodecContext *codecContext;
AVCodec * codec;
enum AVCodecID currentCodecID;
int currentChannelCount;
uint64_t currentChannelLayout;
int currentSampleRate;
SwrContext * swr;
AVFrame * frame;
} CodecHandler;

void CodecHandler_init(CodecHandler* handler);
void CodecHandler_deinit(CodecHandler* handler);

int CodecHandler_loadCodec(CodecHandler * handler, AVFormatContext * formatcontext);
int CodecHandler_hasCodecChangend(CodecHandler * handler, AVFormatContext * formatcontext);

int CodecHandler_decodeCodec(CodecHandler * h, AVPacket * pkt,
uint8_t *outbuffer, uint32_t* bufferfilled);
int CodecHandler_closeCodec(CodecHandler * handler);


#endif /* CODECHANDLER_H_ */
80 changes: 80 additions & 0 deletions helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* helper.c
*
* Created on: 21.04.2015
* Author: sebastian
*/

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <math.h>

#include <ao/ao.h>

ao_device * open_output(int driver_id, ao_option *dev_opts, int bits, int channels, int sample_rate)
{
printf("%d bit, %d channels, %dHz\n",
bits,
channels,
sample_rate);

ao_sample_format out_fmt = {
.bits = bits,
.channels = channels,
.rate = sample_rate,
.byte_format = AO_FMT_NATIVE,
//.matrix = "L,R,BL,BR,C,LFE",
.matrix = "L,R,C,LFE,BL,BR",
};

return (ao_open_live(driver_id, &out_fmt, dev_opts));
}

int test_audio_out(int driver_id, ao_option *dev_opts)
{
struct chan_map {
const char *name;
int freq;
int idx;
} map[] = {
/* This needs to match the order in open_output(). */
{ "left", 500, 0 },
{ "center", 500, 2 },
{ "right", 500, 1 },
{ "rear right", 500, 5 },
{ "rear left", 500, 4 },
{ "sub", 50, 3 }
};

ao_device *odev = open_output(driver_id, dev_opts, 16, 6, 48000);
if (!odev)
errx(1, "cannot open audio output");
int ch;
for (ch = 0; ch < 6; ++ch) {
const size_t buflen = 4800; /* 1/10 of a second */
int16_t buf[buflen * 6];

printf("channel %d: %s\n", map[ch].idx, map[ch].name);

/* prepare sine samples */
memset(buf, 0, sizeof(buf));
int i;
for (i = 0; i < buflen; ++i) {
buf[i * 6 + map[ch].idx] = INT16_MAX / 10 * cos(2 * (3.14159265358979323846) * map[ch].freq * i / 48000.0);
}

/* play for 2 sec, 1 sec pause */
for (i = 0; i < 30; ++i) {
if (i == 20) {
/* now pause */
memset(buf, 0, sizeof(buf));
}
if (!ao_play(odev, (char *)buf, sizeof(buf)))
errx(1, "cannot play test audio");
}
}

return (0);
}
16 changes: 16 additions & 0 deletions helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* helper.h
*
* Created on: 21.04.2015
* Author: sebastian
*/

#ifndef HELPER_H_
#define HELPER_H_

#include <stdint.h>
#include <ao/ao.h>

extern ao_device * open_output(int driver_id, ao_option *dev_opts, int bits, int channels, int sample_rate);
extern int test_audio_out(int driver_id, ao_option *dev_opts);
#endif /* HELPER_H_ */
Loading