Part 2 — Reconstructing 4K Video on a Radeon HD 6570 and Athlon 64 X2
A continuation of Part 1 — Making 4K Video More Compatible.
In Part 1, I described the idea of a dedicated video server: take modern 4K H.265 video, convert it to H.264, and make it usable by older devices. The point was not to improve the original video. It was to bridge generations of hardware without having to replace every player and computer along the way.
That leaves another problem.
H.264 is compatible with older hardware, but 4K H.264 is not necessarily easy for that hardware to play.
A graphics card may have an H.264 decoder and still be limited by the picture sizes, profiles, throughput or memory arrangements its video engine was designed to handle. In other words, changing the codec does not automatically remove the resolution problem.
So I decided to investigate a particularly old combination: an AMD Radeon HD 6570 and an Athlon 64 X2 4200+, a dual-core processor running at 2.2 GHz. The computer ran Ubuntu Server without a desktop environment. Its display was connected through VGA at 1024 × 768.
The question was no longer simply whether the server could convert H.265 to H.264. It was:
Could the client reconstruct a complete 3840 × 2160 picture by dividing the work between hardware and software decoders?
The source material was a 3840 × 2160 HEVC Main10 video, converted upstream into H.264 test streams. The older client was not asked to decode H.265 or encode H.264 itself. The final reconstruction trials used a 45-second excerpt (06:45–07:30) at 23.976 fps, containing 1,079 frames. Although the graphics pipeline worked with a complete 4K picture internally, it scaled that image to 1024 × 576 within the 1024 × 768 VGA output. That distinction matters: we investigated full-resolution reconstruction and real-time presentation, not native 4K display output.
Measuring capability rather than reading a specification sheet
We ran three fundamentally different kinds of experiment. Isolated decoding measured how quickly a single H.264 stream could be decoded when no attempt was made to display it. Concurrent decoding ran multiple streams together and reported the rate of each stream, not their combined FPS. Finally, reconstruction tests decoded tiles, matched their presentation timestamps, assembled the image and, later, displayed it.
Those numbers cannot be substituted for one another. A 60 fps decode-to-null test does not guarantee a 60 fps compositor. Similarly, a video that averages 24 fps over 45 seconds may still have individual frames that arrive late. Keeping these distinctions visible became as important as optimizing the code.
Characterizing the Radeon HD 6570
Before attempting 4K reconstruction, I wanted to understand what the HD 6570 could actually decode. The card uses AMD’s Turks GPU and UVD video engine. Under Ubuntu Server, FFmpeg accessed it through the r600 VA-API driver. The tests ran without a desktop environment so that we could measure decoding without confusing it with display performance.
An H.264 hardware decoder has several different limits. It may accept one picture size but reject another. It may decode a single stream rapidly, yet become too slow when several streams compete for the same video engine. And an easy H.264 sequence may be decoded much faster than a demanding one at the same resolution. We investigated those questions separately.
The first multi-stream question: how many 1080p videos?
We began the concurrent-decoding experiments with familiar 1920 × 1080 H.264 video, using 30 fps per stream as the performance target. One stream was easy. Two still worked. At three, the card continued to decode every stream, but its throughput dropped below the target.
| Simultaneous 1920 × 1080 streams | Decoding speed, per stream | Meets 30 fps? |
|---|---|---|
| 1 | 65 fps | Yes |
| 2 | 36–37 fps | Yes |
| 3 | 24 fps | No |
| 4 | 18–19 fps | No |
These first trials used 150 frames per stream. “Three streams failed” did not mean a decoder error: three streams completed successfully, but they were no longer fast enough to sustain the chosen 30 fps target. Multiplying the per-stream numbers by the stream count gives an aggregate of roughly 65–75 decoded 1080p frames per second across these trials. This suggested that the streams were competing for a relatively fixed decoding capacity, rather than receiving independent full-speed video engines.
There is a subtle point about the word failed. We deliberately chose 30 fps as the pass criterion in this concurrency exploration, even though our later movie excerpt was 23.976 fps. Three 1080p streams at approximately 24 fps were not a robust 30 fps solution, and they left essentially no margin for the 23.976 fps source. That is why the next experiment was not to add another decoder, but to reduce the amount of work per stream.
That immediately led to another question: if we made each stream smaller, could the HD 6570 handle three or even four simultaneously at 30 fps?
Smaller pictures, more simultaneous streams
We repeated the concurrent-decoding tests at three smaller resolutions, running 600 frames per stream. The results were revealing:
| Resolution of each stream | 1 stream | 2 streams | 3 streams | 4 streams |
|---|---|---|---|---|
| 1920 × 1080 | 65 | 36–37 | 24 | 18–19 |
| 1280 × 1152 | 102 | 53 | 35 | 26 |
| 1280 × 1024 | 113 | 59 | 39 | 30–31 |
| 1280 × 720 | 156 | 82 | 55 | 41 |
All values are measured frames per second per stream, not the sum across streams. The 1080p row comes from the earlier 150-frame tests; the smaller-resolution rows are 600-frame tests, so the figures describe distinct experiments.

The contrast with the initial 1080p result is significant. Three 1280 × 1152 streams ran at 35 fps each, while four 1280 × 1024 streams just reached 30–31 fps each. With four 1280 × 720 streams, each stream reached 41 fps. We did not test more than four streams in this particular set, so that is a demonstrated result, not a claim about the absolute maximum number of simultaneous streams.

These numbers changed the direction of the investigation. Instead of treating 1080p as an indivisible unit, we could select tile dimensions that gave the GPU enough throughput for several simultaneous streams. A 1280 × 720 stream contains fewer than half as many pixels as 1920 × 1080; the difference was large enough that four 720p streams each exceeded 30 fps.
At the same time, the test showed why a blanket statement such as “the HD 6570 can decode four videos” would be misleading. How many streams? depended on how large and demanding each stream was. The next step was to find dimensions that suited the decoder, then decide how those pieces could be arranged into a larger picture.
Exploring unusual dimensions and single-stream boundaries
We also characterized single-stream speed at a wider set of resolutions. The measurements below come from a separate resolution sweep; differences between its values and the concurrency tests reflect different test runs and workloads.
| H.264 stream resolution | Measured throughput |
|---|---|
| 1280 × 720 | 132 fps |
| 1280 × 800 | 121 fps |
| 1280 × 900 | 109 fps |
| 1280 × 960 | 104 fps |
| 1280 × 1024 | 99 fps |
| 1280 × 1080 | 93 fps |
| 1440 × 900 | 98 fps |
| 1440 × 1080 | 84 fps |
| 1600 × 900 | 89 fps |
| 1600 × 1000 | 82 fps |
| 1600 × 1080 | 77 fps |
| 1920 × 1080 | 66 fps |
| 2048 × 1080 | 68 fps |
| 2048 × 1152 | 59 fps |

Within this particular sweep, 1280 × 720 reached 132 fps, while even 2048 × 1152 maintained 59 fps. The highest single-stream figure across the separately recorded tests was 156 fps at 1280 × 720 in the concurrency batch. The two 720p results are not a contradiction: the test content and procedures were different, so the correct interpretation is that they are measurements from separate runs, not a universal maximum.
A separate FFmpeg/null-output run at 2048 × 1152 completed 1,079 frames in 19.98 seconds, or about 54 fps. We also tested unconventional portrait-oriented dimensions, including 1080 × 1920 and 720 × 1280, which this VA-API decoding path rejected. That does not, on its own, prove every imaginable hardware limit, but it demonstrates that pixel count, accepted dimensions, and decoding throughput are three distinct questions.
Bitrate changed the result as well
So far, the experiments established that lower resolution increased the number of simultaneous streams. But could we predict decoding performance from pixel count alone? To answer that, we compared different H.264 encodings of the same real-world 1920 × 1080, 23.976 fps video (video_decode_test2.mp4). Each version contained approximately 3,207 frames. We tested an approximately 1.76 Mbps original and re-encodes at approximately 19.94 and 29.01 Mbps. The latter was the actual bitrate reached by encodes targeting higher rates; it was not a 40 or 60 Mbps result.
| Actual bitrate | HD 6570, GPU decoding | Athlon 64 X2, CPU decoding |
|---|---|---|
| 1.76 Mbps | 73 fps | 93 fps |
| 19.94 Mbps | 60 fps | 47 fps |
| 29.01 Mbps | 53 fps | 39 fps |
These were unrestricted single-stream FFmpeg decode-to-null measurements. They are not display FPS, and the original and re-encoded files were not necessarily equally demanding H.264 bitstreams apart from bitrate. The encoder’s motion prediction, reference-frame decisions and other coding choices also matter. Nevertheless, for these actual files, the Radeon fell from 73 to 53 fps, while the Athlon fell from 93 to 39 fps. At the lowest rate, the CPU was faster in this particular test; at the highest rate, the GPU was faster. The Athlon was much more sensitive to the demanding encodes.

We also ran two GPU-decoded streams and two CPU-decoded streams concurrently. This was still a decode-capacity test, not yet a four-tile composited video. Each of the four decoders processed its own 1080p stream of the tested bitrate:
| Bitrate per 1080p stream | Each GPU stream | Each CPU stream | 23.976 fps source rate |
|---|---|---|---|
| 1.76 Mbps | ~36 fps | 43–44 fps | All four above target |
| 19.94 Mbps | ~30 fps | ~24 fps | Borderline on CPU |
| 29.01 Mbps | ~27 fps | ~19 fps | CPU streams below target |
These mixed trials were important for the next stage. They showed that the old Athlon was not incapable of participating in a multi-stream reconstruction; it could perform useful decoding work, provided we controlled the number of pixels assigned to it and the difficulty of the H.264 stream. They also warned us not to rely on a low-bitrate success as proof that every 1080p file would behave the same way.

Proving that two GPU streams could become one picture
Decoding several streams was only the first half of the idea. To use those streams as tiles of a larger image, we had to combine them without wasting time copying complete frames between the GPU and system memory.
We split a 2048 × 1152 picture into two 2048 × 576 H.264 streams, each approximately 10 Mbps. The Radeon decoded both at around 57 fps per stream. The new GPU compositor then reconstructed the image using textures and a shader. It processed 1,079 synchronized frame pairs in 21.663 seconds — 49.81 reconstructed frames per second — with zero timestamp mismatches and no full-frame CPU readback.

A separate earlier FFmpeg test also completed a 2048 × 1152 GPU-only decode/reconstruction workload at about 54 fps, but the 49.81 fps figure above is the more informative result for the dedicated two-tile GPU compositor: it includes synchronized tile handling and composition, not just unrestricted decoder output.
This was the proof of concept that connected the earlier benchmarks to the larger project. The HD 6570 did not need to decode one oversized frame. It could decode supported pieces and let a shader reconstruct the picture. We were now ready to go beyond GPU-only stitching and ask how much of the remaining image area the Athlon could handle in software.
Then, test what the Athlon could contribute
Having measured the Athlon’s software decoder as well as the Radeon, we could make a more sensible division of the image. The Athlon 64 X2 4200+ is a dual-core, 2.2 GHz processor from an era long before software 4K H.264 playback was a reasonable expectation. We were not going to give it the entire 4K picture. Instead, the GPU would decode two upper tiles while the CPU decoded a carefully sized lower region. The bitrate experiments had already shown why the CPU’s assigned workload had to remain manageable. What mattered now was whether all three tiles could arrive in time to reconstruct each source frame.
We first worked at 2880 × 1620, a step beyond conventional full HD but not yet the full 4K workload. An early FFmpeg-based hybrid reconstruction finished 1,079 frames in approximately 41.67 seconds (about 25.9 fps). That was just above the 23.976 fps movie rate, but offered little room for the other work a real player must perform.
After moving the tile composition into a dedicated OpenGL ES pipeline and reducing unnecessary transfers, the 2880 × 1620 offscreen compositor reached 40.04 fps. These are results from different implementations, so the comparison is about the development progression rather than an isolated single-variable speedup. Nevertheless, it demonstrated that where we stitched the tiles could matter almost as much as where we decoded them. That gave us confidence to attempt 3840 × 2160.
Finding a practical stitching strategy
The next question was where the decoded pieces should meet. We explored the following approaches in order of increasing specialization:
| Approach | What it does | Why it mattered |
|---|---|---|
| FFmpeg-side reconstruction | Decode and combine the picture using a general-purpose processing pipeline | A useful first proof of concept, but extra frame movement and processing limited the available margin |
| CPU-side assembly | Copy decoded tiles into a complete frame in system memory before handing it to the graphics card | Straightforward, but potentially expensive at millions of pixels per frame on an Athlon X2 |
| GPU shader stitching | Leave GPU-decoded images in GPU-accessible surfaces, upload only the software-decoded tile and compose the image in a shader | Avoided full-4K CPU copies and let the GPU do scaling and assembly |
We ultimately concentrated on the third strategy. The hardware-decoded top tiles remained on the Radeon; the Athlon decoded the bottom tile into system memory; OpenGL ES sampled the three tile textures, selected the appropriate region for each final pixel, and scaled the assembled image for display. The program did not need to materialize a full 3840 × 2160 picture in system RAM.

This distinction explains a result that would otherwise seem surprising. We were not asking the Athlon to decode, stitch and resize the entire 4K image. It only decoded the part assigned to it. The GPU remained responsible for decoding the other tiles, assembling the image and presenting it.
What we optimized
We iterated through several implementation details:
- GPU surface reuse: VA-API hardware decode surfaces were imported into EGL/OpenGL ES textures using DRM PRIME2/DMA-BUF rather than copied back to system RAM. A small cache avoided repeated surface import for recurring VA surfaces; in one 1,079-frame run, the top paths recorded 1,074 cache hits and five misses each.
- Direct planar upload: the software-decoded bottom image used three
GL_R8planes for Y, U and V.GL_UNPACK_ROW_LENGTHallowed us to respect FFmpeg line strides without repacking every frame into an intermediate buffer. - Shader composition: OpenGL ES reconstructed the 3840 × 2160 image logically from three tile textures and performed the display downscale on the GPU, with no full-4K CPU readback.
- Direct display: the headless server used GBM/EGL and DRM/KMS to present to VGA, bypassing a desktop compositor.
- Display/compute overlap: rather than blocking immediately for each DRM page flip, we deferred the wait while preparing the next frame. This recovered useful throughput and reduced idle time.

The 4K tile arrangements
We tried two closely related 4K partitions. The first used two 1920 × 1080 top tiles with a 3840 × 1080 bottom tile. That offscreen configuration reached 25.69 fps, while its paced VGA version reached 23.56 fps. We then shifted the boundary down: two 1920 × 1152 top tiles, with a shorter 3840 × 1008 bottom tile. This transferred more work to the Radeon and reduced the CPU’s assigned pixel count.
The boundary adjustment was small on screen but meaningful for this processor:
| Contribution | 1080-pixel top boundary | 1152-pixel top boundary |
|---|---|---|
| Each GPU tile | 1920 × 1080 | 1920 × 1152 |
| Software-decoded bottom tile | 3840 × 1080 | 3840 × 1008 |
| Pixels assigned to CPU per frame | 4,147,200 | 3,870,720 |
| Share of 4K pixels decoded by CPU | 50.0% | 46.7% |
In other words, increasing the height of each GPU tile by 72 pixels removed 276,480 pixels per frame, or 6.7%, from the CPU tile. It did not remove that work from the pipeline; it reassigned it to the HD 6570.

The 1152-pixel split delivered 26.81 fps offscreen in the initial full-4K test and about 23.75 fps when paced to VGA. The more consequential change was not another split: it was overlapping the DRM page-flip wait with preparation of the next frame. In the 1152-pixel configuration, an unpaced overlapping KMS test reached 28.22 fps over 1,079 frames (38.241 seconds). That is approximately 17.7% more throughput than the 23.976 fps content rate. A paced overlap run measured 23.99 fps, essentially the target average frame rate.
Selected measured results
The record also includes the 25.9 fps early 1620p FFmpeg prototype and 49.81 fps two-tile GPU compositor discussed above; they are not repeated in the 4K table because they processed different frame sizes and included different stages of work.

| Experiment | Offscreen / output | Measured throughput |
|---|---|---|
| Hybrid 2880 × 1620 | Offscreen | 40.04 fps |
| 4K, 1080-pixel top tiles | Offscreen | 25.69 fps |
| 4K, 1080-pixel top tiles | Paced VGA | 23.56 fps |
| 4K, 1152-pixel top tiles | Offscreen | 26.81 fps |
| 4K, 1152-pixel top tiles | Paced VGA, initial | 23.75 fps |
| 4K, 1152-pixel top tiles | Sequential unpaced VGA | 24.50 fps |
| 4K, 1152-pixel top tiles | Overlapping unpaced VGA | 28.22 fps |
| 4K, 1152-pixel top tiles | Overlapping paced VGA | 23.99 fps |
The measurements above were collected during different iterations and should not be read as a perfectly controlled apples-to-apples codec benchmark. Offscreen means frames were reconstructed without waiting for a physical screen; unpaced VGA means the display path was active but the program was not constrained to movie timing; paced VGA means playback was scheduled to the 23.976 fps presentation clock. They do, however, show the progression from a workable concept to full-frame reconstruction with practical 24 fps average throughput.
Why the last optimizations mattered
In the 28.22 fps unpaced overlap run, the accumulated stage timings were approximately 25.13 seconds decoding, 1.80 seconds VA synchronization/import, 5.06 seconds CPU texture upload, and 5.42 seconds GL draw/finish. These are per-stage totals and should not be summed as if they were a single critical path in a fully overlapping system.

The CPU tile remained the expensive part, but the optimization work mattered. Caching VA surfaces avoided unnecessary re-imports. Direct planar texture uploads eliminated row repacking. GPU-side reconstruction avoided a potentially large full-frame system-memory copying path. Finally, deferring the DRM flip wait meant the main loop could use time that had previously been spent waiting for the display.
For scale, a complete 3840 × 2160 image in three-plane 8-bit 4:2:0 format contains approximately 12.4 MB of active pixel samples per frame (before stride or surface overhead). At 24 fps, repeatedly moving even one whole frame through system memory would involve roughly 299 MB/s of pixel data per copy. It is not that the graphics card could never move that much data; it is that avoiding needless transfers is valuable when the rest of the system is already running near its limit.
What we demonstrated — and what we did not
The HD 6570 and Athlon 64 X2 4200+ reconstructed all 3840 × 2160 pixels of the test video inside an OpenGL ES pipeline. On our 1024 × 768 VGA display, the result was downscaled to a letterboxed image. We also achieved average throughput above the 23.976 fps source rate and measured paced presentation close to 24 fps. The earlier stream-capacity and bitrate benchmarks explain why distributing the pixels across the Radeon and Athlon was necessary.
These results do not establish glitch-free playback of every frame. Some displayed intervals were longer than the nominal 41.7 ms movie frame period. Nor do they establish native 4K HDMI output, a general bitrate ceiling, or universal compatibility with arbitrary H.264 files. In one upstream conversion variant we also observed a colour cast; we therefore have not treated end-to-end colour accuracy as validated. The full-4K reconstruction trial used a specific 45-second, 1,079-frame excerpt, so other scenes and encodings may stress the hardware differently. Detailed diagnosis of occasional late frames is outside the scope of this installment.
The useful conclusion is architectural: a graphics card that cannot handle a particular video as one stream may still contribute substantially to its reconstruction when decoding, memory transfer, composition and presentation are treated as separate engineering problems.
Where Part 2 ends
Our final trial for this article was the 1920 × 1152 + 1920 × 1152 + 3840 × 1008 arrangement. The measured result was enough to demonstrate full-resolution internal reconstruction and approximately real-time display on remarkably old hardware. There were still occasional longer display intervals, so this is not a claim of perfectly smooth playback under every condition. The detailed investigation of those intervals belongs to a later stage of the project.
The broader Off-Label Hardware lesson is that a nominal codec or resolution limit is not always the end of the story. Sometimes the more interesting question is which parts of the job the hardware can still do well — and how to arrange the rest around it.
