1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h"
6
7#include "base/logging.h"
8#include "media/ffmpeg/ffmpeg_common.h"
9#include "media/formats/mp4/box_definitions.h"
10
11namespace media {
12
13FFmpegH264ToAnnexBBitstreamConverter::FFmpegH264ToAnnexBBitstreamConverter(
14    AVCodecContext* stream_context)
15    : configuration_processed_(false),
16      stream_context_(stream_context) {
17  CHECK(stream_context_);
18}
19
20FFmpegH264ToAnnexBBitstreamConverter::~FFmpegH264ToAnnexBBitstreamConverter() {}
21
22bool FFmpegH264ToAnnexBBitstreamConverter::ConvertPacket(AVPacket* packet) {
23  scoped_ptr<mp4::AVCDecoderConfigurationRecord> avc_config;
24
25  if (packet == NULL || !packet->data)
26    return false;
27
28  // Calculate the needed output buffer size.
29  if (!configuration_processed_) {
30    if (!stream_context_->extradata || stream_context_->extradata_size <= 0)
31      return false;
32
33    avc_config.reset(new mp4::AVCDecoderConfigurationRecord());
34
35    if (!converter_.ParseConfiguration(
36            stream_context_->extradata,
37            stream_context_->extradata_size,
38            avc_config.get())) {
39      return false;
40    }
41  }
42
43  uint32 output_packet_size = converter_.CalculateNeededOutputBufferSize(
44      packet->data, packet->size, avc_config.get());
45
46  if (output_packet_size == 0)
47    return false;  // Invalid input packet.
48
49  // Allocate new packet for the output.
50  AVPacket dest_packet;
51  if (av_new_packet(&dest_packet, output_packet_size) != 0)
52    return false;  // Memory allocation failure.
53
54  // This is a bit tricky: since the interface does not allow us to replace
55  // the pointer of the old packet with a new one, we will initially copy the
56  // metadata from old packet to new bigger packet.
57  av_packet_copy_props(&dest_packet, packet);
58
59  // Proceed with the conversion of the actual in-band NAL units, leave room
60  // for configuration in the beginning.
61  uint32 io_size = dest_packet.size;
62  if (!converter_.ConvertNalUnitStreamToByteStream(
63          packet->data, packet->size,
64          avc_config.get(),
65          dest_packet.data, &io_size)) {
66    return false;
67  }
68
69  if (avc_config)
70    configuration_processed_ = true;
71
72  // At the end we must destroy the old packet.
73  av_free_packet(packet);
74  *packet = dest_packet;  // Finally, replace the values in the input packet.
75
76  return true;
77}
78
79}  // namespace media
80