diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c
index 04d4845..018b96c 100644
--- a/libavformat/spdifenc.c
+++ b/libavformat/spdifenc.c
@@ -48,11 +48,16 @@
 #include "avio_internal.h"
 #include "spdif.h"
 #include "libavcodec/ac3.h"
+#include "libavcodec/ac3_parser.h"
 #include "libavcodec/dca.h"
 #include "libavcodec/dcadata.h"
 #include "libavcodec/aacadtsdec.h"
 #include "libavutil/opt.h"
 
+#ifndef AC3_HEADER_SIZE
+#define AC3_HEADER_SIZE 7
+#endif
+
 typedef struct IEC61937Context {
     const AVClass *av_class;
     enum IEC61937DataType data_type;///< burst info - reference to type of payload of the data-burst
@@ -103,10 +108,20 @@ static const AVClass class = {
 static int spdif_header_ac3(AVFormatContext *s, AVPacket *pkt)
 {
     IEC61937Context *ctx = s->priv_data;
-    int bitstream_mode = pkt->data[5] & 0x7;
+    AC3HeaderInfo hdr;
+    GetBitContext gbc;
+    int ret;
 
-    ctx->data_type  = IEC61937_AC3 | (bitstream_mode << 8);
-    ctx->pkt_offset = AC3_FRAME_SIZE << 2;
+    init_get_bits(&gbc, pkt->data, AC3_HEADER_SIZE * 8);
+    ret = ff_ac3_parse_header(&gbc, &hdr);
+    if (ret) {
+        av_log(s, AV_LOG_ERROR, "Wrong AC3 file format\n");
+        return AVERROR_INVALIDDATA;
+    }
+    ctx->data_type   = IEC61937_AC3 | (hdr.bitstream_mode <<8);
+    ctx->pkt_offset  = hdr.num_blocks * 256 << 2;
+    ctx->out_bytes   = hdr.frame_size;
+    ctx->length_code = ctx->out_bytes <<3;
     return 0;
 }
 
@@ -355,7 +370,9 @@ static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt)
         return AVERROR_INVALIDDATA;
     }
 
-    ctx->pkt_offset = hdr.samples << 2;
+    ctx->out_bytes   = ret;
+    ctx->pkt_offset  = hdr.samples << 2;
+    ctx->length_code = ctx->out_bytes <<3;
     switch (hdr.num_aac_frames) {
     case 1:
         ctx->data_type = IEC61937_MPEG2_AAC;
@@ -473,8 +490,8 @@ static int spdif_write_header(AVFormatContext *s)
 static int spdif_write_trailer(AVFormatContext *s)
 {
     IEC61937Context *ctx = s->priv_data;
-    av_freep(&ctx->buffer);
-    av_freep(&ctx->hd_buf);
+    av_free(ctx->buffer);
+    av_free(ctx->hd_buf);
     return 0;
 }
 
@@ -494,7 +511,6 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
 
     ctx->out_buf = pkt->data;
     ctx->out_bytes = pkt->size;
-    ctx->length_code = FFALIGN(pkt->size, 2) << 3;
     ctx->use_preamble = 1;
     ctx->extra_bswap = 0;
 
@@ -503,6 +519,8 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
         return ret;
     if (!ctx->pkt_offset)
         return 0;
+    if (pkt->size < ctx->out_bytes)
+        return -1;
 
     padding = (ctx->pkt_offset - ctx->use_preamble * BURST_HEADER_SIZE - ctx->out_bytes) & ~1;
     if (padding < 0) {
@@ -518,13 +536,13 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
     }
 
     if (ctx->extra_bswap ^ (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN)) {
-    avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1);
+        avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1);
     } else {
-    av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE);
-    if (!ctx->buffer)
-        return AVERROR(ENOMEM);
-    ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1);
-    avio_write(s->pb, ctx->buffer, ctx->out_bytes & ~1);
+        ctx->buffer = av_mallocz(ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE);
+        if (!ctx->buffer)
+            return AVERROR(ENOMEM);
+        ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1);
+        avio_write(s->pb, ctx->buffer, ctx->out_bytes & ~1);
     }
 
     /* a final lone byte has to be MSB aligned */
